merge
This commit is contained in:
commit
a9b1c153f3
@ -320,6 +320,7 @@
|
||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; };
|
||||
D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* TemplateModel.swift */; };
|
||||
D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */; };
|
||||
D23118B325124E18001C8440 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23118B225124E18001C8440 /* Notification.swift */; };
|
||||
D2351C7A24A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */; };
|
||||
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7B24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift */; };
|
||||
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */; };
|
||||
@ -379,7 +380,7 @@
|
||||
D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838E23CCDEDE00DFE4FC /* TwoButtonViewModel.swift */; };
|
||||
D28A839123CD4FD400DFE4FC /* CornerLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A839023CD4FD400DFE4FC /* CornerLabelsModel.swift */; };
|
||||
D28A839323CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A839223CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift */; };
|
||||
D28BA730247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA72F247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift */; };
|
||||
D28BA730247EC2EB00B75CB8 /* NavigationButtonModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA72F247EC2EB00B75CB8 /* NavigationButtonModelProtocol.swift */; };
|
||||
D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA740248025A300B75CB8 /* TabBarModel.swift */; };
|
||||
D28BA7432480284E00B75CB8 /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA7422480284E00B75CB8 /* TabBar.swift */; };
|
||||
D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */; };
|
||||
@ -485,11 +486,15 @@
|
||||
D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99E23E07F8A000B42E6 /* PillButton.swift */; };
|
||||
D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */; };
|
||||
D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */; };
|
||||
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
|
||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
|
||||
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
|
||||
D2EC7BD52527B7A600F540AF /* MoleculeSectionHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */; };
|
||||
D2EC7BD92527B7CF00F540AF /* MoleculeSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */; };
|
||||
D2EC7BDD2527B83700F540AF /* SectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */; };
|
||||
D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */; };
|
||||
D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */; };
|
||||
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */; };
|
||||
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */; };
|
||||
DBC4391822442197001AB423 /* CaretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391622442196001AB423 /* CaretView.swift */; };
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
|
||||
@ -815,6 +820,7 @@
|
||||
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D22D8392241C27B100D3DF69 /* TemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModel.swift; sourceTree = "<group>"; };
|
||||
D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.swift"; sourceTree = "<group>"; };
|
||||
D23118B225124E18001C8440 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||
D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableToggleAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
||||
D2351C7B24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableToggleAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||
D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDescription.swift; sourceTree = "<group>"; };
|
||||
@ -872,7 +878,7 @@
|
||||
D28A838E23CCDEDE00DFE4FC /* TwoButtonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonViewModel.swift; sourceTree = "<group>"; };
|
||||
D28A839023CD4FD400DFE4FC /* CornerLabelsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabelsModel.swift; sourceTree = "<group>"; };
|
||||
D28A839223CE828900DFE4FC /* HeadlineBodyCaretLinkImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyCaretLinkImageModel.swift; sourceTree = "<group>"; };
|
||||
D28BA72F247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtomModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D28BA72F247EC2EB00B75CB8 /* NavigationButtonModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtonModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D28BA740248025A300B75CB8 /* TabBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarModel.swift; sourceTree = "<group>"; };
|
||||
D28BA7422480284E00B75CB8 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = "<group>"; };
|
||||
D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarProtocol.swift; sourceTree = "<group>"; };
|
||||
@ -981,11 +987,15 @@
|
||||
D2E2A99E23E07F8A000B42E6 /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = "<group>"; };
|
||||
D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableableModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
|
||||
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
|
||||
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
|
||||
D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeaderModel.swift; sourceTree = "<group>"; };
|
||||
D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeader.swift; sourceTree = "<group>"; };
|
||||
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = "<group>"; };
|
||||
D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainer.swift; sourceTree = "<group>"; };
|
||||
D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackItem.swift; sourceTree = "<group>"; };
|
||||
D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityProtocol.swift; sourceTree = "<group>"; };
|
||||
DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeftRightLabelView.swift; sourceTree = "<group>"; };
|
||||
DB891E822253FA8500022516 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
|
||||
DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = "<group>"; };
|
||||
@ -1073,6 +1083,7 @@
|
||||
children = (
|
||||
D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */,
|
||||
0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */,
|
||||
D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
@ -1528,7 +1539,7 @@
|
||||
D23EA7FC247EBB7500D60C34 /* Buttons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D28BA72F247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift */,
|
||||
D28BA72F247EC2EB00B75CB8 /* NavigationButtonModelProtocol.swift */,
|
||||
D2509ED52472EE2F001BFB9D /* NavigationImageButtonModel.swift */,
|
||||
D23EA801247EBED400D60C34 /* ImageBarButtonItem.swift */,
|
||||
D23EA7FD247EBBB700D60C34 /* NavigationLabelButtonModel.swift */,
|
||||
@ -2089,9 +2100,13 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */,
|
||||
D2FA83D12513EA6900564112 /* NotificationXButton.swift */,
|
||||
D2CAC7CC251104FE00C75681 /* NotificationModel.swift */,
|
||||
D23118B225124E18001C8440 /* Notification.swift */,
|
||||
D2CAC7D02511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift */,
|
||||
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */,
|
||||
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */,
|
||||
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */,
|
||||
D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */,
|
||||
);
|
||||
path = TopNotification;
|
||||
@ -2419,6 +2434,7 @@
|
||||
AA633B3124989EC000731E80 /* HeadersH2PricingTwoRowsModel.swift in Sources */,
|
||||
8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */,
|
||||
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */,
|
||||
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */,
|
||||
D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */,
|
||||
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
|
||||
D20923592450ECE00044AD09 /* TableView.swift in Sources */,
|
||||
@ -2493,6 +2509,7 @@
|
||||
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
|
||||
32F8804624765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift in Sources */,
|
||||
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
||||
D23118B325124E18001C8440 /* Notification.swift in Sources */,
|
||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
||||
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
||||
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
|
||||
@ -2538,7 +2555,7 @@
|
||||
323AC96A24C837F000F8E4C4 /* ListThreeColumnBillChangesModel.swift in Sources */,
|
||||
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
|
||||
525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */,
|
||||
D28BA730247EC2EB00B75CB8 /* NavigationButtomModelProtocol.swift in Sources */,
|
||||
D28BA730247EC2EB00B75CB8 /* NavigationButtonModelProtocol.swift in Sources */,
|
||||
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */,
|
||||
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */,
|
||||
AA2AD118244EE48C00BBFFE3 /* ListDeviceComplexLinkMediumModel.swift in Sources */,
|
||||
@ -2548,6 +2565,7 @@
|
||||
D2A92882241AAB67004E01C6 /* ScrollingViewController.swift in Sources */,
|
||||
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */,
|
||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */,
|
||||
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */,
|
||||
D2D90B442404789000DD6EC9 /* MoleculeContainerProtocol.swift in Sources */,
|
||||
0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */,
|
||||
94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */,
|
||||
@ -2594,6 +2612,7 @@
|
||||
AAB8549824DC01BD00477C40 /* ListThreeColumnBillHistoryDividerModel.swift in Sources */,
|
||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
||||
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
|
||||
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */,
|
||||
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */,
|
||||
AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */,
|
||||
D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */,
|
||||
@ -2640,6 +2659,7 @@
|
||||
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
|
||||
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */,
|
||||
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */,
|
||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */,
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */,
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */,
|
||||
D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift in Sources */,
|
||||
|
||||
@ -92,10 +92,9 @@ import UIKit
|
||||
}
|
||||
|
||||
func performDropdownAction() {
|
||||
if let actionModel = baseDropdownEntryFieldModel?.action, let actionMap = actionModel.toJSON() {
|
||||
var additionalData = self.additionalData ?? [:]
|
||||
additionalData[KeySourceModel] = baseDropdownEntryFieldModel
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
if let baseDropdownEntryFieldModel = baseDropdownEntryFieldModel, let actionModel = baseDropdownEntryFieldModel.action, let actionMap = actionModel.toJSON() {
|
||||
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: baseDropdownEntryFieldModel)
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,13 +137,11 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
}
|
||||
|
||||
@objc open func selectBox() {
|
||||
guard isEnabled else { return }
|
||||
guard isEnabled, !isSelected else { return }
|
||||
isSelected = true
|
||||
radioBoxModel?.selected = isSelected
|
||||
if let actionModel = radioBoxModel?.action {
|
||||
var additionalData = self.additionalData ?? [:]
|
||||
additionalData[KeySourceModel] = radioBoxModel
|
||||
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
if let radioBoxModel = radioBoxModel, let actionModel = radioBoxModel.action {
|
||||
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioBoxModel)
|
||||
}
|
||||
layer.setNeedsDisplay()
|
||||
}
|
||||
|
||||
@ -95,15 +95,14 @@ import UIKit
|
||||
if !isEnabled {
|
||||
return
|
||||
}
|
||||
let wasPreviouslySelected = isSelected
|
||||
if let radioButtonModel = radioButtonSelectionHelper {
|
||||
radioButtonModel.selected(self)
|
||||
} else {
|
||||
isSelected = !isSelected
|
||||
}
|
||||
if let actionModel = radioModel?.action, isSelected {
|
||||
var additionalData = self.additionalData ?? [:]
|
||||
additionalData[KeySourceModel] = radioModel
|
||||
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
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()
|
||||
|
||||
@ -119,13 +119,11 @@ open class RadioSwatch: Control, MFButtonProtocol {
|
||||
}
|
||||
|
||||
@objc open func selectSwatch() {
|
||||
guard isEnabled else { return }
|
||||
guard isEnabled, !isSelected else { return }
|
||||
isSelected = true
|
||||
radioSwatchModel?.selected = isSelected
|
||||
if let actionModel = radioSwatchModel?.action {
|
||||
var additionalData = self.additionalData ?? [:]
|
||||
additionalData[KeySourceModel] = radioSwatchModel
|
||||
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
if let radioSwatchModel = radioSwatchModel, let actionModel = radioSwatchModel.action {
|
||||
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioSwatchModel)
|
||||
}
|
||||
layer.setNeedsDisplay()
|
||||
}
|
||||
|
||||
@ -394,20 +394,19 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
|
||||
let actionMap = model.action?.toJSON()
|
||||
let alternateActionMap = model.alternateAction?.toJSON()
|
||||
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: model)
|
||||
if actionMap != nil || alternateActionMap != nil {
|
||||
var additionalDatatoUpdate = additionalData ?? [:]
|
||||
additionalDatatoUpdate[KeySourceModel] = model
|
||||
didToggleAction = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if self.isOn {
|
||||
if actionMap != nil {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDatatoUpdate, delegateObject: delegateObject)
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
}
|
||||
} else {
|
||||
if alternateActionMap != nil {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: alternateActionMap, additionalData: additionalDatatoUpdate, delegateObject: delegateObject)
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: alternateActionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
} else if actionMap != nil {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDatatoUpdate, delegateObject: delegateObject)
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,8 +236,8 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: LockupsPlanSMLXL.self, viewModelClass: LockupsPlanSMLXLModel.self)
|
||||
|
||||
// MARK: - Top Notifications
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MVMCoreUITopAlertMainView.self, viewModelClass: NotificationModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MVMCoreUITopAlertExpandableView.self, viewModelClass: CollapsableNotificationModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: NotificationView.self, viewModelClass: NotificationModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: CollapsableNotification.self, viewModelClass: CollapsableNotificationModel.self)
|
||||
|
||||
// MARK:- Helper models
|
||||
try? ModelRegistry.register(RuleRequiredModel.self)
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell {
|
||||
//--------------------------------------------------
|
||||
@ -36,6 +34,7 @@ import UIKit
|
||||
customAccessoryView = true
|
||||
super.setupView()
|
||||
accessoryView = accordionButton
|
||||
accessoryView?.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
override public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
|
||||
@ -18,8 +18,12 @@ public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProt
|
||||
public var backgroundColor: Color?
|
||||
public var tintColor: Color
|
||||
public var line: LineModel?
|
||||
public var hidesSystemBackButton = true
|
||||
|
||||
/// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack
|
||||
public var alwaysShowBackButton: Bool?
|
||||
public var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)? = NavigationImageButtonModel(with: "nav_back", action: ActionBackModel())
|
||||
public var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)?
|
||||
|
||||
public var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
public var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
public var titleView: MoleculeModelProtocol?
|
||||
@ -55,9 +59,7 @@ public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProt
|
||||
tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .black)
|
||||
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) ?? LineModel(type: .standard)
|
||||
alwaysShowBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowBackButton)
|
||||
if let backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol) = try typeContainer.decodeModelIfPresent(codingKey: .backButton) {
|
||||
self.backButton = backButton
|
||||
}
|
||||
backButton = try typeContainer.decodeModelIfPresent(codingKey: .backButton)
|
||||
additionalLeftButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalLeftButtons)
|
||||
additionalRightButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalRightButtons)
|
||||
titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView)
|
||||
|
||||
@ -0,0 +1,187 @@
|
||||
//
|
||||
// CollapsableNotification.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/18/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class CollapsableNotification: View {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public let topView = CollapsableNotificationTopView()
|
||||
public let bottomView = NotificationView()
|
||||
public var verticalStack: UIStackView!
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Life Cycle
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
verticalStack = UIStackView(arrangedSubviews: [topView, bottomView])
|
||||
verticalStack.translatesAutoresizingMaskIntoConstraints = false
|
||||
verticalStack.axis = .vertical
|
||||
verticalStack.alignment = .fill
|
||||
verticalStack.distribution = .fill
|
||||
addSubview(verticalStack)
|
||||
NSLayoutConstraint.constraintPinSubview(verticalStack, pinTop: true, topConstant: 0, pinBottom: true, bottomConstant: 0, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0)
|
||||
|
||||
reset()
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
verticalStack.updateView(size)
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
verticalStack.reset()
|
||||
backgroundColor = .mvmGreen()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Molecule
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? CollapsableNotificationModel else { return }
|
||||
topView.set(with: model, delegateObject, additionalData)
|
||||
bottomView.set(with: model, delegateObject, additionalData)
|
||||
|
||||
// Update top view default noop to expand.
|
||||
if let topAction = model.topAction,
|
||||
topAction.actionType == ActionNoopModel.identifier {
|
||||
topView.button.addActionBlock(event: .touchUpInside) { [weak self] (button) in
|
||||
Button.performButtonAction(with: topAction, button: button, delegateObject: delegateObject, additionalData: additionalData)
|
||||
self?.expand(topViewShowing: model.alwaysShowTopLabel)
|
||||
}
|
||||
}
|
||||
|
||||
// Set initial collapse/expand state.
|
||||
topView.isHidden = !model.alwaysShowTopLabel && !model.initiallyCollapsed
|
||||
topView.button.isUserInteractionEnabled = model.initiallyCollapsed
|
||||
bottomView.isHidden = model.initiallyCollapsed
|
||||
verticalStack.layoutIfNeeded()
|
||||
|
||||
if !model.initiallyCollapsed {
|
||||
autoCollapse()
|
||||
}
|
||||
}
|
||||
|
||||
open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) {
|
||||
let operation = MVMCoreBlockOperation(block: block)!
|
||||
MVMCoreNavigationHandler.shared()?.addNavigationOperation(operation)
|
||||
}
|
||||
|
||||
/// Collapses after a delay
|
||||
open func autoCollapse() {
|
||||
let delay: DispatchTimeInterval = DispatchTimeInterval.seconds((model as? CollapsableNotificationModel)?.collapseTime ?? 5)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||
// If accessibility focused, delay collapse.
|
||||
guard let self = self else { return }
|
||||
if MVMCoreUIUtility.viewContainsAccessiblityFocus(self) {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.accessibilityFocusChanged(notification:)), name: UIAccessibility.elementFocusedNotification, object: nil)
|
||||
} else {
|
||||
self.collapse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collapses to show just the top view.
|
||||
open func collapse(animated: Bool = true) {
|
||||
guard !bottomView.isHidden else { return }
|
||||
performBlockOperation { [weak self] (operation) in
|
||||
let strongSelf = self
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
|
||||
let animation = {
|
||||
strongSelf?.topView.isHidden = false
|
||||
strongSelf?.bottomView.isHidden = true
|
||||
strongSelf?.verticalStack.layoutIfNeeded()
|
||||
}
|
||||
let completion: (Bool) -> Void = { (finished) in
|
||||
strongSelf?.topView.button.isUserInteractionEnabled = true
|
||||
MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
|
||||
UIAccessibility.post(notification: .layoutChanged, argument: strongSelf?.getAccessibilityLayoutChangedArgument())
|
||||
operation.markAsFinished()
|
||||
}
|
||||
|
||||
if animated {
|
||||
UIView.animate(withDuration: 0.5, animations: animation, completion: completion)
|
||||
} else {
|
||||
animation()
|
||||
completion(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Expands to show the bottom view.
|
||||
open func expand(topViewShowing: Bool = false, animated: Bool = true) {
|
||||
guard bottomView.isHidden else { return }
|
||||
performBlockOperation { [weak self] (operation) in
|
||||
let strongSelf = self
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
|
||||
strongSelf?.topView.button.isUserInteractionEnabled = false
|
||||
let animation = {
|
||||
strongSelf?.topView.isHidden = !topViewShowing
|
||||
strongSelf?.bottomView.isHidden = false
|
||||
strongSelf?.verticalStack.layoutIfNeeded()
|
||||
}
|
||||
let completion: (Bool) -> Void = { (finished) in
|
||||
MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
|
||||
UIAccessibility.post(notification: .layoutChanged, argument: strongSelf?.getAccessibilityLayoutChangedArgument())
|
||||
strongSelf?.autoCollapse()
|
||||
operation.markAsFinished()
|
||||
}
|
||||
|
||||
if animated {
|
||||
UIView.animate(withDuration: 0.5, animations: animation, completion: completion)
|
||||
} else {
|
||||
animation()
|
||||
completion(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 120
|
||||
}
|
||||
|
||||
/// Collapse if focus is no longer on this top alert.
|
||||
@objc func accessibilityFocusChanged(notification: Notification) {
|
||||
if !MVMCoreUIUtility.viewContainsAccessiblityFocus(self) {
|
||||
NotificationCenter.default.removeObserver(self, name: UIAccessibility.elementFocusedNotification, object: nil)
|
||||
collapse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CollapsableNotification: StatusBarUI {
|
||||
func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) {
|
||||
let color = backgroundColor ?? UIColor.mvmGreen
|
||||
var greyScale: CGFloat = 0
|
||||
topView.label.textColor.getWhite(&greyScale, alpha: nil)
|
||||
return (color, greyScale > 0.5 ? .lightContent : .default)
|
||||
}
|
||||
}
|
||||
|
||||
extension CollapsableNotification: AccessibilityProtocol {
|
||||
public func getAccessibilityLayoutChangedArgument() -> Any? {
|
||||
if !topView.isHidden {
|
||||
return topView
|
||||
} else {
|
||||
return bottomView.headline
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,16 +8,12 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public class CollapsableNotificationModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "collapsableNotification"
|
||||
public var moleculeName: String = CollapsableNotificationModel.identifier
|
||||
public var backgroundColor: Color?
|
||||
public class CollapsableNotificationModel: NotificationModel {
|
||||
public class override var identifier: String {
|
||||
return "collapsableNotification"
|
||||
}
|
||||
public var topLabel: LabelModel
|
||||
public var topAction: ActionModelProtocol?
|
||||
public var headline: LabelModel
|
||||
public var body: LabelModel?
|
||||
public var button: ButtonModel?
|
||||
public var closeButton: NotificationXButtonModel?
|
||||
public var alwaysShowTopLabel = false
|
||||
public var collapseTime: Int = 5
|
||||
public var initiallyCollapsed = false
|
||||
@ -25,18 +21,23 @@ public class CollapsableNotificationModel: MoleculeModelProtocol {
|
||||
|
||||
init(with topLabel: LabelModel, headline: LabelModel) {
|
||||
self.topLabel = topLabel
|
||||
self.headline = headline
|
||||
super.init(with: headline)
|
||||
}
|
||||
|
||||
override func setDefault() {
|
||||
super.setDefault()
|
||||
if topLabel.textColor == nil {
|
||||
topLabel.textColor = Color(uiColor: .white)
|
||||
}
|
||||
if topLabel.textAlignment == nil {
|
||||
topLabel.textAlignment = .center
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case topLabel
|
||||
case topAction
|
||||
case headline
|
||||
case body
|
||||
case button
|
||||
case closeButton
|
||||
case alwaysShowTopLabel
|
||||
case collapseTime
|
||||
case initiallyCollapsed
|
||||
@ -46,12 +47,7 @@ public class CollapsableNotificationModel: MoleculeModelProtocol {
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
topLabel = try typeContainer.decode(LabelModel.self, forKey: .topLabel)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
topAction = try typeContainer.decodeModelIfPresent(codingKey: .topAction)
|
||||
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
|
||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
||||
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton)
|
||||
if let alwaysShowTopLabel = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowTopLabel) {
|
||||
self.alwaysShowTopLabel = alwaysShowTopLabel
|
||||
}
|
||||
@ -62,18 +58,15 @@ public class CollapsableNotificationModel: MoleculeModelProtocol {
|
||||
self.initiallyCollapsed = initiallyCollapsed
|
||||
}
|
||||
pages = try typeContainer.decodeIfPresent([String].self, forKey: .pages)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(topLabel, forKey: .topLabel)
|
||||
try container.encodeModelIfPresent(topAction, forKey: .topAction)
|
||||
try container.encode(headline, forKey: .headline)
|
||||
try container.encodeIfPresent(body, forKey: .body)
|
||||
try container.encodeIfPresent(button, forKey: .button)
|
||||
try container.encodeIfPresent(closeButton, forKey: .closeButton)
|
||||
try container.encode(alwaysShowTopLabel, forKey: .alwaysShowTopLabel)
|
||||
try container.encode(collapseTime, forKey: .collapseTime)
|
||||
try container.encode(initiallyCollapsed, forKey: .initiallyCollapsed)
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
//
|
||||
// CollapsableNotificationTopView.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/18/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class CollapsableNotificationTopView: View {
|
||||
public let label: Label = {
|
||||
let label = Label(fontStyle: .BoldBodySmall)
|
||||
label.numberOfLines = 1
|
||||
label.textAlignment = .center
|
||||
label.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||
return label
|
||||
}()
|
||||
|
||||
public let button: Button = {
|
||||
let button = Button(type: .custom)
|
||||
button.backgroundColor = .clear
|
||||
button.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
||||
button.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
return button
|
||||
}()
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
addSubview(label)
|
||||
NSLayoutConstraint.constraintPinSubview(label, pinTop: true, topConstant: 0, pinBottom: true, bottomConstant: 0, pinLeft: true, leftConstant: PaddingThree, pinRight: true, rightConstant: PaddingThree)
|
||||
|
||||
addSubview(button)
|
||||
NSLayoutConstraint.constraintPinSubview(button, pinTop: true, topConstant: 0, pinBottom: true, bottomConstant: -5, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0)
|
||||
|
||||
// Listen for status bar touches.
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(pressed(_:)), name: NSNotification.Name(rawValue: NotificationStatusBarTouched), object: nil)
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
label.updateView(size)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
guard let model = model as? CollapsableNotificationModel else { return }
|
||||
label.set(with: model.topLabel, delegateObject, additionalData)
|
||||
button.set(with: model.topAction, delegateObject: delegateObject, additionalData: additionalData)
|
||||
updateAccessibility()
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
label.setFontStyle(.BoldBodySmall)
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
}
|
||||
|
||||
open func updateAccessibility() {
|
||||
isAccessibilityElement = true
|
||||
accessibilityLabel = label.text
|
||||
accessibilityTraits = (button.isUserInteractionEnabled && button.actionModel != nil) ? .button : .none
|
||||
MVMCoreUITopAlertBaseView.amendAccesibilityLabel(for: self)
|
||||
}
|
||||
|
||||
@objc func pressed(_ sender: Notification) {
|
||||
button.callActionBlock(button)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
//
|
||||
// Notification.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/16/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class NotificationView: View {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public let headline = Label(fontStyle: .BoldBodySmall)
|
||||
public let body = Label(fontStyle: .RegularBodySmall)
|
||||
public let button = PillButton(asPrimaryButton: false, makeTiny: true)
|
||||
public let closeButton = NotificationXButton()
|
||||
public var labelStack: Stack<StackModel>!
|
||||
public var horizontalStack: Stack<StackModel>!
|
||||
|
||||
// Legacy constant
|
||||
private static let viewHeight: CGFloat = 96.0
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Life Cycle
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
reset()
|
||||
|
||||
// Buttons should have highest priority, then headline, then body
|
||||
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal)
|
||||
headline.setContentHuggingPriority(.required, for: .vertical)
|
||||
body.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal)
|
||||
body.setContentHuggingPriority(.required, for: .vertical)
|
||||
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: body.contentCompressionResistancePriority(for: .vertical).rawValue + 40), for: .vertical)
|
||||
headline.lineBreakMode = .byTruncatingTail
|
||||
body.lineBreakMode = .byTruncatingTail
|
||||
button.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
||||
|
||||
labelStack = Stack<StackModel>.createStack(with: [headline, body], spacing: 0)
|
||||
horizontalStack = Stack<StackModel>.createStack(with: [(view: labelStack, model: StackItemModel()),(view: button, model: StackItemModel(horizontalAlignment: .fill)),(view: closeButton, model: StackItemModel(horizontalAlignment: .fill))], axis: .horizontal)
|
||||
addSubview(horizontalStack)
|
||||
NSLayoutConstraint.constraintPinSubview(horizontalStack, pinTop: true, topConstant: PaddingTwo, pinBottom: true, bottomConstant: PaddingTwo, pinLeft: true, leftConstant: PaddingThree, pinRight: true, rightConstant: PaddingThree)
|
||||
labelStack.restack()
|
||||
horizontalStack.restack()
|
||||
|
||||
heightAnchor.constraint(equalToConstant: Self.viewHeight).isActive = true
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
horizontalStack.updateView(size)
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
backgroundColor = .mvmGreen()
|
||||
headline.textColor = .white
|
||||
body.textColor = .white
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Molecule
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? NotificationModel else { return }
|
||||
labelStack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, nil)
|
||||
horizontalStack.updateContainedMolecules(with: [labelStack.stackModel, model.button, model.closeButton], delegateObject, nil)
|
||||
updateAccessibility()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return viewHeight
|
||||
}
|
||||
|
||||
open func updateAccessibility() {
|
||||
MVMCoreUITopAlertBaseView.amendAccesibilityLabel(for: headline)
|
||||
MVMCoreUITopAlertBaseView.amendAccesibilityLabel(for: body)
|
||||
MVMCoreUITopAlertBaseView.amendAccesibilityLabel(for: button)
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationView: AccessibilityProtocol {
|
||||
public func getAccessibilityLayoutChangedArgument() -> Any? {
|
||||
return headline
|
||||
}
|
||||
}
|
||||
@ -9,8 +9,9 @@
|
||||
import Foundation
|
||||
|
||||
public class NotificationModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "notification"
|
||||
public var moleculeName: String = NotificationModel.identifier
|
||||
public class var identifier: String {
|
||||
return "notification"
|
||||
}
|
||||
public var backgroundColor: Color?
|
||||
public var headline: LabelModel
|
||||
public var body: LabelModel?
|
||||
@ -20,4 +21,51 @@ public class NotificationModel: MoleculeModelProtocol {
|
||||
init(with headline: LabelModel) {
|
||||
self.headline = headline
|
||||
}
|
||||
|
||||
func setDefault() {
|
||||
if backgroundColor == nil {
|
||||
backgroundColor = Color(uiColor: .mvmGreen())
|
||||
}
|
||||
if headline.textColor == nil {
|
||||
headline.textColor = Color(uiColor: .white)
|
||||
}
|
||||
if body?.textColor == nil {
|
||||
body?.textColor = Color(uiColor: .white)
|
||||
}
|
||||
if button?.style == nil {
|
||||
button?.style = .secondary
|
||||
}
|
||||
button?.size = .tiny
|
||||
button?.enabledTextColor = Color(uiColor: .white)
|
||||
button?.enabledBorderColor = Color(uiColor: .white)
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case headline
|
||||
case body
|
||||
case button
|
||||
case closeButton
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
|
||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
||||
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton)
|
||||
setDefault()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(headline, forKey: .headline)
|
||||
try container.encodeIfPresent(body, forKey: .body)
|
||||
try container.encodeIfPresent(button, forKey: .button)
|
||||
try container.encodeIfPresent(closeButton, forKey: .closeButton)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
//
|
||||
// NotificationXButton.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/17/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class NotificationXButton: Button {
|
||||
|
||||
open func closeTopAlert() {
|
||||
if let delegate = MVMCoreUITopAlertView.sharedGlobal()?.animationDelegate {
|
||||
delegate.topAlertCloseButtonPressed()
|
||||
} else {
|
||||
MVMCoreUISession.sharedGlobal()?.topAlertView?.hideAlertView(true, completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
if let image = MVMCoreUIUtility.imageNamed("nav_close")?.withRenderingMode(.alwaysTemplate) {
|
||||
setImage(image, for: .normal)
|
||||
}
|
||||
tintColor = .white
|
||||
adjustsImageWhenHighlighted = false
|
||||
accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "AccCloseButton")
|
||||
setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? NotificationXButtonModel else { return }
|
||||
tintColor = model.color.uiColor
|
||||
|
||||
// TODO: Temporary, consider action for dismissing top alert
|
||||
if model.action.actionType == ActionNoopModel.identifier {
|
||||
addActionBlock(event: .touchUpInside) { (button) in
|
||||
(button as? NotificationXButton)?.closeTopAlert()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,27 +8,32 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public class NotificationXButtonModel: Codable {
|
||||
public var color: Color?
|
||||
public var action: ActionModelProtocol?
|
||||
public class NotificationXButtonModel: ButtonModelProtocol, MoleculeModelProtocol {
|
||||
public static var identifier: String = "notificationXButton"
|
||||
public var backgroundColor: Color?
|
||||
public var color = Color(uiColor: .white)
|
||||
public var action: ActionModelProtocol = ActionNoopModel()
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case color
|
||||
case action
|
||||
}
|
||||
|
||||
public init() {
|
||||
}
|
||||
public init() {}
|
||||
|
||||
public required init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
color = try typeContainer.decodeIfPresent(Color.self, forKey: .color)
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) ?? Color(uiColor: .white)
|
||||
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
|
||||
self.action = action
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(color, forKey: .color)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(color, forKey: .color)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ public protocol NavigationItemModelProtocol {
|
||||
var backgroundColor: Color? { get set }
|
||||
var tintColor: Color { get set }
|
||||
var line: LineModel? { get set }
|
||||
var hidesSystemBackButton: Bool { get set }
|
||||
var alwaysShowBackButton: Bool? { get set }
|
||||
var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)? { get set }
|
||||
var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? { get set }
|
||||
|
||||
@ -72,21 +72,26 @@ public typealias ButtonAction = (Button) -> ()
|
||||
buttonAction?(self)
|
||||
}
|
||||
|
||||
open func set(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
open func set(with actionModel: ActionModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
self.actionModel = actionModel
|
||||
buttonDelegate = delegateObject?.buttonDelegate
|
||||
|
||||
addActionBlock(event: .touchUpInside) { [weak self] sender in
|
||||
guard let self = self else { return }
|
||||
guard let self = self, let actionModel = actionModel else { return }
|
||||
Self.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||
open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, sourceModel: MoleculeModelProtocol? = nil) {
|
||||
if let data = try? model.encode(using: JSONEncoder()),
|
||||
let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any],
|
||||
delegateObject?.buttonDelegate?.button?(button, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
if let sourceModel = sourceModel {
|
||||
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: sourceModel)
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
|
||||
} else {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
MVMCoreUI/BaseClasses/Protocols/AccessibilityProtocol.swift
Normal file
14
MVMCoreUI/BaseClasses/Protocols/AccessibilityProtocol.swift
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// AccessibilityProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/21/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public protocol AccessibilityProtocol {
|
||||
/// Should return the argument to use for posting a layout change.
|
||||
func getAccessibilityLayoutChangedArgument() -> Any?
|
||||
}
|
||||
@ -47,7 +47,7 @@ import UIKit
|
||||
public static func setNavigationItem(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) {
|
||||
viewController.navigationItem.title = navigationItemModel.title
|
||||
viewController.navigationItem.accessibilityLabel = navigationItemModel.title
|
||||
viewController.navigationItem.hidesBackButton = (navigationItemModel.backButton != nil)
|
||||
viewController.navigationItem.hidesBackButton = navigationItemModel.hidesSystemBackButton
|
||||
setNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
setNavigationTitleView(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
}
|
||||
|
||||
@ -44,13 +44,17 @@ public extension MVMCoreUISplitViewController {
|
||||
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
|
||||
|
||||
// Add back button first.
|
||||
if navigationItemModel?.alwaysShowBackButton != false {
|
||||
var showBackButton: Bool
|
||||
if let forceBackButton = navigationItemModel?.alwaysShowBackButton {
|
||||
showBackButton = forceBackButton
|
||||
} else {
|
||||
showBackButton = navigationController.viewControllers.count > 1
|
||||
}
|
||||
if showBackButton {
|
||||
if let backButtonModel = navigationItemModel?.backButton {
|
||||
if navigationController.viewControllers.count > 1 || navigationItemModel!.alwaysShowBackButton ?? false {
|
||||
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
} else if let backButton = backButton,
|
||||
navigationController.viewControllers.count > 1 {
|
||||
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
} else if let backButton = backButton {
|
||||
// Default to legacy if we have default back button.
|
||||
leftItems.append(backButton)
|
||||
}
|
||||
}
|
||||
|
||||
@ -923,7 +923,6 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
|
||||
// Creates the back button
|
||||
self.backButton = [[UIBarButtonItem alloc] initWithImage:[self imageForBackButton] style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)];
|
||||
self.backButton.imageInsets = UIEdgeInsetsMake(0, 4, 0, -8);
|
||||
|
||||
// Dismisses a panel if the user taps the main view.
|
||||
if (!self.tapToDismissGesture) {
|
||||
@ -1073,10 +1072,13 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
}
|
||||
|
||||
- (UIViewController *)getCurrentDetailViewController {
|
||||
UIViewController *viewController = self.navigationController.topViewController;
|
||||
if ([viewController conformsToProtocol:@protocol(MVMCoreViewManagerProtocol)]) {
|
||||
viewController = [viewController performSelector:@selector(getCurrentViewController)];
|
||||
}
|
||||
__block UIViewController *viewController = nil;
|
||||
[MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
|
||||
viewController = self.navigationController.topViewController;
|
||||
if ([viewController conformsToProtocol:@protocol(MVMCoreViewManagerProtocol)]) {
|
||||
viewController = [viewController performSelector:@selector(getCurrentViewController)];
|
||||
}
|
||||
}];
|
||||
return viewController;
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
@import MVMCore.MVMCoreLoggingHandler;
|
||||
@class MFViewController;
|
||||
@class MVMCoreTopAlertObject;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -20,6 +21,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)defaultLogActionForController:(nullable id <MVMCoreViewControllerProtocol>)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData;
|
||||
- (nullable NSDictionary *)defaultGetActionTrackDataDictionaryForController:(nullable id <MVMCoreViewControllerProtocol>)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData;
|
||||
|
||||
// Logging top notification.
|
||||
- (void)trackTopNotificationShown:(nonnull UIView *)topNotification topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject additionalData:(nullable NSDictionary *)additionalData;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -20,4 +20,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)trackTopNotificationShown:(UIView *)topNotification topAlertObject:(MVMCoreTopAlertObject *)topAlertObject additionalData:(NSDictionary *)additionalData {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -298,58 +298,64 @@
|
||||
__weak typeof(self) weakSelf = self;
|
||||
MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
|
||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||
// Must notify animation delegate before animating.
|
||||
if (animated && weakSelf.animationDelegate) {
|
||||
[weakSelf.animationDelegate topAlertViewBeginAnimation];
|
||||
}
|
||||
|
||||
[weakSelf.viewToLayout layoutIfNeeded];
|
||||
weakSelf.topLabelConstraintBottom.active = NO;
|
||||
weakSelf.topConstraint.active = YES;
|
||||
weakSelf.expanded = YES;
|
||||
|
||||
void(^animation)(void) = ^(void) {
|
||||
weakSelf.buttonView.button.alpha = 1;
|
||||
weakSelf.buttonView.label.alpha = 1;
|
||||
if (weakSelf.onlyShowTopMessageWhenCollapsed) {
|
||||
weakSelf.shortViewHeight.active = YES;
|
||||
}
|
||||
[weakSelf.viewToLayout layoutIfNeeded];
|
||||
};
|
||||
|
||||
//accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed
|
||||
weakSelf.accessibilityElements = @[weakSelf.buttonView];
|
||||
weakSelf.shortView.isAccessibilityElement = NO;
|
||||
|
||||
void(^completion)(void) = ^(void) {
|
||||
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, weakSelf.buttonView.label);
|
||||
[weakSelf performExpansion:animated onCompletion:^{
|
||||
[operation markAsFinished];
|
||||
};
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:.5 animations:animation completion:^(BOOL finished) {
|
||||
[weakSelf.viewToLayout layoutIfNeeded];
|
||||
|
||||
// Must notify animation delegate when animating finished.
|
||||
[MVMCoreDispatchUtility performBlockInBackground:^{
|
||||
if (weakSelf.animationDelegate) {
|
||||
[weakSelf.animationDelegate topAlertViewFinishAnimation];
|
||||
}
|
||||
}];
|
||||
completion();
|
||||
}];
|
||||
} else {
|
||||
animation();
|
||||
completion();
|
||||
}
|
||||
|
||||
// Collapse after 5 seconds (if the view still exists)
|
||||
[weakSelf autoCollapse];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
[[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)performExpansion:(BOOL)animated onCompletion:(void(^)(void))completionHandler {
|
||||
// Must notify animation delegate before animating.
|
||||
if (animated && self.animationDelegate) {
|
||||
[self.animationDelegate topAlertViewBeginAnimation];
|
||||
}
|
||||
|
||||
[self.viewToLayout layoutIfNeeded];
|
||||
self.topLabelConstraintBottom.active = NO;
|
||||
self.topConstraint.active = YES;
|
||||
self.expanded = YES;
|
||||
|
||||
void(^animation)(void) = ^(void) {
|
||||
self.buttonView.button.alpha = 1;
|
||||
self.buttonView.label.alpha = 1;
|
||||
if (self.onlyShowTopMessageWhenCollapsed) {
|
||||
self.shortViewHeight.active = YES;
|
||||
}
|
||||
[self.viewToLayout layoutIfNeeded];
|
||||
};
|
||||
|
||||
//accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed
|
||||
self.accessibilityElements = @[self.buttonView];
|
||||
self.shortView.isAccessibilityElement = NO;
|
||||
|
||||
void(^completion)(void) = ^(void) {
|
||||
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.buttonView.label);
|
||||
completionHandler();
|
||||
};
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:.5 animations:animation completion:^(BOOL finished) {
|
||||
[self.viewToLayout layoutIfNeeded];
|
||||
|
||||
// Must notify animation delegate when animating finished.
|
||||
[MVMCoreDispatchUtility performBlockInBackground:^{
|
||||
if (self.animationDelegate) {
|
||||
[self.animationDelegate topAlertViewFinishAnimation];
|
||||
}
|
||||
}];
|
||||
completion();
|
||||
}];
|
||||
} else {
|
||||
animation();
|
||||
completion();
|
||||
}
|
||||
|
||||
// Collapse after 5 seconds (if the view still exists)
|
||||
[self autoCollapse];
|
||||
}
|
||||
|
||||
- (void)autoCollapse {
|
||||
if (self.collapseAutomaticallyAfterExpanded) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
@ -379,30 +385,8 @@
|
||||
__weak typeof(self) weakSelf = self;
|
||||
MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
|
||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||
// Must notify animation delegate before animating.
|
||||
if (weakSelf.animationDelegate) {
|
||||
[weakSelf.animationDelegate topAlertViewBeginAnimation];
|
||||
}
|
||||
[weakSelf.viewToLayout layoutIfNeeded];
|
||||
weakSelf.topConstraint.active = NO;
|
||||
weakSelf.topLabelConstraintBottom.active = YES;
|
||||
weakSelf.expanded = NO;
|
||||
[UIView animateWithDuration:.5 animations:^{
|
||||
[weakSelf.viewToLayout layoutIfNeeded];
|
||||
weakSelf.buttonView.button.alpha = 0;
|
||||
weakSelf.buttonView.label.alpha = 0;
|
||||
weakSelf.shortViewHeight.active = NO;
|
||||
} completion:^(BOOL finished) {
|
||||
[weakSelf.viewToLayout layoutIfNeeded];
|
||||
weakSelf.accessibilityElements = @[weakSelf.shortView.label];
|
||||
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
|
||||
[MVMCoreDispatchUtility performBlockInBackground:^{
|
||||
// Must notify animation delegate when animating finished.
|
||||
if (weakSelf.animationDelegate) {
|
||||
[weakSelf.animationDelegate topAlertViewFinishAnimation];
|
||||
}
|
||||
[operation markAsFinished];
|
||||
}];
|
||||
[weakSelf performCollapseAnimationThen:^{
|
||||
[operation markAsFinished];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
@ -410,6 +394,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)performCollapseAnimationThen:(void(^)(void))completionHandler {
|
||||
// Must notify animation delegate before animating.
|
||||
if (self.animationDelegate) {
|
||||
[self.animationDelegate topAlertViewBeginAnimation];
|
||||
}
|
||||
[self.viewToLayout layoutIfNeeded];
|
||||
self.topConstraint.active = NO;
|
||||
self.topLabelConstraintBottom.active = YES;
|
||||
self.expanded = NO;
|
||||
[UIView animateWithDuration:.5 animations:^{
|
||||
[self.viewToLayout layoutIfNeeded];
|
||||
self.buttonView.button.alpha = 0;
|
||||
self.buttonView.label.alpha = 0;
|
||||
self.shortViewHeight.active = NO;
|
||||
} completion:^(BOOL finished) {
|
||||
[self.viewToLayout layoutIfNeeded];
|
||||
self.accessibilityElements = @[self.shortView.label];
|
||||
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
|
||||
// Must notify animation delegate when animating finished.
|
||||
[MVMCoreDispatchUtility performBlockInBackground:^{
|
||||
if (self.animationDelegate) {
|
||||
[self.animationDelegate topAlertViewFinishAnimation];
|
||||
}
|
||||
}];
|
||||
completionHandler();
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)accessibilityFocusChanged:(NSNotification *)notification {
|
||||
if (![MVMCoreUIUtility viewContainsAccessiblityFocus:self]) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityElementFocusedNotification object:nil];
|
||||
|
||||
@ -56,21 +56,22 @@ public extension MVMCoreUITopAlertView {
|
||||
}
|
||||
|
||||
/// Returns the top alert molecule to use and status bar color legacy style.
|
||||
@objc func molecule(for topAlertObject: MVMCoreTopAlertObject, statusBarColor: AutoreleasingUnsafeMutablePointer<UIColor?>?, statusBarStyle: UnsafeMutablePointer<UIStatusBarStyle>?) -> MVMCoreUITopAlertBaseView? {
|
||||
@objc func molecule(for topAlertObject: MVMCoreTopAlertObject, statusBarColor: AutoreleasingUnsafeMutablePointer<UIColor?>?, statusBarStyle: UnsafeMutablePointer<UIStatusBarStyle>?) -> UIView? {
|
||||
do {
|
||||
let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
||||
guard let json = topAlertObject.json else { return nil }
|
||||
let model = try TopNotificationModel.decode(json: json, delegateObject: delegateObject)
|
||||
guard let molecule = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil),
|
||||
let view = molecule as? MVMCoreUITopAlertBaseView else {
|
||||
throw ModelRegistry.Error.decoderOther(message: "Molecule not a top alert")
|
||||
guard let molecule = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil) else {
|
||||
throw ModelRegistry.Error.decoderOther(message: "Molecule not mapped")
|
||||
}
|
||||
if let castView = view as? StatusBarUI {
|
||||
if let castView = molecule as? StatusBarUI {
|
||||
let (color, style) = castView.getStatusBarUI()
|
||||
statusBarColor?.pointee = color
|
||||
statusBarStyle?.pointee = style
|
||||
}
|
||||
return view
|
||||
// TODO: Temporary, waiting for actual restriction from design.
|
||||
molecule.heightAnchor.constraint(lessThanOrEqualToConstant: 140).isActive = true
|
||||
return molecule
|
||||
} catch {
|
||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") {
|
||||
MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject)
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
#import <MVMCoreUI/ButtonDelegateProtocol.h>
|
||||
|
||||
@class MVMCoreTopAlertObject;
|
||||
@class MVMCoreUITopAlertBaseView;
|
||||
|
||||
@interface MVMCoreUITopAlertView : UIView <MVMCoreViewProtocol, MVMCoreTopAlertViewProtocol, MVMCoreLoadDelegateProtocol, MVMCoreActionDelegateProtocol, MVMCorePresentationDelegateProtocol, ButtonDelegateProtocol>
|
||||
|
||||
@ -45,7 +44,7 @@
|
||||
- (void)resetDefaultBackgroundColor:(nullable UIColor *)backgroundColor basedOnStatusBarStyle:(UIStatusBarStyle)style;
|
||||
|
||||
// Can be subclassed for custom views.
|
||||
- (nonnull MVMCoreUITopAlertBaseView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor statusBarStyle:(UIStatusBarStyle *_Nullable)statusBarStyle;
|
||||
- (nonnull UIView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor statusBarStyle:(UIStatusBarStyle *_Nullable)statusBarStyle;
|
||||
|
||||
/// Get the background color based on the type
|
||||
- (nonnull UIColor *)getBackgroundColorForType:(nullable NSString *)type;
|
||||
|
||||
@ -124,7 +124,7 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
||||
}
|
||||
}
|
||||
|
||||
- (nonnull MVMCoreUITopAlertBaseView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor statusBarStyle:(UIStatusBarStyle *_Nullable)statusBarStyle {
|
||||
- (nonnull UIView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor statusBarStyle:(UIStatusBarStyle *_Nullable)statusBarStyle {
|
||||
if (topAlertObject.json) {
|
||||
return [self moleculeFor:topAlertObject statusBarColor:statusBarColor statusBarStyle:statusBarStyle];
|
||||
} else {
|
||||
@ -169,8 +169,10 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
||||
|
||||
UIColor *statusBarColor = nil;
|
||||
UIStatusBarStyle statusBarStyle = UIStatusBarStyleDefault;
|
||||
MVMCoreUITopAlertBaseView *view = [self topAlertViewForTopAlertObject:topAlertObject animationDelegate:animationDelegate statusBarColor:&statusBarColor statusBarStyle:&statusBarStyle];
|
||||
[view updateView:CGRectGetWidth(self.bounds)];
|
||||
UIView *view = [self topAlertViewForTopAlertObject:topAlertObject animationDelegate:animationDelegate statusBarColor:&statusBarColor statusBarStyle:&statusBarStyle];
|
||||
if ([view conformsToProtocol:@protocol(MVMCoreViewProtocol)]) {
|
||||
[((UIView <MVMCoreViewProtocol>*)view) updateView:CGRectGetWidth(self.bounds)];
|
||||
}
|
||||
if (!statusBarColor) {
|
||||
statusBarColor = [UIColor whiteColor];
|
||||
}
|
||||
@ -185,7 +187,20 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
||||
[[MVMCoreUISession sharedGlobal].splitViewController.parentViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
- (void)showAlertView:(nullable MVMCoreUITopAlertBaseView *)view topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
||||
- (void)updateAccessibilityForTopAlert:(nullable UIView *)view {
|
||||
// Update accessibility with top alert
|
||||
if ([view isKindOfClass:[MVMCoreUITopAlertBaseView class]]) {
|
||||
[((MVMCoreUITopAlertBaseView *)view) handleAccessibility];
|
||||
} else {
|
||||
id accessibilityArgument = view;
|
||||
if ([view conformsToProtocol:@protocol(AccessibilityProtocol)]) {
|
||||
accessibilityArgument = [((id <AccessibilityProtocol>)view) getAccessibilityLayoutChangedArgument];
|
||||
}
|
||||
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, accessibilityArgument);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showAlertView:(nullable UIView *)view topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
|
||||
@ -205,12 +220,14 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
||||
} completion:^(BOOL finished) {
|
||||
[weakSelf.superview layoutIfNeeded];
|
||||
[weakSelf.animationDelegate topAlertViewFinishAnimation];
|
||||
[view handleAccessibility];
|
||||
|
||||
[weakSelf updateAccessibilityForTopAlert:view];
|
||||
|
||||
[MVMCoreDispatchUtility performBlockInBackground:^{
|
||||
if ([weakSelf.topAlertObject.delegate respondsToSelector:@selector(topAlertViewShown:topAlertObject:)]) {
|
||||
[weakSelf.topAlertObject.delegate topAlertViewShown:view topAlertObject:topAlertObject];
|
||||
}
|
||||
[[MVMCoreUILoggingHandler sharedLoggingHandler] trackTopNotificationShown:view topAlertObject:topAlertObject additionalData:nil];
|
||||
[operation markAsFinished];
|
||||
completionHandler(finished);
|
||||
}];
|
||||
|
||||
@ -89,7 +89,11 @@
|
||||
if (![focusedElement isKindOfClass:[UIView class]]) {
|
||||
return NO;
|
||||
}
|
||||
return [(UIView *)focusedElement isDescendantOfView:view];
|
||||
__block BOOL containsFocus;
|
||||
[MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
|
||||
containsFocus = [(UIView *)focusedElement isDescendantOfView:view];
|
||||
}];
|
||||
return containsFocus;
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
Loading…
Reference in New Issue
Block a user