From fa00f792c5cf26db59bfade0921422810b8c3b2d Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 29 Oct 2020 10:56:06 -0400 Subject: [PATCH 1/4] Initial file movement --- MVMCoreUI.xcodeproj/project.pbxproj | 98 +++++- .../Alerts/MVMCoreAlertDelegateProtocol.h | 28 ++ .../MVMCoreAlertHandler+Extension.swift | 95 ++++++ MVMCoreUI/Alerts/MVMCoreAlertHandler.h | 119 +++++++ MVMCoreUI/Alerts/MVMCoreAlertHandler.m | 262 +++++++++++++++ .../Alerts/MVMCoreAlertObject+Swift.swift | 45 +++ MVMCoreUI/Alerts/MVMCoreAlertObject.h | 72 +++++ MVMCoreUI/Alerts/MVMCoreAlertObject.m | 302 ++++++++++++++++++ MVMCoreUI/Alerts/MVMCoreAlertOperation.h | 39 +++ MVMCoreUI/Alerts/MVMCoreAlertOperation.m | 242 ++++++++++++++ .../Atomic/Actions/ActionAlertModel.swift | 20 ++ .../ActionCollapseNotificationModel.swift | 0 .../Actions/ActionOpenPanelModel.swift | 0 .../Atomic/Actions/ActionPopupModel.swift | 30 ++ .../Actions/ActionTopAlertModel.swift | 0 MVMCoreUI/Atomic/Actions/AlertModel.swift | 116 +++++++ .../UIAlertActionStyle+Codable.swift | 43 +++ .../UIAlertControllerStyle+Extension.swift | 37 +++ .../MVMCoreGlobalTopAlertDelegateProtocol.h | 21 ++ ...MVMCoreTopAlertAnimationDelegateProtocol.h | 22 ++ .../MVMCoreTopAlertDelegateProtocol.h | 23 ++ MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h | 64 ++++ MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m | 95 ++++++ MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h | 33 ++ MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m | 264 +++++++++++++++ .../TopAlert/MVMCoreTopAlertViewProtocol.h | 28 ++ 26 files changed, 2097 insertions(+), 1 deletion(-) create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertHandler.h create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertHandler.m create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertObject.h create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertObject.m create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertOperation.h create mode 100644 MVMCoreUI/Alerts/MVMCoreAlertOperation.m create mode 100644 MVMCoreUI/Atomic/Actions/ActionAlertModel.swift rename MVMCoreUI/{ => Atomic}/Actions/ActionCollapseNotificationModel.swift (100%) rename MVMCoreUI/{ => Atomic}/Actions/ActionOpenPanelModel.swift (100%) create mode 100644 MVMCoreUI/Atomic/Actions/ActionPopupModel.swift rename MVMCoreUI/{ => Atomic}/Actions/ActionTopAlertModel.swift (100%) create mode 100644 MVMCoreUI/Atomic/Actions/AlertModel.swift create mode 100644 MVMCoreUI/Atomic/Extensions/UIAlertActionStyle+Codable.swift create mode 100644 MVMCoreUI/Atomic/Extensions/UIAlertControllerStyle+Extension.swift create mode 100644 MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertAnimationDelegateProtocol.h create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertDelegateProtocol.h create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m create mode 100644 MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 4b0faceb..5ee5ca5b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -501,6 +501,28 @@ 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 */; }; + D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E6254B0CE600A1C293 /* UIAlertActionStyle+Codable.swift */; }; + D2ED27EC254B0CE700A1C293 /* UIAlertControllerStyle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */; }; + D2ED27ED254B0CE700A1C293 /* ActionPopupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */; }; + D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */; }; + D2ED27EF254B0CE700A1C293 /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27EA254B0CE700A1C293 /* AlertModel.swift */; }; + D2ED27FB254B0E0300A1C293 /* MVMCoreAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */; }; + D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F3254B0E0200A1C293 /* MVMCoreAlertObject+Swift.swift */; }; + D2ED27FD254B0E0300A1C293 /* MVMCoreAlertOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F4254B0E0200A1C293 /* MVMCoreAlertOperation.m */; }; + D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */; }; + D2ED27FF254B0E0300A1C293 /* MVMCoreAlertHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */; }; + D2ED2800254B0E0300A1C293 /* MVMCoreAlertHandler+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F7254B0E0200A1C293 /* MVMCoreAlertHandler+Extension.swift */; }; + D2ED2801254B0E0300A1C293 /* MVMCoreAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */; }; + D2ED2802254B0E0300A1C293 /* MVMCoreAlertObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F9254B0E0200A1C293 /* MVMCoreAlertObject.m */; }; + D2ED2803254B0E0300A1C293 /* MVMCoreAlertHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27FA254B0E0300A1C293 /* MVMCoreAlertHandler.m */; }; + D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */; }; + D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */; }; + D2ED280E254B0EB800A1C293 /* MVMCoreTopAlertOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */; }; + D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2808254B0EB700A1C293 /* MVMCoreTopAlertViewProtocol.h */; }; + D2ED2810254B0EB800A1C293 /* MVMCoreTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2809254B0EB700A1C293 /* MVMCoreTopAlertDelegateProtocol.h */; }; + D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */; }; + D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */; }; + D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */; }; 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 */; }; @@ -1014,6 +1036,28 @@ D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeaderModel.swift; sourceTree = ""; }; D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeader.swift; sourceTree = ""; }; D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = ""; }; + D2ED27E6254B0CE600A1C293 /* UIAlertActionStyle+Codable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertActionStyle+Codable.swift"; sourceTree = ""; }; + D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertControllerStyle+Extension.swift"; sourceTree = ""; }; + D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionPopupModel.swift; sourceTree = ""; }; + D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionAlertModel.swift; sourceTree = ""; }; + D2ED27EA254B0CE700A1C293 /* AlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = ""; }; + D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertDelegateProtocol.h; sourceTree = ""; }; + D2ED27F3254B0E0200A1C293 /* MVMCoreAlertObject+Swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MVMCoreAlertObject+Swift.swift"; sourceTree = ""; }; + D2ED27F4254B0E0200A1C293 /* MVMCoreAlertOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertOperation.m; sourceTree = ""; }; + D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertObject.h; sourceTree = ""; }; + D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertHandler.h; sourceTree = ""; }; + D2ED27F7254B0E0200A1C293 /* MVMCoreAlertHandler+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MVMCoreAlertHandler+Extension.swift"; sourceTree = ""; }; + D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertOperation.h; sourceTree = ""; }; + D2ED27F9254B0E0200A1C293 /* MVMCoreAlertObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertObject.m; sourceTree = ""; }; + D2ED27FA254B0E0300A1C293 /* MVMCoreAlertHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertHandler.m; sourceTree = ""; }; + D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertAnimationDelegateProtocol.h; sourceTree = ""; }; + D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertOperation.h; sourceTree = ""; }; + D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertOperation.m; sourceTree = ""; }; + D2ED2808254B0EB700A1C293 /* MVMCoreTopAlertViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertViewProtocol.h; sourceTree = ""; }; + D2ED2809254B0EB700A1C293 /* MVMCoreTopAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertDelegateProtocol.h; sourceTree = ""; }; + D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertObject.h; sourceTree = ""; }; + D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertObject.m; sourceTree = ""; }; + D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreGlobalTopAlertDelegateProtocol.h; sourceTree = ""; }; D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = ""; }; D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = ""; }; D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = ""; }; @@ -1243,6 +1287,9 @@ 94C0150924215643005811A9 /* ActionTopAlertModel.swift */, 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */, D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */, + D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */, + D2ED27EA254B0CE700A1C293 /* AlertModel.swift */, + D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */, ); path = Actions; sourceTree = ""; @@ -1308,6 +1355,8 @@ 0A7ECC6F2441001C00C828E8 /* UIToolbar+Extension.swift */, 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */, 0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */, + D2ED27E6254B0CE600A1C293 /* UIAlertActionStyle+Codable.swift */, + D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */, ); path = Extensions; sourceTree = ""; @@ -1684,6 +1733,7 @@ D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */ = { isa = PBXGroup; children = ( + D2ED27D8254B0C1F00A1C293 /* Alerts */, 27F973512466071600CAB5C5 /* Behaviors */, D2C78CD324252F4E00B69FDE /* Atomic */, 012A88EF23985E0100FE3DA1 /* CustomPrimitives */, @@ -1698,7 +1748,6 @@ D22D1F582204D2590077CEC0 /* Legacy */, D29DF10F21E67A7D003B2FB9 /* BaseControllers */, D29DF11E21E6851E003B2FB9 /* TopAlert */, - 94C01508242155FE005811A9 /* Actions */, D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */, D29DF0D021E404D4003B2FB9 /* Info.plist */, ); @@ -1821,6 +1870,14 @@ D29DF11E21E6851E003B2FB9 /* TopAlert */ = { isa = PBXGroup; children = ( + D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */, + D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */, + D2ED2809254B0EB700A1C293 /* MVMCoreTopAlertDelegateProtocol.h */, + D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */, + D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */, + D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */, + D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */, + D2ED2808254B0EB700A1C293 /* MVMCoreTopAlertViewProtocol.h */, D20C7008250BF99B0095B21C /* TopNotificationModel.swift */, D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */, D29DF12021E6851E003B2FB9 /* MVMCoreUITopAlertView.h */, @@ -2105,6 +2162,7 @@ isa = PBXGroup; children = ( 017BEB7E23676E870024EF95 /* MoleculeObjectMapping.swift */, + 94C01508242155FE005811A9 /* Actions */, D202AFE2242A5F1400E5BEDF /* Extensions */, D2C78CD424252F5D00B69FDE /* Protocols */, D29DF10D21E67A70003B2FB9 /* Atoms */, @@ -2173,6 +2231,22 @@ path = HeadersAndFooters; sourceTree = ""; }; + D2ED27D8254B0C1F00A1C293 /* Alerts */ = { + isa = PBXGroup; + children = ( + D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */, + D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */, + D2ED27FA254B0E0300A1C293 /* MVMCoreAlertHandler.m */, + D2ED27F7254B0E0200A1C293 /* MVMCoreAlertHandler+Extension.swift */, + D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */, + D2ED27F9254B0E0200A1C293 /* MVMCoreAlertObject.m */, + D2ED27F3254B0E0200A1C293 /* MVMCoreAlertObject+Swift.swift */, + D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */, + D2ED27F4254B0E0200A1C293 /* MVMCoreAlertOperation.m */, + ); + path = Alerts; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -2188,14 +2262,18 @@ 9458C3172406C8FD00930963 /* UIFont+FontWrapping.h in Headers */, D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */, D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */, + D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */, D29DF25921E6A22D003B2FB9 /* MFButtonProtocol.h in Headers */, D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */, + D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */, D29DF2CE21E7C104003B2FB9 /* MFLoadingViewController.h in Headers */, D29DF12A21E6851E003B2FB9 /* MVMCoreUITopAlertView.h in Headers */, + D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */, D29DF27521E79E81003B2FB9 /* MVMCoreUILoggingHandler.h in Headers */, D29DF2B321E7B76D003B2FB9 /* MFLoadingSpinner.h in Headers */, D20492A424329A2800A5EED6 /* MVMCoreUIPagingProtocol.h in Headers */, D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */, + D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */, D29DF17521E69E1F003B2FB9 /* ButtonDelegateProtocol.h in Headers */, D29DF26E21E6AA0B003B2FB9 /* FLAnimatedImage.h in Headers */, D29DF11621E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h in Headers */, @@ -2203,9 +2281,15 @@ D29DF13121E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.h in Headers */, D29DF2CA21E7BFC8003B2FB9 /* MFSizeThreshold.h in Headers */, D29DF28021E7AA51003B2FB9 /* MVMCoreUIDetailViewProtocol.h in Headers */, + D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.h in Headers */, D29DF2EE21ECEADF003B2FB9 /* MFFonts.h in Headers */, D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */, D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */, + D2ED2801254B0E0300A1C293 /* MVMCoreAlertOperation.h in Headers */, + D2ED27FB254B0E0300A1C293 /* MVMCoreAlertDelegateProtocol.h in Headers */, + D2ED2810254B0EB800A1C293 /* MVMCoreTopAlertDelegateProtocol.h in Headers */, + D2ED27FF254B0E0300A1C293 /* MVMCoreAlertHandler.h in Headers */, + D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */, D29DF26F21E6AA0B003B2FB9 /* FLAnimatedImageView.h in Headers */, D29DF2A121E7AF4E003B2FB9 /* MVMCoreUIUtility.h in Headers */, D29DF2C821E7BFC1003B2FB9 /* MFSizeObject.h in Headers */, @@ -2319,6 +2403,7 @@ AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */, 94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */, DBC4391922442197001AB423 /* DashLine.swift in Sources */, + D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */, D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */, AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */, BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */, @@ -2366,6 +2451,7 @@ 012A88C8238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift in Sources */, 8D8067D12444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift in Sources */, 0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */, + D2ED2802254B0E0300A1C293 /* MVMCoreAlertObject.m in Sources */, D224798C231450C8003FCCF9 /* HeadlineBodyToggle.swift in Sources */, 9458C3182406C8FD00930963 /* UIFont+FontWrapping.m in Sources */, 522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */, @@ -2389,6 +2475,8 @@ D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */, D28764AC245898A400CB882D /* ThreeLayerFillMiddleTemplateModel.swift in Sources */, BBBBC87D24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift in Sources */, + D2ED2800254B0E0300A1C293 /* MVMCoreAlertHandler+Extension.swift in Sources */, + D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */, D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */, @@ -2411,6 +2499,7 @@ AAA905E124D1759A00D1EFAB /* ListThreeColumnBillHistory.swift in Sources */, C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, + D2ED27EC254B0CE700A1C293 /* UIAlertControllerStyle+Extension.swift in Sources */, C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */, 014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */, 0A9D091F2433796500D2E6C0 /* NumericIndicatorView.swift in Sources */, @@ -2423,6 +2512,7 @@ 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */, 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */, D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */, + D2ED280E254B0EB800A1C293 /* MVMCoreTopAlertOperation.m in Sources */, D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */, D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */, AA37CBD3251907200027344C /* StarsModel.swift in Sources */, @@ -2433,6 +2523,7 @@ AAC23FAF24D92A1E009208DF /* ListThreeColumnSpeedTest.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, + D2ED27ED254B0CE700A1C293 /* ActionPopupModel.swift in Sources */, 94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */, 943820842432382400B43AF3 /* WebView.swift in Sources */, 0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */, @@ -2486,6 +2577,7 @@ D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */, D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */, D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */, + D2ED2803254B0E0300A1C293 /* MVMCoreAlertHandler.m in Sources */, 0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */, D20923592450ECE00044AD09 /* TableView.swift in Sources */, BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */, @@ -2536,6 +2628,7 @@ D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */, 8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */, 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */, + D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */, BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */, 017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */, 323AC96C24C837FF00F8E4C4 /* ListThreeColumnBillChanges.swift in Sources */, @@ -2573,6 +2666,7 @@ 3265B30224BCA737000D154B /* HeadersH1NoButtonsBodyTextModel.swift in Sources */, D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */, D264FAAC2441009400D98315 /* RadioBoxCollectionViewCell.swift in Sources */, + D2ED27FD254B0E0300A1C293 /* MVMCoreAlertOperation.m in Sources */, BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */, D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */, 012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */, @@ -2588,6 +2682,7 @@ 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */, BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */, 8DEFA95E243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift in Sources */, + D2ED27EF254B0CE700A1C293 /* AlertModel.swift in Sources */, D2EAC0A42541F00F00AA9495 /* CarouselCollectionLayout.swift in Sources */, AAE7270E24AC8B9300A3ED0E /* HeadersH2CaretLink.swift in Sources */, 0AD93A9F24C0AA5100E56A97 /* ImageView.swift in Sources */, @@ -2700,6 +2795,7 @@ D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */, 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */, 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */, + D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */, C003506123AA94CD00B6AC29 /* Button.swift in Sources */, DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */, D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */, diff --git a/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h b/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h new file mode 100644 index 00000000..f4f05e5d --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h @@ -0,0 +1,28 @@ +// +// MVMCoreAlertDelegateProtocol.h +// mobilefirst +// +// Created by Pfeil, Scott Robert on 8/8/17. +// Copyright © 2017 Verizon Wireless. All rights reserved. +// +// Called for popup style alerts. + +#import +@class MVMCoreAlertObject; + +@protocol MVMCoreAlertDelegateProtocol + +@optional + +// helps tracking alert state +- (nullable NSDictionary *)additionalAlertDataToTrackForAlertWithObject:(nullable MVMCoreAlertObject *)alertObject; + +// All are performed on the main thread. +- (void)alertShown:(nonnull UIAlertController *)alertController; +- (void)alertCancelled:(nonnull UIAlertController *)alertController; +- (void)alertDismissed:(nonnull UIAlertController *)alertController; +- (void)alertPaused:(nonnull UIAlertController *)alertController; +- (void)alertUnpaused:(nonnull UIAlertController *)alertController; + +@end + diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift b/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift new file mode 100644 index 00000000..309ea8f5 --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift @@ -0,0 +1,95 @@ +// +// MVMCoreAlertHandler+Extension.swift +// MVMCore +// +// Created by Scott Pfeil on 9/15/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import Foundation + +// Temporary, until we can move page checking logic into isReady of topAlertOperation. +@objcMembers public class NotificationPagesOperation: Operation { + public let pages: [String] + + public init(with pages: [String]) { + self.pages = pages + } + + public override var isReady: Bool { + get { + return super.isReady && isCancelled + } + } +} + +// TODO: Move this type of logic into isReady for the top alert operation... then can remove this dependency operation. +public extension MVMCoreAlertHandler { + + /// Adds a page type dependency to the operation + @objc func addPagesDependency(to operation: MVMCoreTopAlertOperation) { + // This notification may only show for certain pages. + guard let pages = operation.topAlertObject.json?.optionalArrayForKey("pages") as? [String], + pages.count > 0 else { return } + let pagesOperation = NotificationPagesOperation(with: pages) + pageOperations.addOperation(pagesOperation) + operation.addDependency(pagesOperation) + } + + /// Updates the pages requirement for the operation + @objc func updatePages(for operation: MVMCoreTopAlertOperation, with topAlertObject: MVMCoreTopAlertObject) { + // Add new dependencies, remove old. + let previousPages = operation.dependencies.filter { $0 as? NotificationPagesOperation != nil } + addPagesDependency(to: operation) + for pageOperation in previousPages { + pageOperation.cancel() + operation.removeDependency(pageOperation) + } + } + + /// Handles page dependencies for all top alerts with the new pageType + @objc func handleAllPagesDependency(for pageType: String?) { + var currentOperation: MVMCoreTopAlertOperation? = nil + for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations { + // Handle the currently executing opration last to avoid race conditions. + guard !operation.isExecuting else { + currentOperation = operation + continue + } + handlePageDependency(for: operation, with: pageType) + } + if let operation = currentOperation { + handlePageDependency(for: operation, with: pageType) + } + } + + /// Updates the operation based on the page type and its dependencies. + @objc func handlePageDependency(for operation: MVMCoreTopAlertOperation, with pageType: String?) { + guard !operation.isCancelled else { return } + + if let pages = operation.topAlertObject.json?.optionalArrayForKey("pages") as? [String], + pages.count > 0, + (pageType == nil || !pages.contains(pageType!)) { + if let dependency = operation.dependencies.first(where: { $0.isFinished && ($0 as? NotificationPagesOperation)?.pages == pages }) { + // Re-add the dependency if it was previously cancelled. + let pagesOperation = NotificationPagesOperation(with: pages) + pageOperations.addOperation(pagesOperation) + operation.addDependency(pagesOperation) + operation.removeDependency(dependency) + } + if operation.isExecuting { + // If the current running operation should not show on the current page, cancel it. If it's persistent, re-add it + operation.reAddAfterCancel = operation.topAlertObject.persistent + operation.cancel() + } + } + + // Cancel any dependency if it contains the current page. + guard let pageType = pageType else { return } + for case let operation as NotificationPagesOperation in operation.dependencies { + if operation.pages.contains(pageType) { + operation.cancel() + } + } + } +} diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.h b/MVMCoreUI/Alerts/MVMCoreAlertHandler.h new file mode 100644 index 00000000..bba77410 --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.h @@ -0,0 +1,119 @@ +// +// MVMCoreAlertHandler.h +// myverizon +// +// Created by Scott Pfeil on 3/10/14. +// Copyright (c) 2014 Verizon Wireless. All rights reserved. +// +// Keeps track of alerts and handles them. Should always use this to present alerts in mf. + +#import +#import +#import +#import + +@class MVMCoreAlertObject; +@class MVMCoreTopAlertOperation; + +@interface MVMCoreAlertHandler : NSObject + +// An operation queue for displaying popup alerts. +@property (nonnull, strong, nonatomic) NSOperationQueue *popupAlertQueue; + +// An operation queue for top alerts +@property (nonnull, strong, nonatomic) NSOperationQueue *topAlertQueue; + +/// Stores any page dependencies for top alerts +@property (nonnull, strong, nonatomic) NSOperationQueue *pageOperations; + +/// Returns the shared instance of this singleton ++ (nullable instancetype)sharedAlertHandler; + +#pragma mark - Popup Alert Functions + +/// Returns if any alert is currently showing (even if supressed). +- (BOOL)alertCurrentlyShowing; + +/// Returns if a greedy alert is currently showing (even if supressed). +- (BOOL)greedyAlertShowing; + +/** Shows the popup with the passed in parameter. + * @param title The title of the alert. + * @param message The message of the alert. + * @param actions An array of actions for the alert. + * @param isGreedy Sets up a greedy popup. In other words, any popups currently shown or queued are dismissed. + * @return Returns the UIAlertController. + */ +- (nonnull UIAlertController *)showAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nullable NSArray*)actions isGreedy:(BOOL)isGreedy; + +/** Shows the alert. + * @param title The title of the alert. + * @param message The message of the alert. + * @param actions An array of actions for the alert. + * @param alertStyle Popup or action sheet + * @param isGreedy Sets up a greedy alert. In other words, any alerts currently shown or queued are dismissed. + * @param alertDelegate The delegate to be notified. + * @return Returns the UIAlertController. + */ +- (nonnull UIAlertController *)showAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nullable NSArray*)actions alertStyle:(UIAlertControllerStyle)alertStyle isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject *)alertDelegate; + +/** Shows the popup with the passed in alert object. This is a convenience method that automatically handles using the proper alert type based on what's available. + * @param alertObject The alert object to use for the alert. + * @return Returns UIAlertController. + */ +- (nonnull UIAlertController *)showAlertWithAlertObject:(nonnull MVMCoreAlertObject *)alertObject; + +/** Cancels and removes an alert operation for the given alertObject. + * @param alertObject The alertObject scheduled to be shown. + */ +- (void)removeAlertViewForObject:(nonnull MVMCoreAlertObject *)alertObject; + +/** Iterates through all scheduled alerts and cancels any that match the provided predicate. +* @param predicate The predicate block to decide whether to cancel an alert. +*/ +- (void)removeAlertViewUsingPredicate:(BOOL(^_Nonnull)(MVMCoreAlertObject * _Nonnull obj))predicate; + +/// Removes all alerts. +- (void)removeAllAlertViews; + +#pragma mark - Supression Functions + +/// Returns true if alerts are supressed. +- (BOOL)mfAlertsSupressed; + +/// Supresses the alerts (Used by other "apps" in our app). +- (void)supressMFAlerts; + +/// Unsupresses the alerts (Used by other "apps" in our app). +- (void)unSupressMFAlerts; + +#pragma mark - Top Alert Functions + +/// Show based on the object. Will be used by the architecture. Creates an operation and calls addTopAlertOperation. +- (void)showTopAlertWithObject:(nullable MVMCoreTopAlertObject *)topAlertObject; + +/// Adds the top alert operation to the queue. +- (void)addTopAlertOperation:(nonnull MVMCoreTopAlertOperation *)topAlertOperation; + +/// Convenience functions +- (void)showTopAlertErrorWithMessage:(nullable NSString *)message; +- (void)showTopAlertConfirmationWithMessage:(nullable NSString *)message; +- (void)showTopAlertWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; +- (void)showTopAlertWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; + +/// Hides the current alert view. +- (void)hideTopAlertView; + +/// Hides a persistent alert based on the type string. +- (void)hidePersistentTopAlertViewOfType:(nullable NSString *)type; + +/// Removes a scheduled top alert given its top alert object. +- (void)removeTopAlertForObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; + +/// Removes all top alerts. +- (void)removeAllTopAlerts; + +/// Returns YES if the persistent type is already registered in the alert queue. +- (BOOL)hasPersistentTopAlertOfType:(nullable NSString *)type; + +@end diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m new file mode 100644 index 00000000..dce4056b --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m @@ -0,0 +1,262 @@ +// +// MVMCoreAlertHandler.m +// myverizon +// +// Created by Scott Pfeil on 3/10/14. +// Copyright (c) 2014 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreAlertHandler.h" +#import "MVMCoreAlertObject.h" +#import "MVMCoreAlertController.h" +#import "MVMCoreAlertOperation.h" +#import "MVMCoreTopAlertOperation.h" +#import "MVMCoreJSONConstants.h" +#import "NSDictionary+MFConvenience.h" +#import "NSArray+MFConvenience.h" +#import + +@interface MVMCoreAlertHandler () + +// Flag that keeps track of if the alerts are supressed or not. +@property (assign, nonatomic) BOOL mfAlertsSupressed; + +@end + +@implementation MVMCoreAlertHandler + ++ (instancetype)sharedAlertHandler { + static dispatch_once_t once; + static id sharedInstance; + + dispatch_once(&once, ^{ + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +- (nullable instancetype)init { + if (self = [super init]) { + self.popupAlertQueue = [[NSOperationQueue alloc] init]; + self.popupAlertQueue.maxConcurrentOperationCount = 1; + self.topAlertQueue = [[NSOperationQueue alloc] init]; + self.topAlertQueue.maxConcurrentOperationCount = 1; + self.pageOperations = [[NSOperationQueue alloc] init]; + } + return self; +} + +#pragma mark - Popup Alert Functions + +- (BOOL)alertCurrentlyShowing { + return (self.popupAlertQueue.operationCount > 0); +} + +- (BOOL)greedyAlertShowing { + if ([self alertCurrentlyShowing]) { + NSInteger index = [self.popupAlertQueue.operations indexOfObjectPassingTest:^BOOL(__kindof MVMCoreAlertOperation * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (obj.isExecuting && obj.isGreedy && stop) { + *stop = YES; + return YES; + } else { + return NO; + } + }]; + return (index != NSNotFound); + } + return NO; +} + +- (nonnull UIAlertController *)showAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nullable NSArray*)actions isGreedy:(BOOL)isGreedy { + return [self showAlertWithTitle:title message:message actions:actions isGreedy:isGreedy alertDelegate:nil]; +} + +- (nonnull UIAlertController *)showAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nullable NSArray*)actions isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject *)alertDelegate { + return [self showAlertWithTitle:title message:message actions:actions alertStyle:UIAlertControllerStyleAlert isGreedy:isGreedy alertDelegate:alertDelegate]; +} + +- (nonnull UIAlertController *)showAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nullable NSArray*)actions alertStyle:(UIAlertControllerStyle)alertStyle isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject *)alertDelegate { + + // It's a greedy alert! Clear all alerts that are queued up and the one that is showing + if (isGreedy) { + [self removeAllAlertViews]; + } + + // Create the alert. Adds the actions one by one. + MVMCoreAlertController *alertController = [MVMCoreAlertController alertControllerWithTitle:(title ?: @"") message:message preferredStyle:alertStyle]; + for (NSUInteger i = 0; i < [actions count]; i++) { + UIAlertAction *action = [actions objectAtIndex:i ofType:[UIAlertAction class]]; + if (action) { + [alertController addAction:action]; + } + } + + MVMCoreAlertOperation *alertOperation = [[MVMCoreAlertOperation alloc] initWithAlert:alertController isGreedy:isGreedy alertDelegate:alertDelegate]; + [self.popupAlertQueue addOperation:alertOperation]; + return alertController; +} + +- (nonnull UIAlertController *)showAlertWithAlertObject:(nonnull MVMCoreAlertObject *)alertObject { + MVMCoreAlertController *controller = (MVMCoreAlertController *)[self showAlertWithTitle:alertObject.title message:alertObject.message actions:alertObject.actions alertStyle:alertObject.alertStyle isGreedy:alertObject.isGreedy alertDelegate:alertObject.alertDelegate]; + controller.alertObject = alertObject; + return controller; +} + +- (void)removeAlertViewForObject:(MVMCoreAlertObject *)alertObject { + for (MVMCoreAlertOperation *operation in self.popupAlertQueue.operations) { + if ([operation.currentAlertView isKindOfClass:[MVMCoreAlertController class]] && [(MVMCoreAlertController *)operation.currentAlertView alertObject] == alertObject) { + [operation cancel]; + } + } +} + +- (void)removeAlertViewUsingPredicate:(BOOL(^)(MVMCoreAlertObject *obj))predicate { + for (MVMCoreAlertOperation *operation in self.popupAlertQueue.operations) { + if ([operation.currentAlertView isKindOfClass:[MVMCoreAlertController class]]) { + MVMCoreAlertObject *alertObject = [(MVMCoreAlertController *)operation.currentAlertView alertObject]; + if (alertObject && predicate(alertObject)) { + [operation cancel]; + } + } + } +} + +- (void)removeAllAlertViews { + [self.popupAlertQueue cancelAllOperations]; +} + +#pragma mark - Supression Functions + +- (BOOL)mfAlertsSupressed { + return _mfAlertsSupressed; +} + +- (void)supressMFAlerts { + if (!self.mfAlertsSupressed) { + self.mfAlertsSupressed = YES; + for (MVMCoreAlertOperation *operation in self.popupAlertQueue.operations) { + [operation pause]; + } + for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { + [operation pause]; + } + } +} + +- (void)unSupressMFAlerts { + if (self.mfAlertsSupressed) { + self.mfAlertsSupressed = NO; + for (MVMCoreAlertOperation *operation in self.popupAlertQueue.operations) { + [operation unpause]; + } + for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { + [operation unpause]; + } + } +} + +#pragma mark - Top Alert Functions + +- (void)addTopAlertOperation:(nonnull MVMCoreTopAlertOperation *)topAlertOperation { + __block MVMCoreTopAlertOperation *alertOperation = topAlertOperation; + __weak typeof(self) weakSelf = self; + [alertOperation setCompletionBlock:^{ + + // If the alert was cancelled to show another with higher priority, re-add to the operation when cancelled to the queue. + if (alertOperation.reAddAfterCancel) { + MVMCoreTopAlertOperation *newOperation = [alertOperation copy]; + newOperation.reAddAfterCancel = NO; + [weakSelf addTopAlertOperation:newOperation]; + } + alertOperation = nil; + }]; + + [self.topAlertQueue addOperation:alertOperation]; + + // If the current running operation is persistent and has a lower queue priority then the added operation, cancel it and re-add it. + for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { + + if (operation.isExecuting && !operation.isCancelled && operation.topAlertObject.persistent && operation.queuePriority < alertOperation.queuePriority && alertOperation.isReady) { + operation.reAddAfterCancel = YES; + [operation cancel]; + break; + } + } +} + +- (void)showTopAlertWithObject:(nullable MVMCoreTopAlertObject *)topAlertObject { + MVMCoreTopAlertOperation *alertOperation = [[MVMCoreTopAlertOperation alloc] initWithTopAlertObject:topAlertObject]; + [self addTopAlertOperation:alertOperation]; +} + +- (void)showTopAlertErrorWithMessage:(nullable NSString *)message { + + MVMCoreTopAlertObject *topAlertObject = [[MVMCoreTopAlertObject alloc] initWithType:ValueTypeError message:message]; + [self showTopAlertWithObject:topAlertObject]; +} + +- (void)showTopAlertConfirmationWithMessage:(nullable NSString *)message { + + MVMCoreTopAlertObject *topAlertObject = [[MVMCoreTopAlertObject alloc] initWithType:ValueTypeSuccess message:message]; + [self showTopAlertWithObject:topAlertObject]; +} + +- (void)showTopAlertWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { + + MVMCoreTopAlertObject *topAlertObject = [[MVMCoreTopAlertObject alloc] initWithType:type message:message subMessage:subMessage persistent:persistent actionMap:actionMap additionalData:additionalData]; + [self showTopAlertWithObject:topAlertObject]; +} + +- (void)showTopAlertWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { + + MVMCoreTopAlertObject *topAlertObject = [[MVMCoreTopAlertObject alloc] initWithType:type message:message subMessage:subMessage persistent:persistent buttonTitle:buttonTitle userActionHandler:userActionHandler]; + [self showTopAlertWithObject:topAlertObject]; +} + +- (void)hideTopAlertView { + + MVMCoreTopAlertOperation *currentOperation = [self.topAlertQueue.operations firstObject]; + currentOperation.topAlertObject.persistent = NO; + currentOperation.reAddAfterCancel = NO; + [currentOperation cancel]; +} + +- (BOOL)hasPersistentTopAlertOfType:(nullable NSString *)type { + BOOL hasAlert = NO; + for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { + if (operation.topAlertObject.persistent && [operation.topAlertObject.type isEqualToString:type]) { + hasAlert = YES; + } + } + return hasAlert; +} + +- (void)hidePersistentTopAlertViewOfType:(nullable NSString *)type { + if (type) { + for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { + + // Cancel all persistent operations of this type. + if (operation.topAlertObject.persistent && [operation.topAlertObject.type isEqualToString:type]) { + operation.reAddAfterCancel = NO; + [operation cancel]; + } + } + } +} + +- (void)removeTopAlertForObject:(MVMCoreTopAlertObject *)topAlertObject { + for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) { + // Finds an cancels top alerts associated with the object. + if (operation.topAlertObject == topAlertObject) { + operation.reAddAfterCancel = NO; + [operation cancel]; + } + } +} + +- (void)removeAllTopAlerts { + [self.topAlertQueue cancelAllOperations]; +} + +@end diff --git a/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift b/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift new file mode 100644 index 00000000..162dd2d1 --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift @@ -0,0 +1,45 @@ +// +// MVMCoreAlertObject+Swift.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 7/10/20. +// Copyright © 2020 myverizon. All rights reserved. +// + + +public extension MVMCoreAlertObject { + + @objc static func alertObjectWith(action actionJson: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> MVMCoreAlertObject? { + + guard let alertJson = actionJson?.optionalDictionaryForKey("alert"), + (alertJson.optionalStringForKey(KeyTitle) != nil || alertJson.optionalStringForKey(KeyMessage) != nil), + let actionsList = alertJson.optionalArrayForKey("alertActions") as? [[AnyHashable: Any]] + else { + error?.pointee = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: ErrorCode.popupFailed.rawValue, domain: ErrorDomainNative, location: String(describing: self)) + return nil + } + + var actionsForAlert: [UIAlertAction] = [] + + for actionJson in actionsList { + let style = UIAlertAction.Style(rawValue: actionJson.stringForkey("style")) + let alertAction = UIAlertAction(title: actionJson.optionalStringForKey(KeyTitle), style: style) { action in + MVMCoreActionHandler.shared()?.handleAction(with: actionJson.optionalDictionaryForKey("action"), + additionalData: additionalData, + delegateObject: delegateObject) + } + actionsForAlert.append(alertAction) + } + + let alertObject = MVMCoreAlertObject(popupAlertWithTitle: alertJson.optionalStringForKey(KeyTitle), + message: alertJson.optionalStringForKey(KeyMessage), + actions: actionsForAlert, + isGreedy: false) + + if let alertStyle = alertJson.optionalStringForKey("style") { + alertObject?.alertStyle = UIAlertController.Style(rawValue: alertStyle) + } + + return alertObject + } +} diff --git a/MVMCoreUI/Alerts/MVMCoreAlertObject.h b/MVMCoreUI/Alerts/MVMCoreAlertObject.h new file mode 100644 index 00000000..161e123a --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertObject.h @@ -0,0 +1,72 @@ +// +// MVMCoreAlertObject.h +// myverizon +// +// Created by Scott Pfeil on 11/21/14. +// Copyright (c) 2014 Verizon Wireless. All rights reserved. +// +// An object for keeping track of all alert variables. Easier to pass around. + +#import +#import +#import +#import +#import + +@class MVMCoreErrorObject; +@class MVMCoreLoadObject; +@class DelegateObject; + +typedef NS_ENUM(NSInteger, MFAlertType) { + MFAlertTypePopup = 0, + MFAlertTypeField, + MFAlertTypeTop, + MFAlertTypeNone +}; + +typedef void (^TextFieldErrorHandler)(NSArray * _Nonnull fieldErrors); + +@interface MVMCoreAlertObject : NSObject + +@property (nullable, strong, nonatomic) NSString *title; +@property (nullable, copy, nonatomic) NSDictionary *pageJson; +@property (nullable, strong, nonatomic) NSString *message; +@property (nonnull, strong, nonatomic) NSArray *actions; +@property (nonatomic) BOOL isGreedy; +@property (nonatomic) UIAlertControllerStyle alertStyle; +@property (nonatomic) MFAlertType type; +@property (nonatomic) BOOL defaultAction; + +@property (nonnull, strong, nonatomic) NSArray *fieldErrors; +@property (nullable, nonatomic, copy) TextFieldErrorHandler textFieldErrorHandler; + +// Set to be notified of popup style alert events. +@property (nonatomic, weak, nullable) NSObject *alertDelegate; + +// Creates an alert object for an error with the passed in load object response info ++ (nullable instancetype)alertObjectForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error delegateObject:(nullable DelegateObject *)delegateObject; ++ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject; + +// Initializes a popup style alert object. Look at the alert handler to see what each is used for. +- (nullable instancetype)initPopupAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nonnull NSArray *)actions isGreedy:(BOOL)isGreedy; + +// Initializes a popup style alert object using the error passed in. Message is formatted default style. By defualt uses the Okay button to just dismiss the error. +- (nullable instancetype)initPopupAlertWithError:(nullable MVMCoreErrorObject *)error isGreedy:(BOOL)isGreedy; + +// Same as above but no default actions. They are passed in. +- (nullable instancetype)initPopupAlertWithError:(nullable MVMCoreErrorObject *)error actions:(nonnull NSArray *)actions isGreedy:(BOOL)isGreedy; + +// Returns the alert object made with the page json. If there is not enough data to make, we will set error ++ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error; + +// Will show this alert in it's appropriate type style. +- (void)showAlert; + +#pragma mark - Deprecated + +// Creates an alert object for an error with the passed in load object response info ++ (nullable instancetype)alertObjectForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error actionDelegate:(nullable NSObject *)actionDelegate __deprecated; ++ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)actionDelegate __deprecated; ++ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate error:(MVMCoreErrorObject *_Nullable *_Nullable)error __deprecated; + +@end diff --git a/MVMCoreUI/Alerts/MVMCoreAlertObject.m b/MVMCoreUI/Alerts/MVMCoreAlertObject.m new file mode 100644 index 00000000..c8deb7a6 --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertObject.m @@ -0,0 +1,302 @@ +// +// MVMCoreAlertObject.m +// myverizon +// +// Created by Scott Pfeil on 11/21/14. +// Copyright (c) 2014 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreAlertObject.h" +#import "MVMCoreAlertHandler.h" +#import "MVMCoreTopAlertObject.h" +#import "MVMCoreCache.h" +#import "MVMCoreErrorConstants.h" +#import "MVMCoreErrorObject.h" +#import "MVMCoreLoadObject.h" +#import "MVMCoreGetterUtility.h" +#import "NSDictionary+MFConvenience.h" +#import "MVMCoreHardcodedStringsConstants.h" +#import "MVMCoreJSONConstants.h" +#import +#import + +@interface MVMCoreAlertObject () + +@property (strong, nonatomic) MVMCoreLoadObject *loadObject; +@property (nullable, strong, nonatomic) NSString *systemDomain; +@property (nullable, strong, nonatomic) MVMCoreTopAlertObject *topAlertObject; +@end + +@implementation MVMCoreAlertObject + ++ (nullable instancetype)alertObjectForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error delegateObject:(nullable DelegateObject *)delegateObject { + + MVMCoreAlertObject *alert = nil; + if (!error || [ErrorDomainServer isEqualToString:error.domain]) { + alert = [MVMCoreAlertObject alertObjectForPageType:loadObject.pageType responseInfo:loadObject.responseInfoMap additionalData:loadObject.dataForPage delegateObject:delegateObject]; + } else { + alert = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO]; + } + + // only if actions are empty, then go inside and set OK as default action + if (alert.type == MFAlertTypePopup && alert.actions.count == 0) { + alert.defaultAction = YES; + alert.actions = @[[UIAlertAction actionWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedOK] style:UIAlertActionStyleDefault handler:nil]]; + } + return alert; +} + ++ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + + __block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init]; + alert.title = [responseInfo stringForKey:KeyErrorHeading]; + alert.message = [responseInfo stringForKey:KeyUserMessage]; + + NSString *messageStyle = [responseInfo stringForKey:KeyMessageStyle]; + if ([ValueTypeFieldErrors isEqualToString:[responseInfo string:KeyType]]) { + + // field errors. + alert.type = MFAlertTypeField; + alert.fieldErrors = [responseInfo array:ValueTypeFieldErrors]; + } else { + + // Check for top alert (persistent or regular). + if ([messageStyle isEqualToString:ValueMessageStyleTopPersistent] || [messageStyle isEqualToString:ValueMessageStyleTop]) { + + alert.topAlertObject = [[MVMCoreTopAlertObject alloc] initWithResponseInfo:responseInfo]; + alert.topAlertObject.delegate = delegateObject.topAlertDelegate; + alert.topAlertObject.pageType = pageType; + alert.type = MFAlertTypeTop; + } else if ([messageStyle isEqualToString:ValueMessageStylePopup]) { + + // Perform a popup. + alert.type = MFAlertTypePopup; + alert.alertStyle = UIAlertControllerStyleAlert; + + // Check if we have a popup driven by page object (otherwise by default it will just use response info title message with an OK button). + NSString *pageTypeForPopup = [responseInfo stringForKey:@"popupPageType"]; + [[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForPopup queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) { + + MVMCoreErrorObject *error = nil; + MVMCoreAlertObject *popupAlert = [MVMCoreAlertObject alertObjectWithPage:jsonDictionary isGreedy:NO additionalData:additionalData delegateObject:delegateObject error:&error]; + if (error) { + + // Error, popup page not found for page type. + popupAlert = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO]; + } + + if (popupAlert) { + alert = popupAlert; + } + }]; + } else if (messageStyle.length == 0 && pageType) { + + // No message style! + alert.type = MFAlertTypeNone; + } else { + + // Default to popup + alert.type = MFAlertTypePopup; + alert.alertStyle = UIAlertControllerStyleAlert; + } + } + alert.alertDelegate = delegateObject.alertDelegate; + return alert; +} + +- (nullable instancetype)initPopupAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(nonnull NSArray *)actions isGreedy:(BOOL)isGreedy { + if (self = [super init]) { + self.title = title; + self.message = message; + self.actions = actions; + self.isGreedy = isGreedy; + self.type = MFAlertTypePopup; + self.alertStyle = UIAlertControllerStyleAlert; + } + return self; +} + +- (nullable instancetype)initPopupAlertWithError:(nullable MVMCoreErrorObject *)error isGreedy:(BOOL)isGreedy { + + if (self = [super init]) { + self.title = error.title; + self.message = [NSString stringWithFormat:@"%@ (%@)",error.messageToDisplay,[error stringErrorCode]]; + self.actions = @[[UIAlertAction actionWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedOK] style:UIAlertActionStyleDefault handler:nil]]; + self.defaultAction = YES; + self.isGreedy = isGreedy; + self.type = MFAlertTypePopup; + self.alertStyle = UIAlertControllerStyleAlert; + } + return self; +} + +- (nullable instancetype)initPopupAlertWithError:(nullable MVMCoreErrorObject *)error actions:(nonnull NSArray *)actions isGreedy:(BOOL)isGreedy { + + if (self = [super init]) { + self.title = error.title; + self.message = [NSString stringWithFormat:@"%@ (%@)",error.messageToDisplay,[error stringErrorCode]]; + self.actions = actions; + self.isGreedy = isGreedy; + self.type = MFAlertTypePopup; + self.alertStyle = UIAlertControllerStyleAlert; + } + return self; +} + ++ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error { + + MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init]; + alert.title = [page stringForKey:KeyTitle]; + alert.pageJson = page; + alert.message = [page stringForKey:KeyMessage]; + alert.isGreedy = isGreedy; + alert.type = MFAlertTypePopup; + alert.alertStyle = UIAlertControllerStyleAlert; + + NSArray *actions = [page array:KeyLinks]; + NSMutableArray *actionsForAlert = [NSMutableArray array]; + for (NSDictionary *actionMap in actions) { + [actionsForAlert addObject:[UIAlertAction actionWithTitle:[actionMap stringForKey:KeyTitle] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegateObject:delegateObject]; + }]]; + } + alert.actions = actionsForAlert; + + if ((alert.title.length > 0 || alert.message.length > 0) && alert.actions.count > 0) { + return alert; + } else { + if (error) { + *error = [[MVMCoreErrorObject alloc] initWithTitle:nil messageToLog:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodePopupFailed domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_Popup_pageType:%@",NSStringFromClass([delegateObject.alertDelegate class]),[page stringForKey:KeyPageType]]]; + } + return nil; + } +} + +- (void)showAlert { + + switch (self.type) { + case MFAlertTypeField: + self.textFieldErrorHandler(self.fieldErrors); + break; + case MFAlertTypeTop: + [[MVMCoreAlertHandler sharedAlertHandler] showTopAlertWithObject:self.topAlertObject]; + break; + case MFAlertTypePopup: + [[MVMCoreAlertHandler sharedAlertHandler] showAlertWithAlertObject:self]; + break; + default: + break; + } +} + +#pragma mark - Deprecated + ++ (nullable instancetype)alertObjectForLoadObject:(nullable MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error actionDelegate:(nullable NSObject *)actionDelegate { + + MVMCoreAlertObject *alert = nil; + if (!error || [ErrorDomainServer isEqualToString:error.domain]) { + alert = [MVMCoreAlertObject alertObjectForPageType:loadObject.pageType responseInfo:loadObject.responseInfoMap additionalData:loadObject.dataForPage actionDelegate:actionDelegate]; + } else { + alert = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO]; + } + + // only if actions are empty, then go inside and set OK as default action + if (alert.type == MFAlertTypePopup && alert.actions.count == 0) { + alert.defaultAction = YES; + alert.actions = @[[UIAlertAction actionWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedOK] style:UIAlertActionStyleDefault handler:nil]]; + } + return alert; +} + ++ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject *)actionDelegate { + + __block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init]; + alert.title = [responseInfo stringForKey:KeyErrorHeading]; + alert.message = [responseInfo stringForKey:KeyUserMessage]; + + NSString *messageStyle = [responseInfo stringForKey:KeyMessageStyle]; + if ([ValueTypeFieldErrors isEqualToString:[responseInfo string:KeyType]]) { + + // field errors. + alert.type = MFAlertTypeField; + alert.fieldErrors = [responseInfo array:ValueTypeFieldErrors]; + } else { + + // Check for top alert (persistent or regular). + if ([messageStyle isEqualToString:ValueMessageStyleTopPersistent] || [messageStyle isEqualToString:ValueMessageStyleTop]) { + + alert.topAlertObject = [[MVMCoreTopAlertObject alloc] initWithResponseInfo:responseInfo]; + if ([actionDelegate conformsToProtocol:@protocol(MVMCoreTopAlertDelegateProtocol)]) { + alert.topAlertObject.delegate = (NSObject *)actionDelegate; + } + alert.topAlertObject.pageType = pageType; + alert.type = MFAlertTypeTop; + } else if ([messageStyle isEqualToString:ValueMessageStylePopup]) { + + // Perform a popup. + alert.type = MFAlertTypePopup; + alert.alertStyle = UIAlertControllerStyleAlert; + + // Check if we have a popup driven by page object (otherwise by default it will just use response info title message with an OK button). + NSString *pageTypeForPopup = [responseInfo stringForKey:@"popupPageType"]; + [[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForPopup queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) { + + MVMCoreErrorObject *error = nil; + MVMCoreAlertObject *popupAlert = [MVMCoreAlertObject alertObjectWithPage:jsonDictionary isGreedy:NO additionalData:additionalData delegate:actionDelegate error:&error]; + if (error) { + + // Error, popup page not found for page type. + popupAlert = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO]; + } + + if (popupAlert) { + alert = popupAlert; + } + }]; + } else if (messageStyle.length == 0 && pageType) { + + // No message style! + alert.type = MFAlertTypeNone; + } else { + + // Default to popup + alert.type = MFAlertTypePopup; + alert.alertStyle = UIAlertControllerStyleAlert; + } + } + if ([actionDelegate conformsToProtocol:@protocol(MVMCoreAlertDelegateProtocol)]) { + alert.alertDelegate = (NSObject *)actionDelegate; + } + return alert; +} + ++ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate error:(MVMCoreErrorObject *_Nullable *_Nullable)error { + + MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init]; + alert.title = [page stringForKey:KeyTitle]; + alert.pageJson = page; + alert.message = [page stringForKey:KeyMessage]; + alert.isGreedy = isGreedy; + alert.type = MFAlertTypePopup; + alert.alertStyle = UIAlertControllerStyleAlert; + + NSArray *actions = [page array:KeyLinks]; + NSMutableArray *actionsForAlert = [NSMutableArray array]; + for (NSDictionary *actionMap in actions) { + [actionsForAlert addObject:[UIAlertAction actionWithTitle:[actionMap stringForKey:KeyTitle] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[MVMCoreActionHandler sharedActionHandler] handleActionWithDictionary:actionMap additionalData:additionalData delegate:delegate]; + }]]; + } + alert.actions = actionsForAlert; + + if ((alert.title.length > 0 || alert.message.length > 0) && alert.actions.count > 0) { + return alert; + } else { + if (error) { + *error = [[MVMCoreErrorObject alloc] initWithTitle:nil messageToLog:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodePopupFailed domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_Popup_pageType:%@",NSStringFromClass([delegate class]),[page stringForKey:KeyPageType]]]; + } + return nil; + } +} + +@end diff --git a/MVMCoreUI/Alerts/MVMCoreAlertOperation.h b/MVMCoreUI/Alerts/MVMCoreAlertOperation.h new file mode 100644 index 00000000..c48fd867 --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertOperation.h @@ -0,0 +1,39 @@ +// +// MVMCoreAlertOperation.h +// myverizon +// +// Created by Scott Pfeil on 9/28/15. +// Copyright © 2015 Verizon Wireless. All rights reserved. +// +// Operation for handling an alert. Should NOT be on the main queue. + +#import +#import +#import "MVMCoreOperation.h" +#import "MVMCoreAlertDelegateProtocol.h" + +@interface MVMCoreAlertOperation : MVMCoreOperation + +/// Alert controller to be displayed. +@property (nonnull, readonly) UIAlertController *currentAlertView; + +/// If this operation is temporarily paused. +@property (readonly, getter=isPaused) BOOL paused; + +/// If this alert is a greedy alert (See MVMCoreAlertHandler). +@property (readonly, getter=isGreedy) BOOL greedy; + +/// The alert delegate if needed. +@property (readonly, nullable, nonatomic, weak) NSObject *alertDelegate; + +/// Initializes the operation with the alert to display and if it is greedy or not. +- (nullable instancetype)initWithAlert:(nonnull UIAlertController *)alert isGreedy:(BOOL)isGreedy; +- (nullable instancetype)initWithAlert:(nonnull UIAlertController *)alert isGreedy:(BOOL)isGreedy alertDelegate:(nullable id )alertDelegate; + +/// Pauses the operation. Temporarily removes any alert. +- (void)pause; + +/// Unpauses the operation, resuming any alert. +- (void)unpause; + +@end diff --git a/MVMCoreUI/Alerts/MVMCoreAlertOperation.m b/MVMCoreUI/Alerts/MVMCoreAlertOperation.m new file mode 100644 index 00000000..5aa9058b --- /dev/null +++ b/MVMCoreUI/Alerts/MVMCoreAlertOperation.m @@ -0,0 +1,242 @@ +// +// MVMCoreAlertOperation.m +// myverizon +// +// Created by Scott Pfeil on 9/28/15. +// Copyright © 2015 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreAlertOperation.h" +#import "MVMCoreAlertHandler.h" +#import "MVMCoreAlertController.h" +#import "MVMCoreNavigationHandler.h" + +@interface MVMCoreAlertOperation () { + __block BOOL _paused; + __block BOOL _displayed; +} + +@property (readwrite, getter=isPaused) BOOL paused; + +@property (readwrite, getter=isGreedy) BOOL greedy; + +@property (readwrite, getter=isDisplayed) BOOL displayed; + +@property (readwrite, nullable, nonatomic, weak) NSObject *alertDelegate; + +// The currently displayed alert view. +@property (nullable, strong, nonatomic) UIAlertController *currentAlertView; + +// A boolean to keep track of if we alreadys signed up to observe. +@property (assign, nonatomic) BOOL alertBeingObserved; + +// For thread safety +@property (strong, nonatomic) dispatch_queue_t pausedQueue; +@property (strong, nonatomic) dispatch_queue_t displayedQueue; + +// Dismisses the alert. +- (void)dismissAlertView; + +// Begins observing for when the alert is dismissed. +- (void)observeForCurrentAlertViewDismissal; + +// Stops observing for when the alert is dismissed. +- (void)stopObservingAlertView; + +@end + +@implementation MVMCoreAlertOperation + +// The context for kvo +static void * XXContext = &XXContext; + +- (instancetype)init { + + self = [super init]; + if (self) { + self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT); + self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (nullable instancetype)initWithAlert:(nonnull UIAlertController *)alert isGreedy:(BOOL)isGreedy { + + if (self = [self init]) { + self.currentAlertView = alert; + self.greedy = isGreedy; + } + return self; +} + +- (nullable instancetype)initWithAlert:(nonnull UIAlertController *)alert isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject *)alertDelegate { + if (self = [self initWithAlert:alert isGreedy:isGreedy]) { + self.alertDelegate = alertDelegate; + } + return self; +} + +- (void)dealloc { + [self stopObservingAlertView]; +} + +- (BOOL)isPaused { + __block BOOL isPaused; + dispatch_sync(self.pausedQueue, ^{ + isPaused = self->_paused; + }); + return isPaused; +} + +- (void)setPaused:(BOOL)paused { + dispatch_barrier_async(self.pausedQueue, ^{ + self->_paused = paused; + }); +} + +- (BOOL)isDisplayed { + __block BOOL isDisplayed; + dispatch_sync(self.displayedQueue, ^{ + isDisplayed = self->_displayed; + }); + return isDisplayed; +} + +- (void)setDisplayed:(BOOL)displayed { + dispatch_barrier_async(self.displayedQueue, ^{ + self->_displayed = displayed; + }); +} + +- (void)main { + + // Always check for cancellation before launching the task. + if ([self checkAndHandleForCancellation]) { + return; + } + + // Display alert only if alerts aren't supressed. + if (![[MVMCoreAlertHandler sharedAlertHandler] mfAlertsSupressed] && self.currentAlertView) { + + // Observe for when it is removed. + [self observeForCurrentAlertViewDismissal]; + + // Adds the presentation to the animation queue. + [[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:self.currentAlertView animated:YES delegate:nil completionHandler:^{ + + // We finished but it was not displayed yet. It's possible that it was cancelled. Finish this task + if (!self.isDisplayed) { + [self markAsFinished]; + } else if (self.isCancelled) { + [self dismissAlertView]; + } + }]; + } +} + +- (void)cancel { + [super cancel]; + + // Notify delegate that the alert is cancelled. + if ([self.alertDelegate respondsToSelector:@selector(alertCancelled:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.alertDelegate alertCancelled:self.currentAlertView]; + }); + } + + [self dismissAlertView]; +} + +- (void)dismissAlertView { + + if (self.isDisplayed) { + + // Dismisses. + [[MVMCoreNavigationHandler sharedNavigationHandler] dismissViewController:self.currentAlertView animated:YES]; + } +} + +- (void)pause { + [self willChangeValueForKey:@"isPaused"]; + self.paused = YES; + [self didChangeValueForKey:@"isPaused"]; + + // Notify delegate of pause. + if ([self.alertDelegate respondsToSelector:@selector(alertPaused:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.alertDelegate alertPaused:self.currentAlertView]; + }); + } + + // Dismiss until unpaused. + [self dismissAlertView]; +} + +- (void)unpause { + [self willChangeValueForKey:@"isPaused"]; + self.paused = NO; + [self didChangeValueForKey:@"isPaused"]; + + // Notify delegate of unpause. + if ([self.alertDelegate respondsToSelector:@selector(alertUnpaused:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.alertDelegate alertUnpaused:self.currentAlertView]; + }); + } + + // Show alert... + if (self.currentAlertView) { + [self start]; + } +} + +#pragma mark - Observer Functions + +- (void)observeForCurrentAlertViewDismissal { + if (!self.alertBeingObserved && ![[MVMCoreAlertHandler sharedAlertHandler] mfAlertsSupressed] && self.currentAlertView && [self.currentAlertView isKindOfClass:[UIAlertController class]]) { + self.alertBeingObserved = YES; + [self.currentAlertView addObserver:self forKeyPath:@"visible" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:XXContext]; + } +} + +- (void)stopObservingAlertView { + if (self.alertBeingObserved) { + [self.currentAlertView removeObserver:self forKeyPath:@"visible" context:XXContext]; + self.alertBeingObserved = NO; + } +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (context == XXContext && [keyPath isEqualToString:@"visible"]) { + if (![object isVisible]) { + + self.displayed = NO; + + // Notify delegate that the alert is dismissed. + if ([self.alertDelegate respondsToSelector:@selector(alertDismissed:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.alertDelegate alertDismissed:self.currentAlertView]; + }); + } + + // Is visible was set to NO, meaning that the alertview is no longer visible. + if (!self.isPaused) { + [self stopObservingAlertView]; + self.currentAlertView = nil; + [self markAsFinished]; + } + } else { + + self.displayed = YES; + + // Notify delegate that the alert is shown. + if ([self.alertDelegate respondsToSelector:@selector(alertShown:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.alertDelegate alertShown:self.currentAlertView]; + }); + } + } + } +} + +@end diff --git a/MVMCoreUI/Atomic/Actions/ActionAlertModel.swift b/MVMCoreUI/Atomic/Actions/ActionAlertModel.swift new file mode 100644 index 00000000..cc6b3f60 --- /dev/null +++ b/MVMCoreUI/Atomic/Actions/ActionAlertModel.swift @@ -0,0 +1,20 @@ +// +// ActionAlertModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 7/9/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + + +@objcMembers public class ActionAlertModel: ActionModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "alert" + public var actionType: String = ActionAlertModel.identifier + public var alert: AlertModel + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? +} diff --git a/MVMCoreUI/Actions/ActionCollapseNotificationModel.swift b/MVMCoreUI/Atomic/Actions/ActionCollapseNotificationModel.swift similarity index 100% rename from MVMCoreUI/Actions/ActionCollapseNotificationModel.swift rename to MVMCoreUI/Atomic/Actions/ActionCollapseNotificationModel.swift diff --git a/MVMCoreUI/Actions/ActionOpenPanelModel.swift b/MVMCoreUI/Atomic/Actions/ActionOpenPanelModel.swift similarity index 100% rename from MVMCoreUI/Actions/ActionOpenPanelModel.swift rename to MVMCoreUI/Atomic/Actions/ActionOpenPanelModel.swift diff --git a/MVMCoreUI/Atomic/Actions/ActionPopupModel.swift b/MVMCoreUI/Atomic/Actions/ActionPopupModel.swift new file mode 100644 index 00000000..8cdbd83c --- /dev/null +++ b/MVMCoreUI/Atomic/Actions/ActionPopupModel.swift @@ -0,0 +1,30 @@ +// +// ActionPopupModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + + +@objcMembers public class ActionPopupModel: ActionModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "popup" + public var actionType: String = ActionPopupModel.identifier + public var pageType: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(pageType: String, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) { + self.pageType = pageType + self.extraParameters = extraParameters + self.analyticsData = analyticsData + } +} diff --git a/MVMCoreUI/Actions/ActionTopAlertModel.swift b/MVMCoreUI/Atomic/Actions/ActionTopAlertModel.swift similarity index 100% rename from MVMCoreUI/Actions/ActionTopAlertModel.swift rename to MVMCoreUI/Atomic/Actions/ActionTopAlertModel.swift diff --git a/MVMCoreUI/Atomic/Actions/AlertModel.swift b/MVMCoreUI/Atomic/Actions/AlertModel.swift new file mode 100644 index 00000000..866bfb31 --- /dev/null +++ b/MVMCoreUI/Atomic/Actions/AlertModel.swift @@ -0,0 +1,116 @@ +// +// AlertModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 7/14/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import UIKit + + +public class AlertButtonModel: Codable { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var title: String + public var action: ActionModelProtocol + public var style: UIAlertAction.Style = .default + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(_ title: String,_ action: ActionModelProtocol,_ style: UIAlertAction.Style = .default) { + self.title = title + self.action = action + self.style = style + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case title + case action + case style + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + title = try typeContainer.decode(String.self, forKey: .title) + + if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) { + self.style = UIAlertAction.Style(rawValue: style) + } + action = try typeContainer.decodeModel(codingKey: .action) + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(title, forKey: .title) + try container.encode(style.rawValueString, forKey: .style) + try container.encodeModel(action, forKey: .action) + } +} + +public class AlertModel: Codable { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var title: String + public var message: String + public var style: UIAlertController.Style = .alert + public var alertActions: [AlertButtonModel] + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public init(_ title: String,_ message: String,_ alertActions: [AlertButtonModel]) { + self.title = title + self.message = message + self.alertActions = alertActions + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case title + case message + case alertActions + case style + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + title = try typeContainer.decode(String.self, forKey: .title) + message = try typeContainer.decode(String.self, forKey: .message) + alertActions = try typeContainer.decode([AlertButtonModel].self, forKey: .alertActions) + + if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) { + self.style = UIAlertController.Style(rawValue: style) + } + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(title, forKey: .title) + try container.encode(message, forKey: .message) + try container.encode(alertActions, forKey: .alertActions) + try container.encode(style.rawValueString, forKey: .style) + } +} diff --git a/MVMCoreUI/Atomic/Extensions/UIAlertActionStyle+Codable.swift b/MVMCoreUI/Atomic/Extensions/UIAlertActionStyle+Codable.swift new file mode 100644 index 00000000..266a3056 --- /dev/null +++ b/MVMCoreUI/Atomic/Extensions/UIAlertActionStyle+Codable.swift @@ -0,0 +1,43 @@ +// +// UIAlertActionStyle+Codable.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 7/14/20. +// Copyright © 2020 myverizon. All rights reserved. +// + + +extension UIAlertAction.Style: Codable { + + init(rawValue: String) { + switch rawValue { + case "default": + self = .default + + case "cancel": + self = .cancel + + case "destructive": + self = .destructive + + default: + self = .default + } + } + + var rawValueString: String { + switch self { + case .default: + return "default" + + case .cancel: + return "cancel" + + case .destructive: + return "destructive" + + @unknown default: + return "default" + } + } +} diff --git a/MVMCoreUI/Atomic/Extensions/UIAlertControllerStyle+Extension.swift b/MVMCoreUI/Atomic/Extensions/UIAlertControllerStyle+Extension.swift new file mode 100644 index 00000000..1de084af --- /dev/null +++ b/MVMCoreUI/Atomic/Extensions/UIAlertControllerStyle+Extension.swift @@ -0,0 +1,37 @@ +// +// UIAlertControllerStyle+Extension.swift +// MVMCore +// +// Created by Kevin Christiano on 7/17/20. +// Copyright © 2020 myverizon. All rights reserved. +// + + +extension UIAlertController.Style: Codable { + + init(rawValue: String) { + switch rawValue { + case "alert": + self = .alert + + case "actionSheet": + self = .actionSheet + + default: + self = .alert + } + } + + var rawValueString: String { + switch self { + case .alert: + return "alert" + + case .actionSheet: + return "actionSheet" + + @unknown default: + return "alert" + } + } +} diff --git a/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h b/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h new file mode 100644 index 00000000..5ee82e70 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h @@ -0,0 +1,21 @@ +// +// MVMCoreGlobalTopAlertDelegateProtocol.h +// MVMCore +// +// Created by Pfeil, Scott Robert on 1/2/18. +// Copyright © 2018 myverizon. All rights reserved. +// + +#import +#import +@class MVMCoreTopAlertObject; + +@protocol MVMCoreGlobalTopAlertDelegateProtocol + +- (NSOperationQueuePriority)priorityForTopAlertByObject:(nonnull MVMCoreTopAlertObject *)object; + +@optional + +- (nonnull UIView *)getTopAlertView; + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertAnimationDelegateProtocol.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertAnimationDelegateProtocol.h new file mode 100644 index 00000000..bb9f6dfc --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertAnimationDelegateProtocol.h @@ -0,0 +1,22 @@ +// +// MVMCoreTopAlertAnimationDelegateProtocol.h +// mobilefirst +// +// Created by Scott Pfeil on 6/4/16. +// Copyright © 2016 Verizon Wireless. All rights reserved. +// + +#import + +@protocol MVMCoreTopAlertAnimationDelegateProtocol + +// Called when the top alert is starting an animation +- (void)topAlertViewBeginAnimation; + +// Called when the top alert is ending an animation +- (void)topAlertViewFinishAnimation; + +// Called when the top alert close button was pressed by the user +- (void)topAlertCloseButtonPressed; + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertDelegateProtocol.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertDelegateProtocol.h new file mode 100644 index 00000000..af094838 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertDelegateProtocol.h @@ -0,0 +1,23 @@ +// +// MVMCoreTopAlertDelegateProtocol.h +// mobilefirst +// +// Created by Scott Pfeil on 6/4/16. +// Copyright © 2016 Verizon Wireless. All rights reserved. +// + +#import + +@class MVMCoreTopAlertObject; + +@protocol MVMCoreTopAlertDelegateProtocol + +@optional + +- (void)topAlertViewShown:(nonnull id)topAlert topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; +- (void)topAlertViewDismissed:(nonnull id)topAlert; + +// Called when the top alert is pressed. Determines if we should load the option the default way or not. +- (BOOL)shouldLoadTopAlertAction:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h new file mode 100644 index 00000000..350f6e19 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h @@ -0,0 +1,64 @@ +// +// MVMCoreTopAlertObject.h +// mobilefirst +// +// Created by Scott Pfeil on 5/24/16. +// Copyright © 2016 Verizon Wireless. All rights reserved. +// + +#import +#import + +extern NSUInteger const TopAlertDismissTime; + +@interface MVMCoreTopAlertObject : NSObject + +@property (nonatomic) BOOL persistent; +@property (nullable, nonatomic) NSString *type; +@property (nonatomic) NSOperationQueuePriority queuePriority; + +// The text +@property (nullable, strong, nonatomic) NSString *title; +@property (nullable, strong, nonatomic) NSString *message; +@property (nullable, strong, nonatomic) NSString *topMessage; + +// For the button. +@property (nullable, strong, nonatomic) NSDictionary *buttonMap; +@property (nullable, strong, nonatomic) NSDictionary *additionalData; +@property (nonatomic) BOOL useCloseButton; + +// For non action map driven button. +@property (nullable, strong, nonatomic) NSString *buttonTitle; +@property (nullable, copy, nonatomic) void (^userActionHandler)(id _Nonnull sender); + +@property (nullable, weak, nonatomic) NSObject *delegate; + +// This is used to ensure legacy style stays intact with new changes +@property (nonatomic) BOOL useNewStyle; + +// The page type used for the top alert +@property (nullable, strong, nonatomic) NSString *pageType; + +// image name or url used imageviews +@property (nullable, strong, nonatomic) NSString *imageNameOrURL; +@property (nullable, strong, nonatomic) NSString *aboveTextImageString; + +// If 0, uses default 5 seconds. +@property (nonatomic) NSInteger topAlertDismissTime; + +// Server can set color. +@property (nullable, strong, nonatomic) UIColor *backgroundColor; +@property (nullable, strong, nonatomic) UIColor *textColor; + +// The full top alert json. Currently only used for molecular. +@property (nullable, strong, nonatomic) NSDictionary *json; + +- (nullable instancetype)initWithResponseInfo:(nullable NSDictionary *)responseInfo; + +- (nullable instancetype)initWithType:(nullable NSString *)type message:(nullable NSString *)message; + +- (nullable instancetype)initWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData; + +- (nullable instancetype)initWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler; + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m new file mode 100644 index 00000000..72b6de4d --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m @@ -0,0 +1,95 @@ +// +// MVMCoreTopAlertObject.m +// mobilefirst +// +// Created by Scott Pfeil on 5/24/16. +// Copyright © 2016 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreTopAlertObject.h" +#import +#import "MVMCoreGetterUtility.h" +#import "MVMCoreAlertHandler.h" +#import "MVMCoreJSONConstants.h" + + +NSUInteger const TopAlertDismissTime = 5; + +@implementation MVMCoreTopAlertObject + +- (nullable instancetype)initWithResponseInfo:(nullable NSDictionary *)responseInfo { + if (self = [super init]) { + + self.type = [responseInfo string:KeyType]; + self.persistent = [[responseInfo stringForKey:KeyMessageStyle] isEqualToString:ValueMessageStyleTopPersistent]; + + self.title = [responseInfo string:KeyMessage]; + self.message = [responseInfo string:KeyUserMessage]; + self.buttonMap = [responseInfo dict:KeyButtonMap]; + self.topMessage = [responseInfo string:KeyTopMessage]; + self.imageNameOrURL = [responseInfo string:@"topAlertImageUrl"]; + self.aboveTextImageString = [responseInfo string:@"topAlertImageURLAboveText"]; + + NSString *color = [responseInfo string:@"topAlertColor"]; + if (color) { + self.backgroundColor = [MVMCoreGetterUtility getColorForHexString:color]; + } + color = [responseInfo string:@"messageColor"]; + if (color) { + self.textColor = [MVMCoreGetterUtility getColorForHexString:color]; + } + + // The default is yes if not sent by server (for legacy to work as is) + NSNumber *closeButton = [responseInfo optionalNumberForKey:KeyCloseButton]; + if (closeButton != nil) { + self.useCloseButton = [closeButton boolValue]; + } else { + self.useCloseButton = YES; + } + + self.useNewStyle = [responseInfo boolForKey:@"newTopAlertStyle"]; + + // Server driven dismiss time. + NSNumber *topAlertTime = [responseInfo optionalNumberForKey:@"topAlertTime"]; + if (topAlertTime != nil) { + self.topAlertDismissTime = [topAlertTime integerValue]; + } + } + return self; +} + +- (nullable instancetype)initWithType:(nullable NSString *)type message:(nullable NSString *)message { + return [self initWithType:type message:nil subMessage:message persistent:NO actionMap:nil additionalData:nil]; +} + +- (nullable instancetype)initWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData { + + if (self = [super init]) { + + self.type = type; + self.persistent = persistent; + + self.title = message; + self.message = subMessage; + self.buttonMap = actionMap; + self.additionalData = additionalData; + } + return self; +} + +- (nullable instancetype)initWithType:(nullable NSString *)type message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage persistent:(BOOL)persistent buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id _Nonnull sender))userActionHandler { + + if (self = [super init]) { + + self.type = type; + self.persistent = persistent; + + self.title = message; + self.message = subMessage; + self.buttonTitle = buttonTitle; + self.userActionHandler = userActionHandler; + } + return self; +} + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h new file mode 100644 index 00000000..6dadc898 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h @@ -0,0 +1,33 @@ +// +// MVMCoreTopAlertOperation.h +// mobilefirst +// +// Created by Scott Pfeil on 6/4/16. +// Copyright © 2016 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreOperation.h" +#import "MVMCoreTopAlertAnimationDelegateProtocol.h" + +@class MVMCoreTopAlertObject; + +@interface MVMCoreTopAlertOperation : MVMCoreOperation + +@property (readonly, getter=isPaused) BOOL paused; + +@property (nonatomic) BOOL reAddAfterCancel; + +@property (nonnull, nonatomic, strong) MVMCoreTopAlertObject *topAlertObject; + +- (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; + +/// Updates the operation with a new object +- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject; + +// Pauses the operation. Temporarily removes any alert. +- (void)pause; + +// Unpauses the operation, resuming any alert. +- (void)unpause; + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m new file mode 100644 index 00000000..6eb8f045 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m @@ -0,0 +1,264 @@ +// +// MVMCoreTopAlertOperation.m +// mobilefirst +// +// Created by Scott Pfeil on 6/4/16. +// Copyright © 2016 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreTopAlertOperation.h" +#import "MVMCoreTopAlertObject.h" +#import "MVMCoreAlertHandler.h" +#import "MVMCoreObject.h" +#import "MVMCoreSessionObject.h" + +@interface MVMCoreTopAlertOperation () { + __block BOOL _paused; + __block BOOL _displayed; + __block BOOL _animating; +} + +@property (readwrite, getter=isPaused) BOOL paused; +@property (readwrite, getter=isDisplayed) BOOL displayed; +@property (readwrite, getter=isAnimating) BOOL animating; + +// For thread safety +@property (strong, nonatomic) dispatch_queue_t pausedQueue; +@property (strong, nonatomic) dispatch_queue_t displayedQueue; +@property (strong, nonatomic) dispatch_queue_t animatingQueue; + +@property (nonatomic, strong) dispatch_source_t timerSource; + +@end + +@implementation MVMCoreTopAlertOperation + +- (instancetype)init { + + self = [super init]; + if (self) { + self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT); + self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT); + self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject { + + if (self = [self init]) { + self.topAlertObject = topAlertObject; + + // Sets the queue priority for various types of alerts. + self.queuePriority = [[MVMCoreObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; + } + return self; +} + +- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject { + self.topAlertObject = topAlertObject; + self.queuePriority = [[MVMCoreObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; + if (self.isExecuting && !self.isCancelled && !self.isPaused) { + [self updateDismissTimer]; + UIView *topAlertView = [[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView]; + if ([topAlertView respondsToSelector:@selector(updateTopAlertWith:)]) { + [topAlertView updateTopAlertWith:topAlertObject]; + } + } +} + +- (BOOL)isPaused { + __block BOOL isPaused; + dispatch_sync(self.pausedQueue, ^{ + isPaused = self->_paused; + }); + return isPaused; +} + +- (void)setPaused:(BOOL)paused { + dispatch_barrier_async(self.pausedQueue, ^{ + self->_paused = paused; + }); +} + +- (BOOL)isDisplayed { + __block BOOL isDisplayed; + dispatch_sync(self.displayedQueue, ^{ + isDisplayed = self->_displayed; + }); + return isDisplayed; +} + +- (void)setDisplayed:(BOOL)displayed { + dispatch_barrier_async(self.displayedQueue, ^{ + self->_displayed = displayed; + }); +} + +- (BOOL)isAnimating { + __block BOOL isAnimating; + dispatch_sync(self.animatingQueue, ^{ + isAnimating = self->_animating; + }); + return isAnimating; +} + +- (void)setAnimating:(BOOL)animating { + dispatch_barrier_async(self.animatingQueue, ^{ + self->_animating = animating; + }); +} + +- (void)main { + + // Always check for cancellation before launching the task. + if ([self checkAndHandleForCancellation]) { + return; + } + + // Do nothing if paused + if (!self.isPaused) { + + // Display alert only if alerts aren't supressed. + if (![[MVMCoreAlertHandler sharedAlertHandler] mfAlertsSupressed]) { + + // Show + if (![[MVMCoreObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { + + // Needs to be a top alert view.... + [self markAsFinished]; + } else { + UIView *topAlertView = [[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView]; + [topAlertView showWithTopAlertObject:self.topAlertObject animationDelegate:self completionHandler:^(BOOL finished) { + + self.displayed = YES; + if (self.isCancelled) { + + // Cancelled, dismiss immediately. + [self dismissAlertView:YES forceful:YES]; + } else if (self.isPaused) { + + // Paused, dismiss for the time being if persistent. + [self dismissAlertView:!self.topAlertObject.persistent forceful:YES]; + } else { + [self updateDismissTimer]; + } + }]; + } + } else { + [self pause]; + } + } +} + +/// Updates the timer to dismiss the top alert. +- (void)updateDismissTimer { + if (self.timerSource) { + dispatch_source_cancel(self.timerSource); + } + if (self.topAlertObject.persistent) { + return; + } + + NSInteger dismissTime; + if (self.topAlertObject.topAlertDismissTime > 0) { + dismissTime = self.topAlertObject.topAlertDismissTime; + } else { + dismissTime = TopAlertDismissTime; + } + + self.timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_timer(self.timerSource, dispatch_time(DISPATCH_TIME_NOW, dismissTime * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, (1ull * NSEC_PER_SEC) / 10); + + __weak typeof(self) weakSelf = self; + dispatch_source_set_event_handler(self.timerSource, ^{ + if (weakSelf.isFinished || [weakSelf checkAndHandleForCancellation]) { + return; + } + [weakSelf dismissAlertView:YES forceful:NO]; + }); + dispatch_resume(self.timerSource); +} + +- (void)cancel { + [super cancel]; + + // Do nothing if animating. + if (!self.isAnimating) { + + if (self.isDisplayed) { + [self dismissAlertView:YES forceful:YES]; + } else if (self.isExecuting) { + [self markAsFinished]; + } + } +} + +- (void)dismissAlertView:(BOOL)andFinish forceful:(BOOL)forceful { + if (self.timerSource) { + dispatch_source_cancel(self.timerSource); + } + if (self.isDisplayed && !self.isAnimating) { + + // Dismisses. + [[[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView] hideAlertView:forceful completionHandler:^(BOOL finished) { + + self.displayed = NO; + if (andFinish) { + [self markAsFinished]; + } + }]; + } +} + +- (void)pause { + + if (!self.paused) { + [self willChangeValueForKey:@"isPaused"]; + self.paused = YES; + [self didChangeValueForKey:@"isPaused"]; + } + [self dismissAlertView:!self.topAlertObject.persistent forceful:YES]; +} + +- (void)unpause { + + if (self.paused) { + [self willChangeValueForKey:@"isPaused"]; + self.paused = NO; + [self didChangeValueForKey:@"isPaused"]; + } + if (self.executing) { + [self start]; + } +} + +#pragma mark - Delegate functions + +- (void)topAlertViewBeginAnimation { + self.animating = YES; +} + +- (void)topAlertViewFinishAnimation { + self.animating = NO; +} + +- (void)topAlertCloseButtonPressed { + [self dismissAlertView:YES forceful:YES]; +} + +- (id)copyWithZone:(nullable NSZone *)zone { + MVMCoreTopAlertOperation *copyObject = [[MVMCoreTopAlertOperation alloc] init]; + copyObject.topAlertObject = self.topAlertObject; + copyObject.paused = self.paused; + copyObject.reAddAfterCancel = self.reAddAfterCancel; + copyObject.queuePriority = self.queuePriority; + for (NSOperation *dependency in self.dependencies) { + [copyObject addDependency:dependency]; + } + copyObject.name = self.name; + copyObject.qualityOfService = self.qualityOfService; + return copyObject; +} + +@end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h new file mode 100644 index 00000000..27789712 --- /dev/null +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h @@ -0,0 +1,28 @@ +// +// MVMCoreTopAlertViewProtocol.h +// MVMCore +// +// Created by Pfeil, Scott Robert on 1/2/18. +// Copyright © 2018 myverizon. All rights reserved. +// + +#import +@class MVMCoreTopAlertObject; + +@protocol MVMCoreTopAlertViewProtocol + +@optional + +// Show based on the object +- (void)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id )animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler; + +// Hides +- (void)hideAlertView:(BOOL)forceful completionHandler:(void (^ __nullable)(BOOL finished))completionHandler; + +// Collapses the notification if it has a short top message. Otherwise removes notification. +- (void)collapseNotification; + +/// Updates the existing top alert with the new object +- (void)updateTopAlertWith:(nullable MVMCoreTopAlertObject *)topAlertObject; + +@end From 213e0d2ce0203bd8d4880d72eae8741563b4d8a2 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 29 Oct 2020 11:16:48 -0400 Subject: [PATCH 2/4] Changes for file movement --- MVMCoreUI.xcodeproj/project.pbxproj | 42 +++-- .../Alerts/MVMCoreAlertDelegateProtocol.h | 10 +- MVMCoreUI/Alerts/MVMCoreAlertHandler.h | 4 +- MVMCoreUI/Alerts/MVMCoreAlertHandler.m | 8 +- MVMCoreUI/Alerts/MVMCoreAlertObject.h | 2 +- MVMCoreUI/Alerts/MVMCoreAlertObject.m | 28 +-- MVMCoreUI/Alerts/MVMCoreAlertOperation.h | 4 +- MVMCoreUI/Alerts/MVMCoreAlertOperation.m | 6 +- MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 2 + .../MVMCoreUISplitViewController.m | 5 +- MVMCoreUI/MVMCoreUI.h | 14 ++ MVMCoreUI/OtherHandlers/CoreUIObject.swift | 1 + .../MVMCoreUIActionDelegateProtocol.h | 19 ++ .../OtherHandlers/MVMCoreUIActionHandler.h | 40 +++++ .../OtherHandlers/MVMCoreUIActionHandler.m | 164 ++++++++++++++++++ .../MVMCoreUIDelegateObject.swift | 4 + .../MVMCoreGlobalTopAlertDelegateProtocol.h | 2 +- MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h | 2 +- MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m | 5 +- .../TopAlert/MVMCoreTopAlertViewProtocol.h | 2 +- .../TopAlert/MVMCoreUITopAlertBaseView.h | 2 +- .../TopAlert/MVMCoreUITopAlertBaseView.m | 3 +- .../MVMCoreUITopAlertExpandableView.h | 2 +- .../MVMCoreUITopAlertExpandableView.m | 4 +- .../TopAlert/MVMCoreUITopAlertMainView.h | 2 +- .../TopAlert/MVMCoreUITopAlertMainView.m | 4 +- .../MVMCoreUITopAlertView+Extension.swift | 10 +- MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h | 4 +- MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m | 10 +- MVMCoreUI/Utility/MVMCoreUIConstants.h | 5 + MVMCoreUI/Utility/MVMCoreUIConstants.m | 4 + 31 files changed, 350 insertions(+), 64 deletions(-) create mode 100644 MVMCoreUI/OtherHandlers/MVMCoreUIActionDelegateProtocol.h create mode 100644 MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.h create mode 100644 MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 5ee5ca5b..13ddbef7 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -506,23 +506,26 @@ D2ED27ED254B0CE700A1C293 /* ActionPopupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */; }; D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */; }; D2ED27EF254B0CE700A1C293 /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27EA254B0CE700A1C293 /* AlertModel.swift */; }; - D2ED27FB254B0E0300A1C293 /* MVMCoreAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */; }; + D2ED27FB254B0E0300A1C293 /* MVMCoreAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F3254B0E0200A1C293 /* MVMCoreAlertObject+Swift.swift */; }; D2ED27FD254B0E0300A1C293 /* MVMCoreAlertOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F4254B0E0200A1C293 /* MVMCoreAlertOperation.m */; }; - D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */; }; - D2ED27FF254B0E0300A1C293 /* MVMCoreAlertHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */; }; + D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED27FF254B0E0300A1C293 /* MVMCoreAlertHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2ED2800254B0E0300A1C293 /* MVMCoreAlertHandler+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F7254B0E0200A1C293 /* MVMCoreAlertHandler+Extension.swift */; }; - D2ED2801254B0E0300A1C293 /* MVMCoreAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */; }; + D2ED2801254B0E0300A1C293 /* MVMCoreAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2ED2802254B0E0300A1C293 /* MVMCoreAlertObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F9254B0E0200A1C293 /* MVMCoreAlertObject.m */; }; D2ED2803254B0E0300A1C293 /* MVMCoreAlertHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27FA254B0E0300A1C293 /* MVMCoreAlertHandler.m */; }; - D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */; }; - D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */; }; + D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2ED280E254B0EB800A1C293 /* MVMCoreTopAlertOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */; }; - D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2808254B0EB700A1C293 /* MVMCoreTopAlertViewProtocol.h */; }; - D2ED2810254B0EB800A1C293 /* MVMCoreTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2809254B0EB700A1C293 /* MVMCoreTopAlertDelegateProtocol.h */; }; - D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */; }; + D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2808254B0EB700A1C293 /* MVMCoreTopAlertViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED2810254B0EB800A1C293 /* MVMCoreTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2809254B0EB700A1C293 /* MVMCoreTopAlertDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */; }; - D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */; }; + D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED2818254B115400A1C293 /* MVMCoreUIActionDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2817254B112900A1C293 /* MVMCoreUIActionDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED281D254B119D00A1C293 /* MVMCoreUIActionHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED281B254B119D00A1C293 /* MVMCoreUIActionHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2ED281E254B119D00A1C293 /* MVMCoreUIActionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED281C254B119D00A1C293 /* MVMCoreUIActionHandler.m */; }; 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 */; }; @@ -1058,6 +1061,9 @@ D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertObject.h; sourceTree = ""; }; D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertObject.m; sourceTree = ""; }; D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreGlobalTopAlertDelegateProtocol.h; sourceTree = ""; }; + D2ED2817254B112900A1C293 /* MVMCoreUIActionDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIActionDelegateProtocol.h; sourceTree = ""; }; + D2ED281B254B119D00A1C293 /* MVMCoreUIActionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIActionHandler.h; sourceTree = ""; }; + D2ED281C254B119D00A1C293 /* MVMCoreUIActionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIActionHandler.m; sourceTree = ""; }; D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = ""; }; D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = ""; }; D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = ""; }; @@ -2045,6 +2051,9 @@ D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */, D2092352244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift */, D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */, + D2ED2817254B112900A1C293 /* MVMCoreUIActionDelegateProtocol.h */, + D2ED281B254B119D00A1C293 /* MVMCoreUIActionHandler.h */, + D2ED281C254B119D00A1C293 /* MVMCoreUIActionHandler.m */, ); path = OtherHandlers; sourceTree = ""; @@ -2262,18 +2271,14 @@ 9458C3172406C8FD00930963 /* UIFont+FontWrapping.h in Headers */, D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */, D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */, - D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */, D29DF25921E6A22D003B2FB9 /* MFButtonProtocol.h in Headers */, D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */, - D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */, D29DF2CE21E7C104003B2FB9 /* MFLoadingViewController.h in Headers */, D29DF12A21E6851E003B2FB9 /* MVMCoreUITopAlertView.h in Headers */, - D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */, D29DF27521E79E81003B2FB9 /* MVMCoreUILoggingHandler.h in Headers */, D29DF2B321E7B76D003B2FB9 /* MFLoadingSpinner.h in Headers */, D20492A424329A2800A5EED6 /* MVMCoreUIPagingProtocol.h in Headers */, D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */, - D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */, D29DF17521E69E1F003B2FB9 /* ButtonDelegateProtocol.h in Headers */, D29DF26E21E6AA0B003B2FB9 /* FLAnimatedImage.h in Headers */, D29DF11621E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.h in Headers */, @@ -2281,11 +2286,16 @@ D29DF13121E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.h in Headers */, D29DF2CA21E7BFC8003B2FB9 /* MFSizeThreshold.h in Headers */, D29DF28021E7AA51003B2FB9 /* MVMCoreUIDetailViewProtocol.h in Headers */, - D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.h in Headers */, D29DF2EE21ECEADF003B2FB9 /* MFFonts.h in Headers */, D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */, D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */, + D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */, + D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */, + D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */, + D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */, + D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.h in Headers */, D2ED2801254B0E0300A1C293 /* MVMCoreAlertOperation.h in Headers */, + D2ED2818254B115400A1C293 /* MVMCoreUIActionDelegateProtocol.h in Headers */, D2ED27FB254B0E0300A1C293 /* MVMCoreAlertDelegateProtocol.h in Headers */, D2ED2810254B0EB800A1C293 /* MVMCoreTopAlertDelegateProtocol.h in Headers */, D2ED27FF254B0E0300A1C293 /* MVMCoreAlertHandler.h in Headers */, @@ -2295,6 +2305,7 @@ D29DF2C821E7BFC1003B2FB9 /* MFSizeObject.h in Headers */, D29DF2E121E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h in Headers */, D29DF12921E6851E003B2FB9 /* MVMCoreUITopAlertMainView.h in Headers */, + D2ED281D254B119D00A1C293 /* MVMCoreUIActionHandler.h in Headers */, D29DF12C21E6851E003B2FB9 /* MVMCoreUITopAlertShortView.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2700,6 +2711,7 @@ BB2FB3BD247E7EF200DF73CD /* Tags.swift in Sources */, AA104ADC244734EA004D2810 /* HeadersH1LandingPageHeaderModel.swift in Sources */, BBAA4F03243D8E3B005AAD5F /* RadioBoxes.swift in Sources */, + D2ED281E254B119D00A1C293 /* MVMCoreUIActionHandler.m in Sources */, 323AC96A24C837F000F8E4C4 /* ListThreeColumnBillChangesModel.swift in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, 525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */, diff --git a/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h b/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h index f4f05e5d..1b8d65c1 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h +++ b/MVMCoreUI/Alerts/MVMCoreAlertDelegateProtocol.h @@ -9,6 +9,8 @@ #import @class MVMCoreAlertObject; +@class MVMCoreLoadObject; +@class MVMCoreErrorObject; @protocol MVMCoreAlertDelegateProtocol @@ -24,5 +26,11 @@ - (void)alertPaused:(nonnull UIAlertController *)alertController; - (void)alertUnpaused:(nonnull UIAlertController *)alertController; -@end +/** Get the alert object whose data will be presented. Overwrite this to alter how you want the alert to show. + * @param loadObject The load object. + * @param errorObject An error object if there was an error. + * @return Returns the alert object. + * Details: Gets the alert that will display to the screen. Easier to subclass here to avoid subclassing the displaying logic. */ +- (nullable MVMCoreAlertObject *)alertObjectToShow:(nonnull MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)errorObject; +@end diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.h b/MVMCoreUI/Alerts/MVMCoreAlertHandler.h index bba77410..f3b30efd 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler.h +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.h @@ -9,8 +9,8 @@ #import #import -#import -#import +#import +#import @class MVMCoreAlertObject; @class MVMCoreTopAlertOperation; diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m index dce4056b..4e7be1f7 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m @@ -8,12 +8,12 @@ #import "MVMCoreAlertHandler.h" #import "MVMCoreAlertObject.h" -#import "MVMCoreAlertController.h" +#import #import "MVMCoreAlertOperation.h" #import "MVMCoreTopAlertOperation.h" -#import "MVMCoreJSONConstants.h" -#import "NSDictionary+MFConvenience.h" -#import "NSArray+MFConvenience.h" +#import +#import +#import #import @interface MVMCoreAlertHandler () diff --git a/MVMCoreUI/Alerts/MVMCoreAlertObject.h b/MVMCoreUI/Alerts/MVMCoreAlertObject.h index 161e123a..87c5050a 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertObject.h +++ b/MVMCoreUI/Alerts/MVMCoreAlertObject.h @@ -11,7 +11,7 @@ #import #import #import -#import +#import @class MVMCoreErrorObject; @class MVMCoreLoadObject; diff --git a/MVMCoreUI/Alerts/MVMCoreAlertObject.m b/MVMCoreUI/Alerts/MVMCoreAlertObject.m index c8deb7a6..975c9540 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertObject.m +++ b/MVMCoreUI/Alerts/MVMCoreAlertObject.m @@ -9,16 +9,17 @@ #import "MVMCoreAlertObject.h" #import "MVMCoreAlertHandler.h" #import "MVMCoreTopAlertObject.h" -#import "MVMCoreCache.h" -#import "MVMCoreErrorConstants.h" -#import "MVMCoreErrorObject.h" -#import "MVMCoreLoadObject.h" -#import "MVMCoreGetterUtility.h" -#import "NSDictionary+MFConvenience.h" -#import "MVMCoreHardcodedStringsConstants.h" -#import "MVMCoreJSONConstants.h" +#import +#import +#import +#import +#import +#import +#import +#import #import #import +#import @interface MVMCoreAlertObject () @@ -47,6 +48,10 @@ } + (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + MVMCoreUIDelegateObject *alertDelegateObject = nil; + if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) { + alertDelegateObject = (MVMCoreUIDelegateObject *)delegateObject; + } __block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init]; alert.title = [responseInfo stringForKey:KeyErrorHeading]; @@ -64,7 +69,7 @@ if ([messageStyle isEqualToString:ValueMessageStyleTopPersistent] || [messageStyle isEqualToString:ValueMessageStyleTop]) { alert.topAlertObject = [[MVMCoreTopAlertObject alloc] initWithResponseInfo:responseInfo]; - alert.topAlertObject.delegate = delegateObject.topAlertDelegate; + alert.topAlertObject.delegate = alertDelegateObject.topAlertDelegate; alert.topAlertObject.pageType = pageType; alert.type = MFAlertTypeTop; } else if ([messageStyle isEqualToString:ValueMessageStylePopup]) { @@ -100,7 +105,7 @@ alert.alertStyle = UIAlertControllerStyleAlert; } } - alert.alertDelegate = delegateObject.alertDelegate; + alert.alertDelegate = alertDelegateObject.alertDelegate; return alert; } @@ -166,7 +171,8 @@ return alert; } else { if (error) { - *error = [[MVMCoreErrorObject alloc] initWithTitle:nil messageToLog:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodePopupFailed domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_Popup_pageType:%@",NSStringFromClass([delegateObject.alertDelegate class]),[page stringForKey:KeyPageType]]]; + id delegate = [delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]] ? ((MVMCoreUIDelegateObject *)delegateObject).alertDelegate : nil; + *error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodePopupFailed domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_Popup_pageType:%@",NSStringFromClass([delegate class]),[page stringForKey:KeyPageType]]]; } return nil; } diff --git a/MVMCoreUI/Alerts/MVMCoreAlertOperation.h b/MVMCoreUI/Alerts/MVMCoreAlertOperation.h index c48fd867..a8031e5e 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertOperation.h +++ b/MVMCoreUI/Alerts/MVMCoreAlertOperation.h @@ -9,8 +9,8 @@ #import #import -#import "MVMCoreOperation.h" -#import "MVMCoreAlertDelegateProtocol.h" +#import +#import @interface MVMCoreAlertOperation : MVMCoreOperation diff --git a/MVMCoreUI/Alerts/MVMCoreAlertOperation.m b/MVMCoreUI/Alerts/MVMCoreAlertOperation.m index 5aa9058b..c96ebe57 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertOperation.m +++ b/MVMCoreUI/Alerts/MVMCoreAlertOperation.m @@ -7,9 +7,9 @@ // #import "MVMCoreAlertOperation.h" -#import "MVMCoreAlertHandler.h" -#import "MVMCoreAlertController.h" -#import "MVMCoreNavigationHandler.h" +#import +#import +#import @interface MVMCoreAlertOperation () { __block BOOL _paused; diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 8a5b737a..fbd5f742 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -251,6 +251,8 @@ import Foundation try? ModelRegistry.register(RuleRegexModel.self) // MARK:- Actions + try? ModelRegistry.register(ActionPopupModel.self) + try? ModelRegistry.register(ActionAlertModel.self) try? ModelRegistry.register(ActionTopAlertModel.self) try? ModelRegistry.register(ActionCollapseNotificationModel.self) try? ModelRegistry.register(ActionOpenPanelModel.self) diff --git a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m index 72152c40..7377701b 100644 --- a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m +++ b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m @@ -10,7 +10,6 @@ @import MVMCore.MVMCoreNavigationHandler; @import MVMCore.MVMCoreDispatchUtility; @import MVMCore.MVMCoreViewManagerProtocol; -@import MVMCore.MVMCoreObject; @import MVMCore.MVMCoreActionUtility; @import MVMCore.NSDictionary_MFConvenience; #import "MVMCoreUIUtility.h" @@ -847,8 +846,8 @@ CGFloat const PanelAnimationDuration = 0.2; // Top Alert MVMCoreUITopAlertView *topAlertView = nil; - if ([[MVMCoreObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { - topAlertView = (MVMCoreUITopAlertView *)[[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView]; + if ([[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { + topAlertView = (MVMCoreUITopAlertView *)[[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView]; if (topAlertView) { self.topAlertView = topAlertView; [self.view addSubview:topAlertView]; diff --git a/MVMCoreUI/MVMCoreUI.h b/MVMCoreUI/MVMCoreUI.h index 278f8a49..ce663709 100644 --- a/MVMCoreUI/MVMCoreUI.h +++ b/MVMCoreUI/MVMCoreUI.h @@ -20,8 +20,22 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[]; #import #import #import +#import +#import + +// Alert Handling +#import +#import +#import +#import #pragma mark - TopAlert +#import +#import +#import +#import +#import +#import #import #import #import diff --git a/MVMCoreUI/OtherHandlers/CoreUIObject.swift b/MVMCoreUI/OtherHandlers/CoreUIObject.swift index 3553b54b..3a4d2cbc 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIObject.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIObject.swift @@ -10,6 +10,7 @@ import UIKit @objcMembers open class CoreUIObject: MVMCoreObject { public var moleculeMap: MoleculeObjectMapping? + public var globalTopAlertDelegate: MVMCoreGlobalTopAlertDelegateProtocol? open override func defaultInitialSetup() { cache = MVMCoreCache() diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIActionDelegateProtocol.h b/MVMCoreUI/OtherHandlers/MVMCoreUIActionDelegateProtocol.h new file mode 100644 index 00000000..5659db85 --- /dev/null +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIActionDelegateProtocol.h @@ -0,0 +1,19 @@ +// +// MVMCoreUIActionDelegateProtocol.h +// MVMCoreUI +// +// Created by Scott Pfeil on 10/28/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// +#import +@class MVMCoreAlertObject; + +@protocol MVMCoreUIActionDelegateProtocol + +// Gives the delegate a chance to alter the alert object +- (void)willShowPopupWithAlertObject:(nonnull MVMCoreAlertObject *)alertObject alertJson:(nonnull NSDictionary *)alertJson; + +// Gives the delegate a chance to alter the alert object +- (nullable MVMCoreAlertObject *)willShowTopAlertWithAlertObject:(nonnull MVMCoreAlertObject *)alertObject alertJson:(nonnull NSDictionary *)alertJson; + +@end diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.h b/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.h new file mode 100644 index 00000000..3835207b --- /dev/null +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.h @@ -0,0 +1,40 @@ +// +// MVMCoreUIActionHandler.h +// MVMCoreUI +// +// Created by Scott Pfeil on 10/28/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MVMCoreUIActionHandler : MVMCoreActionHandler + +// Shows a popup alert by grabbing the content from the page map. +- (void)popupAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject; + +// Shows popup alert from the alert object in the action map. The actionType of the action is 'alert' +- (void)showAlert:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject; + +// Shows a top alert +- (void)topAlertAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject; + +// Collapses the current top notification +- (void)collapseNotificationAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject; + +#pragma mark - Deprecated + +// Shows a popup +- (void)popupAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate __deprecated; + +// Shows a top alert +- (void)topAlertAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate __deprecated; + +// Collapses the current top notification +- (void)collapseNotificationAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate __deprecated; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m b/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m new file mode 100644 index 00000000..eaf7d821 --- /dev/null +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m @@ -0,0 +1,164 @@ +// +// MVMCoreUIActionHandler.m +// MVMCoreUI +// +// Created by Scott Pfeil on 10/28/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +#import "MVMCoreUIActionHandler.h" +#import "MVMCoreUIConstants.h" +#import "MVMCoreAlertObject.h" +#import +#import +@import MVMCore.MVMCoreActionHandler; +@import MVMCore.NSDictionary_MFConvenience; +@import MVMCore.MVMCoreJSONConstants; +@import MVMCore.MVMCoreCache; + +@implementation MVMCoreUIActionHandler + +- (BOOL)handleOtherActions:(NSString *)actionType actionInformation:(NSDictionary *)actionInformation additionalData:(NSDictionary *)additionalData delegateObject:(DelegateObject *)delegateObject { + if ([actionType isEqualToString:KeyActionTypePopup]) { + [self popupAction:actionInformation additionalData:additionalData delegateObject:delegateObject]; + return YES; + } else if ([actionType isEqualToString:KeyActionTypeTopAlert]) { + [self topAlertAction:actionInformation additionalData:additionalData delegateObject:delegateObject]; + return YES; + } else if ([actionType isEqualToString:KeyActionTypeCollapseNotification]) { + [self collapseNotificationAction:actionInformation additionalData:additionalData delegateObject:delegateObject]; + return YES; + } else if ([actionType isEqualToString:KeyActionTypeAlert]) { + [self showAlert:actionInformation additionalData:additionalData delegateObject:delegateObject]; + return YES; + } + return NO; +} + +- (void)popupAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + // Perform a popup. + NSString *pageTypeForPopup = [actionInformation stringForKey:KeyPageType]; + [[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForPopup queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) { + + MVMCoreErrorObject *error = nil; + MVMCoreAlertObject *alertObject = [MVMCoreAlertObject alertObjectWithPage:jsonDictionary isGreedy:NO additionalData:additionalData delegateObject:delegateObject error:&error]; + if ([delegateObject.actionDelegate respondsToSelector:@selector(willShowPopupWithAlertObject:alertJson:)]) { + [((id )delegateObject.actionDelegate) willShowPopupWithAlertObject:alertObject alertJson:jsonDictionary]; + } + + if (alertObject) { + [[MVMCoreAlertHandler sharedAlertHandler] showAlertWithAlertObject:alertObject]; + } else { + [self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject ]; + } + }]; +} + +- (void)showAlert:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + + MVMCoreErrorObject *error = nil; + MVMCoreAlertObject *alertObject = [MVMCoreAlertObject alertObjectWithAction:actionInformation additionalData:additionalData delegateObject:delegateObject error:&error]; + if ([delegateObject.actionDelegate respondsToSelector:@selector(willShowPopupWithAlertObject:alertJson:)]) { + [((id )delegateObject.actionDelegate) willShowPopupWithAlertObject:alertObject alertJson:actionInformation]; + } + + if (alertObject) { + [[MVMCoreAlertHandler sharedAlertHandler] showAlertWithAlertObject:alertObject]; + } else { + [self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject]; + } +} + +- (void)topAlertAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + // Perform a top alert. + NSString *pageTypeForTopAlert = [actionInformation stringForKey:KeyPageType]; + [[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForTopAlert queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) { + + NSDictionary *responseInfo = [jsonDictionary dict:KeyResponseInfo]; + if (responseInfo) { + MVMCoreAlertObject *alertObject = [MVMCoreAlertObject alertObjectForPageType:pageTypeForTopAlert responseInfo:responseInfo additionalData:additionalData delegateObject:delegateObject]; + if ([delegateObject.actionDelegate respondsToSelector:@selector(willShowTopAlertWithAlertObject:alertJson:)]) { + [((id )delegateObject.actionDelegate) willShowTopAlertWithAlertObject:alertObject alertJson:actionInformation]; + } + [alertObject showAlert]; + } + }]; +} + +- (void)collapseNotificationAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject { + // Collapse the current notification. + if ([[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { + [[[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView] collapseNotification]; + } +} + ++ (void)defaultHandleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData { + [super defaultHandleActionError:error additionalData:additionalData]; + if (!error.silentError) { + + // Show alert + [MVMCoreDispatchUtility performBlockOnMainThread:^{ + MVMCoreAlertObject *alertObject = [[MVMCoreAlertObject alloc] initPopupAlertWithError:error isGreedy:NO]; + [[MVMCoreAlertHandler sharedAlertHandler] showAlertWithAlertObject:alertObject]; + }]; + } +} + +#pragma mark - Deprecated + +- (BOOL)handleOtherActions:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { + if ([actionType isEqualToString:KeyActionTypePopup]) { + [self popupAction:actionInformation additionalData:additionalData delegate:delegate]; + } else if ([actionType isEqualToString:KeyActionTypeTopAlert]) { + [self topAlertAction:actionInformation additionalData:additionalData delegate:delegate]; + return YES; + } else if ([actionType isEqualToString:KeyActionTypeCollapseNotification]) { + [self collapseNotificationAction:actionInformation additionalData:additionalData delegate:delegate]; + return YES; + } + return NO; +} + +- (void)popupAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { + // Perform a popup. + NSString *pageTypeForPopup = [actionInformation stringForKey:KeyPageType]; + [[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForPopup queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) { + + MVMCoreErrorObject *error = nil; + MVMCoreAlertObject *alertObject = [MVMCoreAlertObject alertObjectWithPage:jsonDictionary isGreedy:NO additionalData:additionalData delegate:delegate error:&error]; + if ([delegate respondsToSelector:@selector(willShowPopupWithAlertObject:alertJson:)]) { + [((id )delegate) willShowPopupWithAlertObject:alertObject alertJson:jsonDictionary]; + } + + if (alertObject) { + [[MVMCoreAlertHandler sharedAlertHandler] showAlertWithAlertObject:alertObject]; + } else { + [self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegate:delegate]; + } + }]; +} + +- (void)topAlertAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { + // Perform a top alert. + NSString *pageTypeForTopAlert = [actionInformation stringForKey:KeyPageType]; + [[MVMCoreCache sharedCache] fetchJSONForPageType:pageTypeForTopAlert queue:nil waitUntilFinished:YES completionHandler:^(NSDictionary * _Nullable jsonDictionary) { + + NSDictionary *responseInfo = [jsonDictionary dict:KeyResponseInfo]; + if (responseInfo) { + MVMCoreAlertObject *alertObject = [MVMCoreAlertObject alertObjectForPageType:pageTypeForTopAlert responseInfo:responseInfo additionalData:additionalData actionDelegate:delegate]; + if ([delegate respondsToSelector:@selector(willShowTopAlertWithAlertObject:alertJson:)]) { + alertObject = [((id )delegate) willShowTopAlertWithAlertObject:alertObject alertJson:jsonDictionary]; + } + [alertObject showAlert]; + } + }]; +} + +- (void)collapseNotificationAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject *)delegate { + // Collapse the current notification. + if ([[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { + [[[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView] collapseNotification]; + } +} + +@end diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift index c63c4a87..b4ea0cd7 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift @@ -17,6 +17,8 @@ open class MVMCoreUIDelegateObject: DelegateObject { public weak var uiTextViewDelegate: UITextViewDelegate? public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? public weak var moleculeDelegate: MoleculeDelegateProtocol? + public weak var alertDelegate: (MVMCoreAlertDelegateProtocol & NSObjectProtocol)? + public weak var topAlertDelegate: (MVMCoreTopAlertDelegateProtocol & NSObjectProtocol)? open override func setAll(withDelegate delegate: Any) { super.setAll(withDelegate: delegate) @@ -26,6 +28,8 @@ open class MVMCoreUIDelegateObject: DelegateObject { uiTextViewDelegate = delegate as? UITextViewDelegate observingTextFieldDelegate = delegate as? ObservingTextFieldDelegate moleculeDelegate = delegate as? MoleculeDelegateProtocol + alertDelegate = delegate as? (MVMCoreAlertDelegateProtocol & NSObjectProtocol) + topAlertDelegate = delegate as? (MVMCoreTopAlertDelegateProtocol & NSObjectProtocol) } class func delegateObject(from controller: MVMCoreViewControllerProtocol?) -> MVMCoreUIDelegateObject? { diff --git a/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h b/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h index 5ee82e70..ff35c5e9 100644 --- a/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h +++ b/MVMCoreUI/TopAlert/MVMCoreGlobalTopAlertDelegateProtocol.h @@ -7,7 +7,7 @@ // #import -#import +#import @class MVMCoreTopAlertObject; @protocol MVMCoreGlobalTopAlertDelegateProtocol diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h index 350f6e19..c222747a 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.h @@ -7,7 +7,7 @@ // #import -#import +#import extern NSUInteger const TopAlertDismissTime; diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m index 72b6de4d..141f4cf8 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertObject.m @@ -8,10 +8,9 @@ #import "MVMCoreTopAlertObject.h" #import -#import "MVMCoreGetterUtility.h" +#import +#import #import "MVMCoreAlertHandler.h" -#import "MVMCoreJSONConstants.h" - NSUInteger const TopAlertDismissTime = 5; diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h index 27789712..e10cec10 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertViewProtocol.h @@ -6,7 +6,7 @@ // Copyright © 2018 myverizon. All rights reserved. // -#import +#import @class MVMCoreTopAlertObject; @protocol MVMCoreTopAlertViewProtocol diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.h index c4053d30..f8c3d7f5 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.h @@ -7,7 +7,7 @@ // #import -#import +#import #import @class Button; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.m index f2401757..11d10ff0 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertBaseView.m @@ -19,8 +19,7 @@ #import "MFStyler.h" #import "MVMCoreUISession.h" #import - -@import MVMCore.MVMCoreTopAlertDelegateProtocol; +#import "MVMCoreTopAlertDelegateProtocol.h" @implementation MVMCoreUITopAlertBaseView diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h index 04d41363..7a5519b3 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.h @@ -8,7 +8,7 @@ #import #import -#import +#import @class PrimaryButton; @class MVMCoreUITopAlertShortView; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m index 76ddb1ed..55468c95 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m @@ -10,8 +10,8 @@ #import "MVMCoreUITopAlertShortView.h" #import "MVMCoreUITopAlertMainView.h" #import -#import -#import +#import +#import #import #import #import "MFStyler.h" diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h index b08ca00b..618730bc 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.h @@ -8,7 +8,7 @@ #import #import -#import +#import @class PillButton; @class MVMCoreTopAlertObject; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m index c817059d..44f248f3 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertMainView.m @@ -11,9 +11,9 @@ #import "NSLayoutConstraint+MFConvenience.h" #import #import -#import +#import #import "UIColor+MFConvenience.h" -#import +#import #import #import #import "MVMCoreUICommonViewsUtility.h" diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift index 58a06420..9bceb57a 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView+Extension.swift @@ -28,7 +28,15 @@ public extension MVMCoreUITopAlertView { /// Checks for new top alert json @objc private func responseJSONUpdated(notification: Notification) { - guard let responseJSON = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON, + guard let loadObject = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject) else { return } + + // Dismiss any top alerts that server wants us to dismiss/ + if let disableType = loadObject.responseInfoMap?.optionalStringForKey("disableType") { + MVMCoreAlertHandler.shared()?.hidePersistentTopAlertView(ofType: disableType) + } + + // Show any new top alert. + guard let responseJSON = loadObject.responseJSON, let json = responseJSON.optionalDictionaryForKey("TopNotification"), let model = decodeTopNotification(with: json, delegateObject: getDelegateObject()) else { return } showTopAlert(with: model) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h index 1979a850..5bb033d7 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.h @@ -7,12 +7,12 @@ // #import -@import MVMCore.MVMCoreTopAlertAnimationDelegateProtocol; @import MVMCore.MVMCoreLoadDelegateProtocol; @import MVMCore.MVMCoreActionDelegateProtocol; @import MVMCore.MVMCorePresentationDelegateProtocol; -@import MVMCore.MVMCoreTopAlertViewProtocol; @import MVMCore.MVMCoreViewProtocol; +#import +#import #import @class MVMCoreTopAlertObject; diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m index 14f4dee2..4ac5aaa0 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m @@ -17,13 +17,13 @@ #import "MVMCoreUISession.h" #import "MVMCoreUIUtility.h" #import -@import MVMCore.MVMCoreTopAlertObject; +#import @import MVMCore.MVMCoreLoadHandler; @import MVMCore.MVMCoreNavigationHandler; @import MVMCore.MVMCoreBlockOperation; -@import MVMCore.MVMCoreAlertObject; +#import @import MVMCore.MVMCoreActionHandler; -@import MVMCore.MVMCoreAlertHandler; +#import @import MVMCore.NSDictionary_MFConvenience; @import MVMCore.MVMCoreRequestParameters; @import MVMCore.MVMCoreJSONConstants; @@ -274,7 +274,9 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed."; [weakSelf.topAlertObject.delegate topAlertViewDismissed:view]; } [operation markAsFinished]; - completionHandler(finished); + if (completionHandler) { + completionHandler(finished); + } weakSelf.topAlertObject = nil; [MVMCoreDispatchUtility performBlockOnMainThread:^{ [weakSelf setStatusBarColor:[UIColor whiteColor] statusBarStyle:UIStatusBarStyleDefault]; diff --git a/MVMCoreUI/Utility/MVMCoreUIConstants.h b/MVMCoreUI/Utility/MVMCoreUIConstants.h index 684d6044..ddd93d44 100644 --- a/MVMCoreUI/Utility/MVMCoreUIConstants.h +++ b/MVMCoreUI/Utility/MVMCoreUIConstants.h @@ -44,6 +44,11 @@ extern NSString * const KeyFieldKey; extern NSString * const KeyRequired; extern NSString * const KeySourceModel; +extern NSString * const KeyActionTypePopup; +extern NSString * const KeyActionTypeAlert; +extern NSString * const KeyActionTypeTopAlert; +extern NSString * const KeyActionTypeCollapseNotification; + #pragma mark - Values extern NSString * const StringY; diff --git a/MVMCoreUI/Utility/MVMCoreUIConstants.m b/MVMCoreUI/Utility/MVMCoreUIConstants.m index e4954b01..a2b352fb 100644 --- a/MVMCoreUI/Utility/MVMCoreUIConstants.m +++ b/MVMCoreUI/Utility/MVMCoreUIConstants.m @@ -42,6 +42,10 @@ NSString * const KeyIsHidden = @"isHidden"; NSString * const KeyIsOpaque = @"isOpaque"; NSString * const KeySourceModel = @"sourceModel"; +NSString * const KeyActionTypePopup = @"popup"; +NSString * const KeyActionTypeAlert = @"alert"; +NSString * const KeyActionTypeTopAlert = @"topAlert"; +NSString * const KeyActionTypeCollapseNotification = @"collapseNotification"; #pragma mark - Values From dc11171a9829f2fb93bd3449de2d597f9af7ef80 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 29 Oct 2020 11:27:55 -0400 Subject: [PATCH 3/4] file updates --- MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h | 4 ++-- MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h index 6dadc898..73acec1e 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h @@ -6,8 +6,8 @@ // Copyright © 2016 Verizon Wireless. All rights reserved. // -#import "MVMCoreOperation.h" -#import "MVMCoreTopAlertAnimationDelegateProtocol.h" +#import +#import @class MVMCoreTopAlertObject; diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m index 6eb8f045..bcf9515a 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m @@ -9,8 +9,7 @@ #import "MVMCoreTopAlertOperation.h" #import "MVMCoreTopAlertObject.h" #import "MVMCoreAlertHandler.h" -#import "MVMCoreObject.h" -#import "MVMCoreSessionObject.h" +#import @interface MVMCoreTopAlertOperation () { __block BOOL _paused; @@ -50,17 +49,17 @@ self.topAlertObject = topAlertObject; // Sets the queue priority for various types of alerts. - self.queuePriority = [[MVMCoreObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; + self.queuePriority = [[CoreUIObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; } return self; } - (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject { self.topAlertObject = topAlertObject; - self.queuePriority = [[MVMCoreObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; + self.queuePriority = [[CoreUIObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject]; if (self.isExecuting && !self.isCancelled && !self.isPaused) { [self updateDismissTimer]; - UIView *topAlertView = [[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView]; + UIView *topAlertView = [[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView]; if ([topAlertView respondsToSelector:@selector(updateTopAlertWith:)]) { [topAlertView updateTopAlertWith:topAlertObject]; } @@ -123,12 +122,12 @@ if (![[MVMCoreAlertHandler sharedAlertHandler] mfAlertsSupressed]) { // Show - if (![[MVMCoreObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { + if (![[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) { // Needs to be a top alert view.... [self markAsFinished]; } else { - UIView *topAlertView = [[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView]; + UIView *topAlertView = [[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView]; [topAlertView showWithTopAlertObject:self.topAlertObject animationDelegate:self completionHandler:^(BOOL finished) { self.displayed = YES; @@ -201,7 +200,7 @@ if (self.isDisplayed && !self.isAnimating) { // Dismisses. - [[[MVMCoreObject sharedInstance].globalTopAlertDelegate getTopAlertView] hideAlertView:forceful completionHandler:^(BOOL finished) { + [[[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView] hideAlertView:forceful completionHandler:^(BOOL finished) { self.displayed = NO; if (andFinish) { From 8cb69bb1bfb96d25b31e6aff727fdfe4ea073df7 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 30 Oct 2020 10:56:32 -0400 Subject: [PATCH 4/4] review changes --- MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m b/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m index eaf7d821..ad19f862 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIActionHandler.m @@ -92,7 +92,7 @@ } } -+ (void)defaultHandleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData { +- (void)defaultHandleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData { [super defaultHandleActionError:error additionalData:additionalData]; if (!error.silentError) {