Notification Swiftify: Name changes and reorganization.
This commit is contained in:
parent
7da3af94ec
commit
b5e3f42d6e
@ -349,8 +349,8 @@
|
|||||||
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */; };
|
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */; };
|
||||||
D20923592450ECE00044AD09 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20923582450ECE00044AD09 /* TableView.swift */; };
|
D20923592450ECE00044AD09 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20923582450ECE00044AD09 /* TableView.swift */; };
|
||||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
||||||
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* TopNotificationModel.swift */; };
|
D20C7009250BF99B0095B21C /* NotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* NotificationModel.swift */; };
|
||||||
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */; };
|
D20C700B250BFDE40095B21C /* NotificationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* NotificationContainerView.swift */; };
|
||||||
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B43252E00E4004B3F56 /* PageProtocol.swift */; };
|
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B43252E00E4004B3F56 /* PageProtocol.swift */; };
|
||||||
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; };
|
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; };
|
||||||
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
|
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
|
||||||
@ -369,7 +369,7 @@
|
|||||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; };
|
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; };
|
||||||
D22D8393241C27B100D3DF69 /* BaseTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */; };
|
D22D8393241C27B100D3DF69 /* BaseTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */; };
|
||||||
D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8394241FB41200D3DF69 /* UIStackView+Extension.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 */; };
|
D23118B325124E18001C8440 /* NotificationMoleculeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23118B225124E18001C8440 /* NotificationMoleculeView.swift */; };
|
||||||
D2351C7A24A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */; };
|
D2351C7A24A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */; };
|
||||||
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7B24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift */; };
|
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7B24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift */; };
|
||||||
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */; };
|
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */; };
|
||||||
@ -518,7 +518,7 @@
|
|||||||
D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C521A823EDE79E00CA2634 /* ViewController.swift */; };
|
D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C521A823EDE79E00CA2634 /* ViewController.swift */; };
|
||||||
D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */; };
|
D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */; };
|
||||||
D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */; };
|
D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */; };
|
||||||
D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CC251104FE00C75681 /* NotificationModel.swift */; };
|
D2CAC7CD251104FE00C75681 /* NotificationMoleculeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CC251104FE00C75681 /* NotificationMoleculeModel.swift */; };
|
||||||
D2CAC7CF2511052300C75681 /* CollapsableNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */; };
|
D2CAC7CF2511052300C75681 /* CollapsableNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */; };
|
||||||
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */; };
|
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */; };
|
||||||
D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */; };
|
D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */; };
|
||||||
@ -934,8 +934,8 @@
|
|||||||
D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerModelBase.swift; sourceTree = "<group>"; };
|
D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerModelBase.swift; sourceTree = "<group>"; };
|
||||||
D20923582450ECE00044AD09 /* TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = "<group>"; };
|
D20923582450ECE00044AD09 /* TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = "<group>"; };
|
||||||
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
||||||
D20C7008250BF99B0095B21C /* TopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationModel.swift; sourceTree = "<group>"; };
|
D20C7008250BF99B0095B21C /* NotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationModel.swift; sourceTree = "<group>"; };
|
||||||
D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertView+Extension.swift"; sourceTree = "<group>"; };
|
D20C700A250BFDE40095B21C /* NotificationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContainerView.swift; sourceTree = "<group>"; };
|
||||||
D20F3B43252E00E4004B3F56 /* PageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageProtocol.swift; sourceTree = "<group>"; };
|
D20F3B43252E00E4004B3F56 /* PageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageProtocol.swift; sourceTree = "<group>"; };
|
||||||
D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = "<group>"; };
|
D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = "<group>"; };
|
||||||
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||||
@ -954,7 +954,7 @@
|
|||||||
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = "<group>"; };
|
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTemplateModel.swift; sourceTree = "<group>"; };
|
D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTemplateModel.swift; sourceTree = "<group>"; };
|
||||||
D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.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>"; };
|
D23118B225124E18001C8440 /* NotificationMoleculeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationMoleculeView.swift; sourceTree = "<group>"; };
|
||||||
D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableToggleAllTextAndLinksModel.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>"; };
|
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>"; };
|
D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDescription.swift; sourceTree = "<group>"; };
|
||||||
@ -1105,7 +1105,7 @@
|
|||||||
D2C521A823EDE79E00CA2634 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
D2C521A823EDE79E00CA2634 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||||
D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelModel.swift; sourceTree = "<group>"; };
|
D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelModel.swift; sourceTree = "<group>"; };
|
||||||
D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButtonModel.swift; sourceTree = "<group>"; };
|
D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButtonModel.swift; sourceTree = "<group>"; };
|
||||||
D2CAC7CC251104FE00C75681 /* NotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationModel.swift; sourceTree = "<group>"; };
|
D2CAC7CC251104FE00C75681 /* NotificationMoleculeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationMoleculeModel.swift; sourceTree = "<group>"; };
|
||||||
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationModel.swift; sourceTree = "<group>"; };
|
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationModel.swift; sourceTree = "<group>"; };
|
||||||
D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooterModel.swift; sourceTree = "<group>"; };
|
D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooterModel.swift; sourceTree = "<group>"; };
|
||||||
D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooter.swift; sourceTree = "<group>"; };
|
D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooter.swift; sourceTree = "<group>"; };
|
||||||
@ -2114,8 +2114,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */,
|
AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */,
|
||||||
D20C7008250BF99B0095B21C /* TopNotificationModel.swift */,
|
D20C7008250BF99B0095B21C /* NotificationModel.swift */,
|
||||||
D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */,
|
D20C700A250BFDE40095B21C /* NotificationContainerView.swift */,
|
||||||
);
|
);
|
||||||
path = Notification;
|
path = Notification;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2421,8 +2421,8 @@
|
|||||||
children = (
|
children = (
|
||||||
D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */,
|
D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */,
|
||||||
D2FA83D12513EA6900564112 /* NotificationXButton.swift */,
|
D2FA83D12513EA6900564112 /* NotificationXButton.swift */,
|
||||||
D2CAC7CC251104FE00C75681 /* NotificationModel.swift */,
|
D2CAC7CC251104FE00C75681 /* NotificationMoleculeModel.swift */,
|
||||||
D23118B225124E18001C8440 /* Notification.swift */,
|
D23118B225124E18001C8440 /* NotificationMoleculeView.swift */,
|
||||||
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */,
|
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */,
|
||||||
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */,
|
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */,
|
||||||
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */,
|
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */,
|
||||||
@ -2675,7 +2675,7 @@
|
|||||||
011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */,
|
011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */,
|
||||||
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */,
|
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */,
|
||||||
BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */,
|
BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */,
|
||||||
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */,
|
D20C700B250BFDE40095B21C /* NotificationContainerView.swift in Sources */,
|
||||||
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */,
|
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */,
|
||||||
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */,
|
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */,
|
||||||
EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */,
|
EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */,
|
||||||
@ -2816,7 +2816,7 @@
|
|||||||
8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */,
|
8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */,
|
||||||
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */,
|
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */,
|
||||||
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */,
|
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */,
|
||||||
D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */,
|
D2CAC7CD251104FE00C75681 /* NotificationMoleculeModel.swift in Sources */,
|
||||||
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
|
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
|
||||||
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */,
|
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */,
|
||||||
D20923592450ECE00044AD09 /* TableView.swift in Sources */,
|
D20923592450ECE00044AD09 /* TableView.swift in Sources */,
|
||||||
@ -2903,7 +2903,7 @@
|
|||||||
32F8804624765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift in Sources */,
|
32F8804624765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift in Sources */,
|
||||||
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
||||||
4457904E27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift in Sources */,
|
4457904E27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift in Sources */,
|
||||||
D23118B325124E18001C8440 /* Notification.swift in Sources */,
|
D23118B325124E18001C8440 /* NotificationMoleculeView.swift in Sources */,
|
||||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
||||||
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
||||||
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */,
|
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */,
|
||||||
@ -2948,7 +2948,7 @@
|
|||||||
D253BB9E2458751F002DE544 /* BGImageMoleculeModel.swift in Sources */,
|
D253BB9E2458751F002DE544 /* BGImageMoleculeModel.swift in Sources */,
|
||||||
AA104AC924472DC7004D2810 /* HeadersH1ButtonModel.swift in Sources */,
|
AA104AC924472DC7004D2810 /* HeadersH1ButtonModel.swift in Sources */,
|
||||||
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */,
|
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */,
|
||||||
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */,
|
D20C7009250BF99B0095B21C /* NotificationModel.swift in Sources */,
|
||||||
D29C558A25C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift in Sources */,
|
D29C558A25C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift in Sources */,
|
||||||
8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */,
|
8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */,
|
||||||
AFA4932229E5EF2E001A9663 /* NotificationHandler.swift in Sources */,
|
AFA4932229E5EF2E001A9663 /* NotificationHandler.swift in Sources */,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import MVMCore
|
|||||||
/// Notifications that conform are collapsable and can collapse.
|
/// Notifications that conform are collapsable and can collapse.
|
||||||
public protocol CollapsableNotificationProtocol {
|
public protocol CollapsableNotificationProtocol {
|
||||||
/// Collapses the notification.
|
/// Collapses the notification.
|
||||||
|
@MainActor
|
||||||
func collapse()
|
func collapse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,9 +23,9 @@ open class ActionCollapseNotificationHandler: MVMCoreActionHandlerProtocol {
|
|||||||
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
||||||
guard let notification = await NotificationHandler.shared().getCurrentNotification() else { return }
|
guard let notification = await NotificationHandler.shared().getCurrentNotification() else { return }
|
||||||
guard let notification = notification.0 as? CollapsableNotificationProtocol else {
|
guard let notification = notification.0 as? CollapsableNotificationProtocol else {
|
||||||
NotificationHandler.shared().hideTopAlertView()
|
NotificationHandler.shared().hideNotification()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
notification.collapse()
|
await notification.collapse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,6 @@ open class ActionDismissNotificationHandler: MVMCoreActionHandlerProtocol {
|
|||||||
required public init() {}
|
required public init() {}
|
||||||
|
|
||||||
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
||||||
NotificationHandler.shared().hideTopAlertView()
|
NotificationHandler.shared().hideNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,11 +13,11 @@ public struct ActionTopNotificationModel: ActionModelProtocol {
|
|||||||
|
|
||||||
public static var identifier: String = "topNotification"
|
public static var identifier: String = "topNotification"
|
||||||
public var actionType: String = ActionTopNotificationModel.identifier
|
public var actionType: String = ActionTopNotificationModel.identifier
|
||||||
public var topNotification: TopNotificationModel
|
public var topNotification: NotificationModel
|
||||||
public var extraParameters: JSONValueDictionary?
|
public var extraParameters: JSONValueDictionary?
|
||||||
public var analyticsData: JSONValueDictionary?
|
public var analyticsData: JSONValueDictionary?
|
||||||
|
|
||||||
public init(topNotification: TopNotificationModel, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
|
public init(topNotification: NotificationModel, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
|
||||||
self.topNotification = topNotification
|
self.topNotification = topNotification
|
||||||
self.extraParameters = extraParameters
|
self.extraParameters = extraParameters
|
||||||
self.analyticsData = analyticsData
|
self.analyticsData = analyticsData
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import Foundation
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public let topView = CollapsableNotificationTopView()
|
public let topView = CollapsableNotificationTopView()
|
||||||
public let bottomView = NotificationView()
|
public let bottomView = NotificationMoleculeView()
|
||||||
public var verticalStack: UIStackView!
|
public var verticalStack: UIStackView!
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -170,7 +170,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension CollapsableNotification: StatusBarUI {
|
extension CollapsableNotification: StatusBarUI {
|
||||||
func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) {
|
public func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) {
|
||||||
let color = backgroundColor ?? UIColor.mvmGreen
|
let color = backgroundColor ?? UIColor.mvmGreen
|
||||||
var greyScale: CGFloat = 0
|
var greyScale: CGFloat = 0
|
||||||
topView.label.textColor.getWhite(&greyScale, alpha: nil)
|
topView.label.textColor.getWhite(&greyScale, alpha: nil)
|
||||||
@ -189,6 +189,7 @@ extension CollapsableNotification: AccessibilityProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension CollapsableNotification: CollapsableNotificationProtocol {
|
extension CollapsableNotification: CollapsableNotificationProtocol {
|
||||||
|
@MainActor
|
||||||
public func collapse() {
|
public func collapse() {
|
||||||
collapse(animated: true)
|
collapse(animated: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
open class CollapsableNotificationModel: NotificationModel {
|
open class CollapsableNotificationModel: NotificationMoleculeModel {
|
||||||
public class override var identifier: String {
|
public class override var identifier: String {
|
||||||
return "collapsableNotification"
|
return "collapsableNotification"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ import Foundation
|
|||||||
isAccessibilityElement = true
|
isAccessibilityElement = true
|
||||||
accessibilityLabel = label.text
|
accessibilityLabel = label.text
|
||||||
accessibilityTraits = (button.isUserInteractionEnabled && button.actionModel != nil) ? .button : .none
|
accessibilityTraits = (button.isUserInteractionEnabled && button.actionModel != nil) ? .button : .none
|
||||||
NotificationView.amendAccesibilityLabel(for: self)
|
NotificationMoleculeView.amendAccesibilityLabel(for: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func pressed(_ sender: Notification) {
|
@objc func pressed(_ sender: Notification) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// NotificationModel.swift
|
// NotificationMoleculeModel.swift
|
||||||
// MVMCoreUI
|
// MVMCoreUI
|
||||||
//
|
//
|
||||||
// Created by Scott Pfeil on 9/15/20.
|
// Created by Scott Pfeil on 9/15/20.
|
||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
open class NotificationModel: ContainerModel, MoleculeModelProtocol {
|
open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The style of the notification:
|
The style of the notification:
|
||||||
@ -34,7 +34,7 @@ open class NotificationModel: ContainerModel, MoleculeModelProtocol {
|
|||||||
public var body: LabelModel?
|
public var body: LabelModel?
|
||||||
public var button: ButtonModel?
|
public var button: ButtonModel?
|
||||||
public var closeButton: NotificationXButtonModel?
|
public var closeButton: NotificationXButtonModel?
|
||||||
public var style: NotificationModel.Style = .success
|
public var style: NotificationMoleculeModel.Style = .success
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
@ -132,7 +132,7 @@ open class NotificationModel: ContainerModel, MoleculeModelProtocol {
|
|||||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||||
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
|
||||||
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton)
|
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton)
|
||||||
if let style = try typeContainer.decodeIfPresent(NotificationModel.Style.self, forKey: .style) {
|
if let style = try typeContainer.decodeIfPresent(NotificationMoleculeModel.Style.self, forKey: .style) {
|
||||||
self.style = style
|
self.style = style
|
||||||
}
|
}
|
||||||
super.init()
|
super.init()
|
||||||
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Notification.swift
|
// NotificationMoleculeView.swift
|
||||||
// MVMCoreUI
|
// MVMCoreUI
|
||||||
//
|
//
|
||||||
// Created by Scott Pfeil on 9/16/20.
|
// Created by Scott Pfeil on 9/16/20.
|
||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@objcMembers open class NotificationView: Container {
|
@objcMembers open class NotificationMoleculeView: Container {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -63,7 +63,7 @@ import Foundation
|
|||||||
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
guard let model = model as? NotificationModel else { return }
|
guard let model = model as? NotificationMoleculeModel else { return }
|
||||||
labelStack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, nil)
|
labelStack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, nil)
|
||||||
horizontalStack.updateContainedMolecules(with: [labelStack.stackModel, model.button, model.closeButton], delegateObject, nil)
|
horizontalStack.updateContainedMolecules(with: [labelStack.stackModel, model.button, model.closeButton], delegateObject, nil)
|
||||||
updateAccessibility()
|
updateAccessibility()
|
||||||
@ -74,9 +74,9 @@ import Foundation
|
|||||||
}
|
}
|
||||||
|
|
||||||
open func updateAccessibility() {
|
open func updateAccessibility() {
|
||||||
NotificationView.amendAccesibilityLabel(for: headline)
|
NotificationMoleculeView.amendAccesibilityLabel(for: headline)
|
||||||
NotificationView.amendAccesibilityLabel(for: body)
|
NotificationMoleculeView.amendAccesibilityLabel(for: body)
|
||||||
NotificationView.amendAccesibilityLabel(for: button)
|
NotificationMoleculeView.amendAccesibilityLabel(for: button)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats the accessibilityLabel so voice over users know it's in the notification.
|
/// Formats the accessibilityLabel so voice over users know it's in the notification.
|
||||||
@ -88,7 +88,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationView: AccessibilityProtocol {
|
extension NotificationMoleculeView: AccessibilityProtocol {
|
||||||
public func getAccessibilityLayoutChangedArgument() -> Any? {
|
public func getAccessibilityLayoutChangedArgument() -> Any? {
|
||||||
return headline
|
return headline
|
||||||
}
|
}
|
||||||
@ -8,6 +8,14 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import Combine
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
|
/// Allows overrides of the status bar color and style.
|
||||||
|
public protocol StatusBarUI {
|
||||||
|
/// Returns the background color of the status bar view and the style of the status bar.
|
||||||
|
func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle)
|
||||||
|
}
|
||||||
|
|
||||||
// Navigation bar update functions
|
// Navigation bar update functions
|
||||||
public extension MVMCoreUISplitViewController {
|
public extension MVMCoreUISplitViewController {
|
||||||
@ -225,3 +233,31 @@ extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
|
|||||||
updateState(with: viewController)
|
updateState(with: viewController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc public extension MVMCoreUISplitViewController {
|
||||||
|
/// Subscribes for notification events.
|
||||||
|
@objc func subscribeForNotifications() {
|
||||||
|
guard cancellables == nil else { return }
|
||||||
|
var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
// Ensure the status bar background color and tint are proper for the notification.
|
||||||
|
NotificationHandler.shared().onNotificationWillShow.sink { [weak self] (notification, model) in
|
||||||
|
guard let conformer = notification as? StatusBarUI else { return }
|
||||||
|
let statusBarUI = conformer.getStatusBarUI()
|
||||||
|
self?.setStatusBarBackgroundColor(statusBarUI.color, style: statusBarUI.style)
|
||||||
|
}.store(in: &cancellables)
|
||||||
|
|
||||||
|
NotificationHandler.shared().onNotificationUpdated.sink { [weak self] (notification, model) in
|
||||||
|
guard let conformer = notification as? StatusBarUI else { return }
|
||||||
|
let statusBarUI = conformer.getStatusBarUI()
|
||||||
|
self?.setStatusBarBackgroundColor(statusBarUI.color, style: statusBarUI.style)
|
||||||
|
}.store(in: &cancellables)
|
||||||
|
|
||||||
|
// Ensure the status bar background color and tint are proper for the view controller.
|
||||||
|
NotificationHandler.shared().onNotificationDismissed.sink { (notification, model) in
|
||||||
|
guard let conformer = notification as? StatusBarUI else { return }
|
||||||
|
MVMCoreUISplitViewController.main()?.setStatusBarForCurrentViewController()
|
||||||
|
}.store(in: &cancellables)
|
||||||
|
self.cancellables = cancellables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -57,6 +57,8 @@ typedef NS_ENUM(NSInteger, MFNumberOfDrawers) {
|
|||||||
/// Tab bar index history. Contains either indices (0, 1, etc) or NSNull if there was no tab bar indice to set.
|
/// Tab bar index history. Contains either indices (0, 1, etc) or NSNull if there was no tab bar indice to set.
|
||||||
@property (nonnull, strong, nonatomic) NSMutableArray <NSNumber *>*tabBarIndices;
|
@property (nonnull, strong, nonatomic) NSMutableArray <NSNumber *>*tabBarIndices;
|
||||||
|
|
||||||
|
@property (nullable, strong, nonatomic) NSSet *cancellables;
|
||||||
|
|
||||||
// Convenience getter
|
// Convenience getter
|
||||||
+ (nullable instancetype)mainSplitViewController;
|
+ (nullable instancetype)mainSplitViewController;
|
||||||
|
|
||||||
|
|||||||
@ -84,12 +84,18 @@ CGFloat const PanelAnimationDuration = 0.2;
|
|||||||
MVMCoreUISplitViewController *splitViewController = [[self alloc] initWithLeftPanel:leftPanel rightPanel:rightPanel];
|
MVMCoreUISplitViewController *splitViewController = [[self alloc] initWithLeftPanel:leftPanel rightPanel:rightPanel];
|
||||||
splitViewController.topAlertView = topAlertView;
|
splitViewController.topAlertView = topAlertView;
|
||||||
[MVMCoreUISession sharedGlobal].splitViewController = splitViewController;
|
[MVMCoreUISession sharedGlobal].splitViewController = splitViewController;
|
||||||
|
if (topAlertView) {
|
||||||
|
[splitViewController subscribeForNotifications];
|
||||||
|
}
|
||||||
return splitViewController;
|
return splitViewController;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (nullable instancetype)setupAsMainController:(nullable UIViewController <MVMCoreUIPanelProtocol> *)leftPanel rightPanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)rightPanel topAlertView:(nullable UIView*)topAlertView {
|
+ (nullable instancetype)setupAsMainController:(nullable UIViewController <MVMCoreUIPanelProtocol> *)leftPanel rightPanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)rightPanel topAlertView:(nullable UIView*)topAlertView {
|
||||||
MVMCoreUISplitViewController *splitViewController = [self setup:leftPanel rightPanel:rightPanel topAlertView:topAlertView];
|
MVMCoreUISplitViewController *splitViewController = [self setup:leftPanel rightPanel:rightPanel topAlertView:topAlertView];
|
||||||
[[MVMCoreUISession sharedGlobal] setupAsStandardLoadViewDelegate:splitViewController];
|
[[MVMCoreUISession sharedGlobal] setupAsStandardLoadViewDelegate:splitViewController];
|
||||||
|
if (topAlertView) {
|
||||||
|
[splitViewController subscribeForNotifications];
|
||||||
|
}
|
||||||
return splitViewController;
|
return splitViewController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,14 +9,10 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
/// Allows top alerts to determine the status bar color and style.
|
/// A simple container view that shows and hides a notification.
|
||||||
protocol StatusBarUI {
|
|
||||||
func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle)
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NotificationContainerView: UIView {
|
public class NotificationContainerView: UIView {
|
||||||
|
|
||||||
public var currentModel: TopNotificationModel?
|
public var currentModel: NotificationModel?
|
||||||
public var currentNotificationView: UIView?
|
public var currentNotificationView: UIView?
|
||||||
|
|
||||||
lazy private var height = heightAnchor.constraint(equalToConstant: 0)
|
lazy private var height = heightAnchor.constraint(equalToConstant: 0)
|
||||||
@ -31,7 +27,8 @@ public class NotificationContainerView: UIView {
|
|||||||
setupView()
|
setupView()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAccessibilityForTopAlert(_ view: UIView) {
|
/// Posts a layout change with taking the arguments from the view following the AccessibilityProtocol.
|
||||||
|
private func updateAccessibilityForTopAlert(_ view: UIView) {
|
||||||
// Update accessibility with top alert
|
// Update accessibility with top alert
|
||||||
var accessibilityArgument: Any? = view
|
var accessibilityArgument: Any? = view
|
||||||
if let view = view as? AccessibilityProtocol {
|
if let view = view as? AccessibilityProtocol {
|
||||||
@ -39,8 +36,6 @@ public class NotificationContainerView: UIView {
|
|||||||
}
|
}
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: accessibilityArgument)
|
UIAccessibility.post(notification: .layoutChanged, argument: accessibilityArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessibilityFocusChanged; No longer seeing this function, needs a testing.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationContainerView: NotificationTransitionDelegateProtocol {
|
extension NotificationContainerView: NotificationTransitionDelegateProtocol {
|
||||||
@ -54,11 +49,6 @@ extension NotificationContainerView: NotificationTransitionDelegateProtocol {
|
|||||||
if let conformer = notification as? MVMCoreViewProtocol {
|
if let conformer = notification as? MVMCoreViewProtocol {
|
||||||
conformer.updateView(bounds.width)
|
conformer.updateView(bounds.width)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let conformer = notification as? StatusBarUI {
|
|
||||||
let statusBarUI = conformer.getStatusBarUI()
|
|
||||||
MVMCoreUISplitViewController.main()?.setStatusBarBackgroundColor(statusBarUI.color, style: statusBarUI.style)
|
|
||||||
}
|
|
||||||
|
|
||||||
superview?.layoutIfNeeded()
|
superview?.layoutIfNeeded()
|
||||||
await withCheckedContinuation { continuation in
|
await withCheckedContinuation { continuation in
|
||||||
@ -83,9 +73,6 @@ extension NotificationContainerView: NotificationTransitionDelegateProtocol {
|
|||||||
self.superview?.layoutIfNeeded()
|
self.superview?.layoutIfNeeded()
|
||||||
} completion: { finished in
|
} completion: { finished in
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: nil)
|
UIAccessibility.post(notification: .layoutChanged, argument: nil)
|
||||||
if let _ = self.currentNotificationView as? StatusBarUI {
|
|
||||||
MVMCoreUISplitViewController.main()?.setStatusBarForCurrentViewController()
|
|
||||||
}
|
|
||||||
self.currentNotificationView?.removeFromSuperview()
|
self.currentNotificationView?.removeFromSuperview()
|
||||||
self.currentNotificationView = nil
|
self.currentNotificationView = nil
|
||||||
continuation.resume()
|
continuation.resume()
|
||||||
@ -94,10 +81,9 @@ extension NotificationContainerView: NotificationTransitionDelegateProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public func update(with model: TopNotificationModel) {
|
public func update(with model: NotificationModel, delegateObject: MVMCoreUIDelegateObject?) {
|
||||||
guard let currentModel = currentModel,
|
guard let currentModel = currentModel,
|
||||||
currentModel.type == model.type else { return }
|
currentModel.type == model.type else { return }
|
||||||
let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
|
||||||
guard let molecule = currentNotificationView as? MoleculeViewProtocol,
|
guard let molecule = currentNotificationView as? MoleculeViewProtocol,
|
||||||
currentModel.molecule.moleculeName == model.molecule.moleculeName else {
|
currentModel.molecule.moleculeName == model.molecule.moleculeName else {
|
||||||
// Log that we couldn't update.
|
// Log that we couldn't update.
|
||||||
@ -111,11 +97,6 @@ extension NotificationContainerView: NotificationTransitionDelegateProtocol {
|
|||||||
molecule.reset()
|
molecule.reset()
|
||||||
molecule.set(with: model.molecule, delegateObject, nil)
|
molecule.set(with: model.molecule, delegateObject, nil)
|
||||||
(molecule as? MVMCoreViewProtocol)?.updateView(self.bounds.width)
|
(molecule as? MVMCoreViewProtocol)?.updateView(self.bounds.width)
|
||||||
|
|
||||||
// Update status bar.
|
|
||||||
guard let statusBarDelegate = molecule as? StatusBarUI else { return }
|
|
||||||
let statusBarUI = statusBarDelegate.getStatusBarUI()
|
|
||||||
MVMCoreUISplitViewController.main()?.setStatusBarBackgroundColor(statusBarUI.color, style: statusBarUI.style)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ import MVMCore
|
|||||||
import Dispatch
|
import Dispatch
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
|
/// Handles the UI tasks for the notification.
|
||||||
public protocol NotificationTransitionDelegateProtocol {
|
public protocol NotificationTransitionDelegateProtocol {
|
||||||
@MainActor
|
@MainActor
|
||||||
func show(notification: UIView) async
|
func show(notification: UIView) async
|
||||||
@ -18,25 +19,26 @@ public protocol NotificationTransitionDelegateProtocol {
|
|||||||
func hide(notification: UIView) async
|
func hide(notification: UIView) async
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func update(with model: TopNotificationModel)
|
func update(with model: NotificationModel, delegateObject: MVMCoreUIDelegateObject?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An operation for managing the life cycle of the notification.
|
||||||
public class NotificationOperation: MVMCoreOperation {
|
public class NotificationOperation: MVMCoreOperation {
|
||||||
|
|
||||||
public let notification: UIView
|
public let notification: UIView
|
||||||
|
|
||||||
public var notificationModel: TopNotificationModel
|
public var notificationModel: NotificationModel
|
||||||
|
|
||||||
/// The delegate that manages transitioning the notification.
|
/// The delegate that manages transitioning the notification.
|
||||||
private let transitionDelegate: NotificationTransitionDelegateProtocol
|
private let transitionDelegate: NotificationTransitionDelegateProtocol
|
||||||
|
|
||||||
/// The notification animation transition operation (show or hide).
|
/// The showing animation transition operation.
|
||||||
private var transitionOperation: MVMCoreOperation?
|
private weak var showTransitionOperation: Operation?
|
||||||
|
|
||||||
/// The stop timer for non-persistent notifications.
|
/// The stop timer for non-persistent notifications.
|
||||||
private var timerSource: DispatchSourceTimer?
|
private var timerSource: DispatchSourceTimer?
|
||||||
|
|
||||||
/// Determines if the operation is ready. Certain notifications are only meant to be displayed on certain pages.
|
/// Determines if the operation is ready. For example, certain notifications are only meant to be displayed on certain pages and this can be set accordingly.
|
||||||
public var isDisplayable: Bool {
|
public var isDisplayable: Bool {
|
||||||
get {
|
get {
|
||||||
var isDisplayable: Bool = true
|
var isDisplayable: Bool = true
|
||||||
@ -52,7 +54,9 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Thread safety.
|
||||||
private var displayableQueue = DispatchQueue(label: "displayable", attributes: .concurrent)
|
private var displayableQueue = DispatchQueue(label: "displayable", attributes: .concurrent)
|
||||||
|
/// Updates the operation readiness accordingly.
|
||||||
private var _isDisplayable: Bool = true {
|
private var _isDisplayable: Bool = true {
|
||||||
willSet {
|
willSet {
|
||||||
guard super.isReady else { return }
|
guard super.isReady else { return }
|
||||||
@ -73,7 +77,10 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public actor Properties {
|
public actor Properties {
|
||||||
|
/// If the notification is currently displayed.
|
||||||
private var isDisplayed: Bool = false
|
private var isDisplayed: Bool = false
|
||||||
|
|
||||||
|
/// If the notification is currently animating (showing/hiding).
|
||||||
private var isAnimating: Bool = false
|
private var isAnimating: Bool = false
|
||||||
|
|
||||||
fileprivate func set(displayed: Bool) {
|
fileprivate func set(displayed: Bool) {
|
||||||
@ -92,12 +99,13 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
return isAnimating
|
return isAnimating
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Actor isolated properties for the operation.
|
||||||
public var properties = Properties()
|
public var properties = Properties()
|
||||||
|
|
||||||
// A flag for tracking if the operation needs to be re-added because it was cancelled for a higher priority notification.
|
/// A flag for tracking if the operation needs to be re-added because it was cancelled for a higher priority notification.
|
||||||
public var reAddAfterCancel = false
|
public var reAddAfterCancel = false
|
||||||
|
|
||||||
public init(with notification: UIView, notificationModel: TopNotificationModel, transitionDelegate: NotificationTransitionDelegateProtocol) {
|
public init(with notification: UIView, notificationModel: NotificationModel, transitionDelegate: NotificationTransitionDelegateProtocol) {
|
||||||
self.notification = notification
|
self.notification = notification
|
||||||
self.notificationModel = notificationModel
|
self.notificationModel = notificationModel
|
||||||
self.transitionDelegate = transitionDelegate
|
self.transitionDelegate = transitionDelegate
|
||||||
@ -107,15 +115,32 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
|
|
||||||
public override func main() {
|
public override func main() {
|
||||||
guard !checkAndHandleForCancellation() else { return }
|
guard !checkAndHandleForCancellation() else { return }
|
||||||
add { [weak self] in
|
Task {
|
||||||
guard let self = self else { return }
|
await withCheckedContinuation { continuation in
|
||||||
await self.showNotification()
|
// Show the notification.
|
||||||
guard !self.isCancelled else {
|
showTransitionOperation = add(transition: { [weak self] in
|
||||||
// Cancelled, dismiss immediately.
|
guard let self = self else { return }
|
||||||
self.stop()
|
NotificationHandler.shared().onNotificationWillShow.send((self.notification, self.notificationModel))
|
||||||
|
await self.showNotification()
|
||||||
|
}, completionBlock: {
|
||||||
|
continuation.resume()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
guard await properties.getIsDisplayed() else {
|
||||||
|
// If the animation did not complete...
|
||||||
|
markAsFinished()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.updateStopTimer()
|
|
||||||
|
// Publish that the notification has been shown.
|
||||||
|
NotificationHandler.shared().onNotificationShown.send((notification, notificationModel))
|
||||||
|
|
||||||
|
guard !isCancelled else {
|
||||||
|
// If cancelled during the animation, dismiss immediately.
|
||||||
|
stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateStopTimer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,69 +151,33 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
Task {
|
Task {
|
||||||
guard await properties.getIsDisplayed(),
|
guard await properties.getIsDisplayed(),
|
||||||
await !properties.getIsAnimating() else { return }
|
await !properties.getIsAnimating() else { return }
|
||||||
add { [weak self] in
|
// Hide the notification
|
||||||
guard let self = self else { return }
|
await withCheckedContinuation({ continuation in
|
||||||
await self.hideNotification()
|
_ = add(transition: { [weak self] in
|
||||||
guard !self.isCancelled,
|
guard let self = self else { return }
|
||||||
!self.notificationModel.persistent else { return }
|
await self.hideNotification()
|
||||||
self.markAsFinished()
|
}, completionBlock: {
|
||||||
}
|
continuation.resume()
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the transition of the notification to the queue.
|
|
||||||
private func add(transition: @escaping () async -> Void) {
|
|
||||||
Task {
|
|
||||||
guard await properties.getIsDisplayed(),
|
|
||||||
await !properties.getIsAnimating() else { return }
|
|
||||||
transitionOperation = MVMCoreBlockOperation(block: { blockOperation in
|
|
||||||
guard !blockOperation.checkAndHandleForCancellation() else { return }
|
|
||||||
Task {
|
|
||||||
await transition()
|
|
||||||
blockOperation.markAsFinished()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
transitionOperation?.completionBlock = { [weak self] in
|
// The animation must complete...
|
||||||
self?.transitionOperation = nil
|
guard await !self.properties.getIsDisplayed() else { return }
|
||||||
}
|
|
||||||
// Add the animation to the navigation queue to avoid animation collisions.
|
// Publish that the notification has been hidden.
|
||||||
await MVMCoreNavigationHandler.shared()?.addNavigationOperation(transitionOperation!)
|
NotificationHandler.shared().onNotificationDismissed.send((notification, notificationModel))
|
||||||
|
|
||||||
|
guard !isCancelled,
|
||||||
|
!notificationModel.persistent else { return }
|
||||||
|
markAsFinished()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateStopTimer() {
|
|
||||||
if let timerSource = timerSource {
|
|
||||||
timerSource.cancel()
|
|
||||||
}
|
|
||||||
guard !notificationModel.persistent else { return }
|
|
||||||
timerSource = DispatchSource.makeTimerSource()
|
|
||||||
timerSource?.setEventHandler(handler: { [weak self] in
|
|
||||||
print("SSSS TIMER EVENT FIRED FOR: \(String(describing: self?.notificationModel.type))")
|
|
||||||
guard let self = self,
|
|
||||||
!self.isFinished,
|
|
||||||
!self.checkAndHandleForCancellation() else { return }
|
|
||||||
/*
|
|
||||||
// If accessible and focused, do not collapse until unfocused.
|
|
||||||
if (!forceful && [MVMCoreUIUtility viewContainsAccessiblityFocus:self]) {
|
|
||||||
self.hideCompletionHandler = completionHandler;
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessibilityFocusChanged:) name:UIAccessibilityElementFocusedNotification object:nil];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
self.stop()
|
|
||||||
})
|
|
||||||
timerSource?.setCancelHandler(handler: { [weak self] in
|
|
||||||
print("SSSS TIMER EVENT CANCELLED FOR: \(String(describing: self?.notificationModel.type))")
|
|
||||||
})
|
|
||||||
timerSource?.schedule(deadline: .now() + .seconds(notificationModel.dismissTime))
|
|
||||||
}
|
|
||||||
|
|
||||||
public override func cancel() {
|
public override func cancel() {
|
||||||
super.cancel()
|
super.cancel()
|
||||||
Task {
|
Task {
|
||||||
if await !properties.getIsDisplayed() {
|
if await !properties.getIsDisplayed() {
|
||||||
// Cancel any pending show transitions.
|
// Cancel any pending show transitions.
|
||||||
transitionOperation?.cancel()
|
showTransitionOperation?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing if animating.
|
// Do nothing if animating.
|
||||||
@ -201,37 +190,7 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
public func copy(with zone: NSZone? = nil) -> Any {
|
||||||
private func showNotification() async {
|
|
||||||
await properties.set(animating: true)
|
|
||||||
await transitionDelegate.show(notification: notification)
|
|
||||||
await properties.set(displayed: true)
|
|
||||||
await properties.set(animating: false)
|
|
||||||
NotificationHandler.shared().onNotificationShown.send((notification, notificationModel))
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
private func hideNotification() async {
|
|
||||||
await properties.set(animating: true)
|
|
||||||
await transitionDelegate.hide(notification: notification)
|
|
||||||
await properties.set(displayed: false)
|
|
||||||
await properties.set(animating: false)
|
|
||||||
NotificationHandler.shared().onNotificationDismissed.send((notification, notificationModel))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the notification with the new model.
|
|
||||||
public func update(with model: TopNotificationModel) {
|
|
||||||
self.notificationModel = model
|
|
||||||
queuePriority = model.priority
|
|
||||||
guard isExecuting,
|
|
||||||
!isCancelled else { return }
|
|
||||||
updateStopTimer()
|
|
||||||
Task { @MainActor in
|
|
||||||
transitionDelegate.update(with: notificationModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func copy(with zone: NSZone? = nil) -> Any {
|
|
||||||
let operation = NotificationOperation(with: notification, notificationModel: notificationModel, transitionDelegate: transitionDelegate)
|
let operation = NotificationOperation(with: notification, notificationModel: notificationModel, transitionDelegate: transitionDelegate)
|
||||||
operation.reAddAfterCancel = reAddAfterCancel
|
operation.reAddAfterCancel = reAddAfterCancel
|
||||||
operation.isDisplayable = isDisplayable
|
operation.isDisplayable = isDisplayable
|
||||||
@ -242,22 +201,96 @@ public class NotificationOperation: MVMCoreOperation {
|
|||||||
operation.qualityOfService = qualityOfService
|
operation.qualityOfService = qualityOfService
|
||||||
return operation
|
return operation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Automatic
|
||||||
|
|
||||||
|
/// Sets up a timer to hide the notification.
|
||||||
|
private func updateStopTimer() {
|
||||||
|
if let timerSource = timerSource {
|
||||||
|
timerSource.cancel()
|
||||||
|
}
|
||||||
|
guard !notificationModel.persistent else { return }
|
||||||
|
timerSource = DispatchSource.makeTimerSource()
|
||||||
|
timerSource?.setEventHandler(handler: { [weak self] in
|
||||||
|
print("SSSS TIMER EVENT FIRED FOR: \(String(describing: self?.notificationModel.type))")
|
||||||
|
guard let self = self,
|
||||||
|
!self.isFinished,
|
||||||
|
!self.checkAndHandleForCancellation() else { return }
|
||||||
|
|
||||||
|
// If voice over is on and the notification is focused, do not collapse until unfocused.
|
||||||
|
guard !MVMCoreUIUtility.viewContainsAccessiblityFocus(notification) else {
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(accessibilityFocusChanged), name: UIAccessibility.elementFocusedNotification, object: nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.stop()
|
||||||
|
})
|
||||||
|
timerSource?.setCancelHandler(handler: { [weak self] in
|
||||||
|
print("SSSS TIMER EVENT CANCELLED FOR: \(String(describing: self?.notificationModel.type))")
|
||||||
|
})
|
||||||
|
timerSource?.schedule(deadline: .now() + .seconds(notificationModel.dismissTime))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the voice over user leaves top alert focus, hide.
|
||||||
|
@objc func accessibilityFocusChanged(_ notification: NSNotification) {
|
||||||
|
guard let _ = notification.userInfo?[UIAccessibility.focusedElementUserInfoKey],
|
||||||
|
!MVMCoreUIUtility.viewContainsAccessiblityFocus(self.notification) else { return }
|
||||||
|
NotificationCenter.default.removeObserver(self, name: UIAccessibility.elementFocusedNotification, object: nil)
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Transitions
|
||||||
|
|
||||||
|
/// Adds the transition of the notification to the navigation queue to avoid animation collisions.
|
||||||
|
private func add(transition: @escaping () async -> Void, completionBlock: (() -> Void)?) -> Operation {
|
||||||
|
let transitionOperation = MVMCoreBlockOperation(block: { blockOperation in
|
||||||
|
guard !blockOperation.checkAndHandleForCancellation() else { return }
|
||||||
|
Task {
|
||||||
|
await transition()
|
||||||
|
blockOperation.markAsFinished()
|
||||||
|
}
|
||||||
|
})!
|
||||||
|
transitionOperation.completionBlock = completionBlock
|
||||||
|
MVMCoreNavigationHandler.shared()?.addNavigationOperation(transitionOperation)
|
||||||
|
return transitionOperation
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private func showNotification() async {
|
||||||
|
await properties.set(animating: true)
|
||||||
|
await transitionDelegate.show(notification: notification)
|
||||||
|
await properties.set(displayed: true)
|
||||||
|
await properties.set(animating: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private func hideNotification() async {
|
||||||
|
await properties.set(animating: true)
|
||||||
|
await transitionDelegate.hide(notification: notification)
|
||||||
|
await properties.set(displayed: false)
|
||||||
|
await properties.set(animating: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Manages notifications.
|
||||||
public class NotificationHandler {
|
public class NotificationHandler {
|
||||||
|
|
||||||
/// The operation queue of top notification operations.
|
|
||||||
private var queue = OperationQueue()
|
private var queue = OperationQueue()
|
||||||
|
|
||||||
public var transitionDelegate: NotificationTransitionDelegateProtocol
|
private var transitionDelegate: NotificationTransitionDelegateProtocol
|
||||||
|
|
||||||
private var delegateObject: MVMCoreUIDelegateObject?
|
private var delegateObject: MVMCoreUIDelegateObject?
|
||||||
|
|
||||||
|
/// Publishes when a notification will show.
|
||||||
|
public let onNotificationWillShow = PassthroughSubject<(UIView, NotificationModel), Never>()
|
||||||
|
|
||||||
/// Publishes when a notification is shown.
|
/// Publishes when a notification is shown.
|
||||||
public let onNotificationShown = PassthroughSubject<(UIView, TopNotificationModel), Never>()
|
public let onNotificationShown = PassthroughSubject<(UIView, NotificationModel), Never>()
|
||||||
|
|
||||||
/// Publishes when a notification is dismissed.
|
/// Publishes when a notification is dismissed.
|
||||||
public let onNotificationDismissed = PassthroughSubject<(UIView, TopNotificationModel), Never>()
|
public let onNotificationDismissed = PassthroughSubject<(UIView, NotificationModel), Never>()
|
||||||
|
|
||||||
|
/// Publishes when a notification is updated.
|
||||||
|
public let onNotificationUpdated = PassthroughSubject<(UIView, NotificationModel), Never>()
|
||||||
|
|
||||||
/// Returns the handler stored in the CoreUIObject
|
/// Returns the handler stored in the CoreUIObject
|
||||||
public static func shared() -> Self {
|
public static func shared() -> Self {
|
||||||
@ -285,10 +318,13 @@ public class NotificationHandler {
|
|||||||
/// Checks for new top alert json
|
/// Checks for new top alert json
|
||||||
@objc private func responseJSONUpdated(notification: Notification) async {
|
@objc private func responseJSONUpdated(notification: Notification) async {
|
||||||
guard let loadObject = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject) else { return }
|
guard let loadObject = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject) else { return }
|
||||||
|
let delegateObject = loadObject.delegateObject as? MVMCoreUIDelegateObject
|
||||||
|
|
||||||
// Dismiss any top alerts that server wants us to dismiss/
|
// Dismiss any top alerts that server wants us to dismiss.
|
||||||
if let disableType = loadObject.responseInfoMap?.optionalStringForKey("disableType") {
|
if let disableType = loadObject.responseInfoMap?.optionalStringForKey("disableType") {
|
||||||
NotificationHandler.shared().hideTopAlertView(of: disableType)
|
NotificationHandler.shared().cancelNotification(using: { view, model in
|
||||||
|
return model.type == disableType
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show any new top alert.
|
// Show any new top alert.
|
||||||
@ -299,9 +335,10 @@ public class NotificationHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts the json to a model and creates the view and queues up the notification.
|
||||||
public func showNotification(for json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) async {
|
public func showNotification(for json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) async {
|
||||||
do {
|
do {
|
||||||
let model = try TopNotificationModel.decode(json: json, delegateObject: delegateObject)
|
let model = try NotificationModel.decode(json: json, delegateObject: delegateObject)
|
||||||
try await showNotification(for: model, delegateObject: delegateObject)
|
try await showNotification(for: model, delegateObject: delegateObject)
|
||||||
} catch {
|
} catch {
|
||||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") {
|
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") {
|
||||||
@ -332,10 +369,10 @@ public class NotificationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks for existing top alert object of same type and updates it. Only happens for molecular top alerts. Returns true if we updated.
|
/// Checks for existing top alert object of same type and updates it. Only happens for molecular top alerts. Returns true if we updated.
|
||||||
private func checkAndUpdateExisting(with model: TopNotificationModel) -> Bool {
|
private func checkAndUpdateExisting(with model: NotificationModel, delegateObject: MVMCoreUIDelegateObject?) -> Bool {
|
||||||
for case let operation as NotificationOperation in queue.operations {
|
for case let operation as NotificationOperation in queue.operations {
|
||||||
guard operation.notificationModel.type == model.type else { continue }
|
guard operation.notificationModel.type == model.type else { continue }
|
||||||
operation.update(with: model)
|
operation.update(with: model, delegateObject: delegateObject)
|
||||||
let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType
|
let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType
|
||||||
operation.updateDisplayable(by: pageType)
|
operation.updateDisplayable(by: pageType)
|
||||||
reevaluteQueue()
|
reevaluteQueue()
|
||||||
@ -377,76 +414,28 @@ public class NotificationHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Show and hide
|
// MARK: - Verify
|
||||||
|
|
||||||
public func isTopAlertShowing() -> Bool {
|
/// Returns if any notification is executing
|
||||||
|
public func isNotificationShowing() -> Bool {
|
||||||
return queue.operations.first(where: { operation in
|
return queue.operations.first(where: { operation in
|
||||||
return operation.isExecuting
|
return operation.isExecuting
|
||||||
}) != nil
|
}) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hasPersistentTopAlert(of type: String) -> Bool {
|
/** Returns if the first executing operation matches the provided predicate.
|
||||||
|
* @param predicate The predicate block to decide if it is the notification.
|
||||||
|
*/
|
||||||
|
public func hasNotification(using predicate: ((UIView, NotificationModel) -> Bool)) -> Bool {
|
||||||
return queue.operations.first(where: { operation in
|
return queue.operations.first(where: { operation in
|
||||||
guard operation.isExecuting,
|
guard operation.isExecuting,
|
||||||
let operation = operation as? NotificationOperation else { return false }
|
let operation = operation as? NotificationOperation else { return false }
|
||||||
return operation.notificationModel.persistent && operation.notificationModel.type == type
|
return predicate(operation.notification, operation.notificationModel)
|
||||||
}) as? NotificationOperation != nil
|
}) as? NotificationOperation != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the view and queues up the notification.
|
/// Returns the current executing notification view and model
|
||||||
public func showNotification(for model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject? = nil) async throws {
|
public func getCurrentNotification() async -> (UIView, NotificationModel)? {
|
||||||
guard !checkAndUpdateExisting(with: model) else { return }
|
|
||||||
let view = try await createMolecule(for: model, delegateObject: delegateObject)
|
|
||||||
let operation = NotificationOperation(with: view, notificationModel: model, transitionDelegate: transitionDelegate)
|
|
||||||
NotificationHandler.shared().add(operation: operation)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cancel the current top alert view.
|
|
||||||
public func hideTopAlertView() {
|
|
||||||
guard let currentOperation = queue.operations.first(where: { operation in
|
|
||||||
return operation.isExecuting
|
|
||||||
}) as? NotificationOperation else { return }
|
|
||||||
currentOperation.notificationModel.persistent = false
|
|
||||||
currentOperation.reAddAfterCancel = false
|
|
||||||
currentOperation.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cancel all operations of this type.
|
|
||||||
public func hideTopAlertView(of type: String) {
|
|
||||||
for operation in queue.operations {
|
|
||||||
guard let operation = operation as? NotificationOperation,
|
|
||||||
operation.notificationModel.type == type else { continue }
|
|
||||||
operation.reAddAfterCancel = false
|
|
||||||
operation.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cancel all persistent operations of this type.
|
|
||||||
public func hidePersistentTopAlertView(of type: String) {
|
|
||||||
for operation in queue.operations {
|
|
||||||
guard let operation = operation as? NotificationOperation,
|
|
||||||
operation.notificationModel.persistent,
|
|
||||||
operation.notificationModel.type == type else { continue }
|
|
||||||
operation.reAddAfterCancel = false
|
|
||||||
operation.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds an cancels top alerts associated with the object.
|
|
||||||
public func removeTopAlert(for object: TopNotificationModel) {
|
|
||||||
for operation in queue.operations {
|
|
||||||
guard let operation = operation as? NotificationOperation,
|
|
||||||
operation.notificationModel.id == object.id else { return }
|
|
||||||
operation.reAddAfterCancel = false
|
|
||||||
operation.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func removeAllTopAlerts() {
|
|
||||||
queue.cancelAllOperations()
|
|
||||||
}
|
|
||||||
|
|
||||||
public func getCurrentNotification() async -> (UIView, TopNotificationModel)? {
|
|
||||||
for operation in queue.operations {
|
for operation in queue.operations {
|
||||||
guard operation.isExecuting,
|
guard operation.isExecuting,
|
||||||
let operation = operation as? NotificationOperation,
|
let operation = operation as? NotificationOperation,
|
||||||
@ -456,15 +445,43 @@ public class NotificationHandler {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates and returns the molecule view.
|
// MARK: - Show and hide
|
||||||
@MainActor
|
|
||||||
private func createMolecule(for model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject? = nil) throws -> UIView {
|
/// Creates the view and queues up the notification.
|
||||||
do {
|
public func showNotification(for model: NotificationModel, delegateObject: MVMCoreUIDelegateObject? = nil) async throws {
|
||||||
guard let molecule = ModelRegistry.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil) else {
|
guard !checkAndUpdateExisting(with: model, delegateObject: delegateObject) else { return }
|
||||||
throw ModelRegistry.Error.decoderOther(message: "Molecule not mapped")
|
guard let view = ModelRegistry.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: nil) else {
|
||||||
}
|
throw ModelRegistry.Error.decoderOther(message: "Molecule not mapped")
|
||||||
return molecule
|
|
||||||
}
|
}
|
||||||
|
let operation = NotificationOperation(with: view, notificationModel: model, transitionDelegate: transitionDelegate)
|
||||||
|
NotificationHandler.shared().add(operation: operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel the current top alert view.
|
||||||
|
public func hideNotification() {
|
||||||
|
guard let currentOperation = queue.operations.first(where: { operation in
|
||||||
|
return operation.isExecuting
|
||||||
|
}) as? NotificationOperation else { return }
|
||||||
|
currentOperation.notificationModel.persistent = false
|
||||||
|
currentOperation.reAddAfterCancel = false
|
||||||
|
currentOperation.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterates through all scheduled notifications and cancels any that match the provided predicate.
|
||||||
|
* @param predicate The predicate block to decide whether to cancel an notification.
|
||||||
|
*/
|
||||||
|
public func cancelNotification(using predicate: ((UIView, NotificationModel) -> Bool)) {
|
||||||
|
for case let operation as NotificationOperation in queue.operations {
|
||||||
|
if predicate(operation.notification, operation.notificationModel) {
|
||||||
|
operation.reAddAfterCancel = false
|
||||||
|
operation.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel all notifications, current or pending.
|
||||||
|
public func removeAllNotifications() {
|
||||||
|
queue.cancelAllOperations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,6 +504,18 @@ extension NotificationHandler: MVMCorePresentationDelegateProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationOperation {
|
extension NotificationOperation {
|
||||||
|
/// Updates the operation and notification with the new model.
|
||||||
|
public func update(with model: NotificationModel, delegateObject: MVMCoreUIDelegateObject?) {
|
||||||
|
self.notificationModel = model
|
||||||
|
queuePriority = model.priority
|
||||||
|
guard isExecuting,
|
||||||
|
!isCancelled else { return }
|
||||||
|
updateStopTimer()
|
||||||
|
Task { @MainActor in
|
||||||
|
transitionDelegate.update(with: notificationModel, delegateObject: delegateObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Updates if the operation is displayable based on the page type.
|
/// Updates if the operation is displayable based on the page type.
|
||||||
func updateDisplayable(by pageType: String?) {
|
func updateDisplayable(by pageType: String?) {
|
||||||
guard let pages = notificationModel.pages else {
|
guard let pages = notificationModel.pages else {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// TopNotification.swift
|
// NotificationModel.swift
|
||||||
// MVMCoreUI
|
// MVMCoreUI
|
||||||
//
|
//
|
||||||
// Created by Scott Pfeil on 9/11/20.
|
// Created by Scott Pfeil on 9/11/20.
|
||||||
@ -9,7 +9,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
open class TopNotificationModel: Codable, Identifiable {
|
open class NotificationModel: Codable, Identifiable {
|
||||||
public var type: String
|
public var type: String
|
||||||
public var priority = Operation.QueuePriority.normal
|
public var priority = Operation.QueuePriority.normal
|
||||||
public var molecule: MoleculeModelProtocol
|
public var molecule: MoleculeModelProtocol
|
||||||
@ -209,7 +209,7 @@ open class CoreUIModelMapping: ModelMapping {
|
|||||||
ModelRegistry.register(handler: TitleLockup.self, for: TitleLockupModel.self)
|
ModelRegistry.register(handler: TitleLockup.self, for: TitleLockupModel.self)
|
||||||
|
|
||||||
// MARK: - Top Notifications
|
// MARK: - Top Notifications
|
||||||
ModelRegistry.register(handler: NotificationView.self, for: NotificationModel.self)
|
ModelRegistry.register(handler: NotificationMoleculeView.self, for: NotificationMoleculeModel.self)
|
||||||
ModelRegistry.register(handler: CollapsableNotification.self, for: CollapsableNotificationModel.self)
|
ModelRegistry.register(handler: CollapsableNotification.self, for: CollapsableNotificationModel.self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user