Merge branch 'develop' into feature/account_settings_push_enablement
This commit is contained in:
commit
6dfbea79dd
@ -280,7 +280,6 @@
|
|||||||
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */; };
|
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */; };
|
||||||
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */; };
|
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */; };
|
||||||
AF1C33652883B5A4006B1001 /* ActionTopNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33642883B5A4006B1001 /* ActionTopNotificationHandler.swift */; };
|
AF1C33652883B5A4006B1001 /* ActionTopNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33642883B5A4006B1001 /* ActionTopNotificationHandler.swift */; };
|
||||||
AF1C33672883B712006B1001 /* ActionPopupHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33662883B712006B1001 /* ActionPopupHandler.swift */; };
|
|
||||||
AF1C336928859778006B1001 /* ActionAlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336828859778006B1001 /* ActionAlertHandler.swift */; };
|
AF1C336928859778006B1001 /* ActionAlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336828859778006B1001 /* ActionAlertHandler.swift */; };
|
||||||
AF1C336B28859C73006B1001 /* ActionTopAlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336A28859C73006B1001 /* ActionTopAlertHandler.swift */; };
|
AF1C336B28859C73006B1001 /* ActionTopAlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336A28859C73006B1001 /* ActionTopAlertHandler.swift */; };
|
||||||
AF1C336D28859EE1006B1001 /* ActionOpenPanelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336C28859EE1006B1001 /* ActionOpenPanelHandler.swift */; };
|
AF1C336D28859EE1006B1001 /* ActionOpenPanelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336C28859EE1006B1001 /* ActionOpenPanelHandler.swift */; };
|
||||||
@ -289,6 +288,12 @@
|
|||||||
AF1C33732885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */; };
|
AF1C33732885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */; };
|
||||||
AF60A7F62892D2E300919EEB /* ActionDismissNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */; };
|
AF60A7F62892D2E300919EEB /* ActionDismissNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */; };
|
||||||
AF60A7F82892D34D00919EEB /* ActionDismissNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */; };
|
AF60A7F82892D34D00919EEB /* ActionDismissNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */; };
|
||||||
|
AF7E509829E477C1009DC2AD /* AlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E509629E477C0009DC2AD /* AlertHandler.swift */; };
|
||||||
|
AF7E509929E477C1009DC2AD /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E509729E477C0009DC2AD /* AlertController.swift */; };
|
||||||
|
AFA4932029E5CA73001A9663 /* AlertOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4931F29E5CA73001A9663 /* AlertOperation.swift */; };
|
||||||
|
AFA4932229E5EF2E001A9663 /* TopNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4932129E5EF2E001A9663 /* TopNotificationHandler.swift */; };
|
||||||
|
AFA4933F29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */; };
|
||||||
|
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4935629EE3DCC001A9663 /* AlertDelegateProtocol.swift */; };
|
||||||
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */; };
|
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */; };
|
||||||
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
|
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
|
||||||
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */; };
|
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */; };
|
||||||
@ -558,18 +563,9 @@
|
|||||||
D2EC7BDD2527B83700F540AF /* SectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.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 */; };
|
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 */; };
|
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 */; };
|
D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */; };
|
||||||
D2ED27EF254B0CE700A1C293 /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27EA254B0CE700A1C293 /* AlertModel.swift */; };
|
D2ED27EF254B0CE700A1C293 /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27EA254B0CE700A1C293 /* AlertModel.swift */; };
|
||||||
D2ED27FB254B0E0300A1C293 /* MVMCoreAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D2ED27FC254B0E0300A1C293 /* AlertObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F3254B0E0200A1C293 /* AlertObject.swift */; };
|
||||||
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 */; 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 */; 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 */; settings = {ATTRIBUTES = (Public, ); }; };
|
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, ); }; };
|
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 */; };
|
D2ED280E254B0EB800A1C293 /* MVMCoreTopAlertOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */; };
|
||||||
@ -578,7 +574,6 @@
|
|||||||
D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.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 */; };
|
D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */; };
|
||||||
D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
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, ); }; };
|
|
||||||
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
|
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
|
||||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
|
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
|
||||||
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
|
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
|
||||||
@ -892,7 +887,6 @@
|
|||||||
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocatorModel.swift; sourceTree = "<group>"; };
|
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocatorModel.swift; sourceTree = "<group>"; };
|
||||||
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocator.swift; sourceTree = "<group>"; };
|
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocator.swift; sourceTree = "<group>"; };
|
||||||
AF1C33642883B5A4006B1001 /* ActionTopNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTopNotificationHandler.swift; sourceTree = "<group>"; };
|
AF1C33642883B5A4006B1001 /* ActionTopNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTopNotificationHandler.swift; sourceTree = "<group>"; };
|
||||||
AF1C33662883B712006B1001 /* ActionPopupHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionPopupHandler.swift; sourceTree = "<group>"; };
|
|
||||||
AF1C336828859778006B1001 /* ActionAlertHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionAlertHandler.swift; sourceTree = "<group>"; };
|
AF1C336828859778006B1001 /* ActionAlertHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionAlertHandler.swift; sourceTree = "<group>"; };
|
||||||
AF1C336A28859C73006B1001 /* ActionTopAlertHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTopAlertHandler.swift; sourceTree = "<group>"; };
|
AF1C336A28859C73006B1001 /* ActionTopAlertHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTopAlertHandler.swift; sourceTree = "<group>"; };
|
||||||
AF1C336C28859EE1006B1001 /* ActionOpenPanelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelHandler.swift; sourceTree = "<group>"; };
|
AF1C336C28859EE1006B1001 /* ActionOpenPanelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelHandler.swift; sourceTree = "<group>"; };
|
||||||
@ -901,6 +895,12 @@
|
|||||||
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionOpenPageHandler.swift; sourceTree = "<group>"; };
|
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionOpenPageHandler.swift; sourceTree = "<group>"; };
|
||||||
AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationModel.swift; sourceTree = "<group>"; };
|
AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationModel.swift; sourceTree = "<group>"; };
|
||||||
AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationHandler.swift; sourceTree = "<group>"; };
|
AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationHandler.swift; sourceTree = "<group>"; };
|
||||||
|
AF7E509629E477C0009DC2AD /* AlertHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertHandler.swift; sourceTree = "<group>"; };
|
||||||
|
AF7E509729E477C0009DC2AD /* AlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertController.swift; sourceTree = "<group>"; };
|
||||||
|
AFA4931F29E5CA73001A9663 /* AlertOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertOperation.swift; sourceTree = "<group>"; };
|
||||||
|
AFA4932129E5EF2E001A9663 /* TopNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationHandler.swift; sourceTree = "<group>"; };
|
||||||
|
AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUILoggingDelegateProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
AFA4935629EE3DCC001A9663 /* AlertDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertDelegateProtocol.swift; sourceTree = "<group>"; };
|
||||||
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSColorTokens.xcframework; path = ../SharedFrameworks/VDSColorTokens.xcframework; sourceTree = "<group>"; };
|
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSColorTokens.xcframework; path = ../SharedFrameworks/VDSColorTokens.xcframework; sourceTree = "<group>"; };
|
||||||
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
|
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
|
||||||
BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionViewLeftAlignedLayout.swift; sourceTree = "<group>"; };
|
BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionViewLeftAlignedLayout.swift; sourceTree = "<group>"; };
|
||||||
@ -1171,18 +1171,9 @@
|
|||||||
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = "<group>"; };
|
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = "<group>"; };
|
||||||
D2ED27E6254B0CE600A1C293 /* UIAlertActionStyle+Codable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertActionStyle+Codable.swift"; sourceTree = "<group>"; };
|
D2ED27E6254B0CE600A1C293 /* UIAlertActionStyle+Codable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertActionStyle+Codable.swift"; sourceTree = "<group>"; };
|
||||||
D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertControllerStyle+Extension.swift"; sourceTree = "<group>"; };
|
D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertControllerStyle+Extension.swift"; sourceTree = "<group>"; };
|
||||||
D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionPopupModel.swift; sourceTree = "<group>"; };
|
|
||||||
D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionAlertModel.swift; sourceTree = "<group>"; };
|
D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionAlertModel.swift; sourceTree = "<group>"; };
|
||||||
D2ED27EA254B0CE700A1C293 /* AlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = "<group>"; };
|
D2ED27EA254B0CE700A1C293 /* AlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = "<group>"; };
|
||||||
D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertDelegateProtocol.h; sourceTree = "<group>"; };
|
D2ED27F3254B0E0200A1C293 /* AlertObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertObject.swift; sourceTree = "<group>"; };
|
||||||
D2ED27F3254B0E0200A1C293 /* MVMCoreAlertObject+Swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MVMCoreAlertObject+Swift.swift"; sourceTree = "<group>"; };
|
|
||||||
D2ED27F4254B0E0200A1C293 /* MVMCoreAlertOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertOperation.m; sourceTree = "<group>"; };
|
|
||||||
D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertObject.h; sourceTree = "<group>"; };
|
|
||||||
D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertHandler.h; sourceTree = "<group>"; };
|
|
||||||
D2ED27F7254B0E0200A1C293 /* MVMCoreAlertHandler+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MVMCoreAlertHandler+Extension.swift"; sourceTree = "<group>"; };
|
|
||||||
D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertOperation.h; sourceTree = "<group>"; };
|
|
||||||
D2ED27F9254B0E0200A1C293 /* MVMCoreAlertObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertObject.m; sourceTree = "<group>"; };
|
|
||||||
D2ED27FA254B0E0300A1C293 /* MVMCoreAlertHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertHandler.m; sourceTree = "<group>"; };
|
|
||||||
D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertAnimationDelegateProtocol.h; sourceTree = "<group>"; };
|
D2ED2805254B0EB700A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertAnimationDelegateProtocol.h; sourceTree = "<group>"; };
|
||||||
D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertOperation.h; sourceTree = "<group>"; };
|
D2ED2806254B0EB700A1C293 /* MVMCoreTopAlertOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertOperation.h; sourceTree = "<group>"; };
|
||||||
D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertOperation.m; sourceTree = "<group>"; };
|
D2ED2807254B0EB700A1C293 /* MVMCoreTopAlertOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertOperation.m; sourceTree = "<group>"; };
|
||||||
@ -1191,7 +1182,6 @@
|
|||||||
D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertObject.h; sourceTree = "<group>"; };
|
D2ED280A254B0EB700A1C293 /* MVMCoreTopAlertObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertObject.h; sourceTree = "<group>"; };
|
||||||
D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertObject.m; sourceTree = "<group>"; };
|
D2ED280B254B0EB800A1C293 /* MVMCoreTopAlertObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreTopAlertObject.m; sourceTree = "<group>"; };
|
||||||
D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreGlobalTopAlertDelegateProtocol.h; sourceTree = "<group>"; };
|
D2ED2814254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreGlobalTopAlertDelegateProtocol.h; sourceTree = "<group>"; };
|
||||||
D2ED2817254B112900A1C293 /* MVMCoreUIActionDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIActionDelegateProtocol.h; sourceTree = "<group>"; };
|
|
||||||
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
|
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
|
||||||
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
|
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
|
||||||
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
|
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
|
||||||
@ -1532,8 +1522,6 @@
|
|||||||
D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */,
|
D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */,
|
||||||
D2ED27EA254B0CE700A1C293 /* AlertModel.swift */,
|
D2ED27EA254B0CE700A1C293 /* AlertModel.swift */,
|
||||||
AF1C336828859778006B1001 /* ActionAlertHandler.swift */,
|
AF1C336828859778006B1001 /* ActionAlertHandler.swift */,
|
||||||
D2ED27E8254B0CE600A1C293 /* ActionPopupModel.swift */,
|
|
||||||
AF1C33662883B712006B1001 /* ActionPopupHandler.swift */,
|
|
||||||
C6687440259D92D400F32D13 /* ActionTopNotificationModel.swift */,
|
C6687440259D92D400F32D13 /* ActionTopNotificationModel.swift */,
|
||||||
AF1C33642883B5A4006B1001 /* ActionTopNotificationHandler.swift */,
|
AF1C33642883B5A4006B1001 /* ActionTopNotificationHandler.swift */,
|
||||||
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */,
|
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */,
|
||||||
@ -2340,11 +2328,11 @@
|
|||||||
D29DF27821E7A533003B2FB9 /* MVMCoreUISession.m */,
|
D29DF27821E7A533003B2FB9 /* MVMCoreUISession.m */,
|
||||||
D29DF27321E79E81003B2FB9 /* MVMCoreUILoggingHandler.h */,
|
D29DF27321E79E81003B2FB9 /* MVMCoreUILoggingHandler.h */,
|
||||||
D29DF27421E79E81003B2FB9 /* MVMCoreUILoggingHandler.m */,
|
D29DF27421E79E81003B2FB9 /* MVMCoreUILoggingHandler.m */,
|
||||||
|
AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */,
|
||||||
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */,
|
D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */,
|
||||||
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */,
|
D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */,
|
||||||
D2092352244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift */,
|
D2092352244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift */,
|
||||||
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */,
|
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */,
|
||||||
D2ED2817254B112900A1C293 /* MVMCoreUIActionDelegateProtocol.h */,
|
|
||||||
AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */,
|
AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */,
|
||||||
D23A90672614B0B4007E14CE /* CoreUIModelMapping.swift */,
|
D23A90672614B0B4007E14CE /* CoreUIModelMapping.swift */,
|
||||||
);
|
);
|
||||||
@ -2538,15 +2526,12 @@
|
|||||||
D2ED27D8254B0C1F00A1C293 /* Alerts */ = {
|
D2ED27D8254B0C1F00A1C293 /* Alerts */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D2ED27F2254B0E0200A1C293 /* MVMCoreAlertDelegateProtocol.h */,
|
AFA4935629EE3DCC001A9663 /* AlertDelegateProtocol.swift */,
|
||||||
D2ED27F6254B0E0200A1C293 /* MVMCoreAlertHandler.h */,
|
D2ED27F3254B0E0200A1C293 /* AlertObject.swift */,
|
||||||
D2ED27FA254B0E0300A1C293 /* MVMCoreAlertHandler.m */,
|
AF7E509729E477C0009DC2AD /* AlertController.swift */,
|
||||||
D2ED27F7254B0E0200A1C293 /* MVMCoreAlertHandler+Extension.swift */,
|
AF7E509629E477C0009DC2AD /* AlertHandler.swift */,
|
||||||
D2ED27F5254B0E0200A1C293 /* MVMCoreAlertObject.h */,
|
AFA4931F29E5CA73001A9663 /* AlertOperation.swift */,
|
||||||
D2ED27F9254B0E0200A1C293 /* MVMCoreAlertObject.m */,
|
AFA4932129E5EF2E001A9663 /* TopNotificationHandler.swift */,
|
||||||
D2ED27F3254B0E0200A1C293 /* MVMCoreAlertObject+Swift.swift */,
|
|
||||||
D2ED27F8254B0E0200A1C293 /* MVMCoreAlertOperation.h */,
|
|
||||||
D2ED27F4254B0E0200A1C293 /* MVMCoreAlertOperation.m */,
|
|
||||||
);
|
);
|
||||||
path = Alerts;
|
path = Alerts;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2598,15 +2583,10 @@
|
|||||||
D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */,
|
D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */,
|
||||||
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */,
|
D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */,
|
||||||
D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */,
|
D2ED2811254B0EB800A1C293 /* MVMCoreTopAlertObject.h in Headers */,
|
||||||
D2ED27FE254B0E0300A1C293 /* MVMCoreAlertObject.h in Headers */,
|
|
||||||
D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */,
|
D2ED280F254B0EB800A1C293 /* MVMCoreTopAlertViewProtocol.h in Headers */,
|
||||||
D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */,
|
D2ED280C254B0EB800A1C293 /* MVMCoreTopAlertAnimationDelegateProtocol.h in Headers */,
|
||||||
D2ED280D254B0EB800A1C293 /* MVMCoreTopAlertOperation.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 */,
|
D2ED2810254B0EB800A1C293 /* MVMCoreTopAlertDelegateProtocol.h in Headers */,
|
||||||
D2ED27FF254B0E0300A1C293 /* MVMCoreAlertHandler.h in Headers */,
|
|
||||||
D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */,
|
D2ED2815254B0EE400A1C293 /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */,
|
||||||
D29DF26F21E6AA0B003B2FB9 /* FLAnimatedImageView.h in Headers */,
|
D29DF26F21E6AA0B003B2FB9 /* FLAnimatedImageView.h in Headers */,
|
||||||
D29DF2A121E7AF4E003B2FB9 /* MVMCoreUIUtility.h in Headers */,
|
D29DF2A121E7AF4E003B2FB9 /* MVMCoreUIUtility.h in Headers */,
|
||||||
@ -2726,7 +2706,7 @@
|
|||||||
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */,
|
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */,
|
||||||
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */,
|
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */,
|
||||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
||||||
D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */,
|
D2ED27FC254B0E0300A1C293 /* AlertObject.swift in Sources */,
|
||||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||||
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */,
|
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */,
|
||||||
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
||||||
@ -2782,7 +2762,6 @@
|
|||||||
012A88C8238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift in Sources */,
|
012A88C8238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift in Sources */,
|
||||||
8D8067D12444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift in Sources */,
|
8D8067D12444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift in Sources */,
|
||||||
0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */,
|
0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */,
|
||||||
D2ED2802254B0E0300A1C293 /* MVMCoreAlertObject.m in Sources */,
|
|
||||||
D224798C231450C8003FCCF9 /* HeadlineBodyToggle.swift in Sources */,
|
D224798C231450C8003FCCF9 /* HeadlineBodyToggle.swift in Sources */,
|
||||||
9458C3182406C8FD00930963 /* UIFont+FontWrapping.m in Sources */,
|
9458C3182406C8FD00930963 /* UIFont+FontWrapping.m in Sources */,
|
||||||
522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */,
|
522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */,
|
||||||
@ -2801,7 +2780,6 @@
|
|||||||
AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */,
|
AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */,
|
||||||
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
|
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
|
||||||
011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */,
|
011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */,
|
||||||
AF1C33672883B712006B1001 /* ActionPopupHandler.swift in Sources */,
|
|
||||||
D23A900926125FFB007E14CE /* GetContactBehavior.swift in Sources */,
|
D23A900926125FFB007E14CE /* GetContactBehavior.swift in Sources */,
|
||||||
D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */,
|
D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */,
|
||||||
AA617AB22453012400910B8F /* ListDeviceComplexLinkSmallModel.swift in Sources */,
|
AA617AB22453012400910B8F /* ListDeviceComplexLinkSmallModel.swift in Sources */,
|
||||||
@ -2809,7 +2787,6 @@
|
|||||||
D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */,
|
D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */,
|
||||||
D28764AC245898A400CB882D /* ThreeLayerFillMiddleTemplateModel.swift in Sources */,
|
D28764AC245898A400CB882D /* ThreeLayerFillMiddleTemplateModel.swift in Sources */,
|
||||||
BBBBC87D24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift in Sources */,
|
BBBBC87D24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift in Sources */,
|
||||||
D2ED2800254B0E0300A1C293 /* MVMCoreAlertHandler+Extension.swift in Sources */,
|
|
||||||
D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */,
|
D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */,
|
||||||
D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */,
|
D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */,
|
||||||
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */,
|
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */,
|
||||||
@ -2864,7 +2841,6 @@
|
|||||||
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
||||||
D23A8FF82612308D007E14CE /* PageBehaviorProtocolRequirer.swift in Sources */,
|
D23A8FF82612308D007E14CE /* PageBehaviorProtocolRequirer.swift in Sources */,
|
||||||
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
||||||
D2ED27ED254B0CE700A1C293 /* ActionPopupModel.swift in Sources */,
|
|
||||||
94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */,
|
94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */,
|
||||||
943820842432382400B43AF3 /* WebView.swift in Sources */,
|
943820842432382400B43AF3 /* WebView.swift in Sources */,
|
||||||
0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */,
|
0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */,
|
||||||
@ -2878,6 +2854,7 @@
|
|||||||
8DDD6C1D244D90B8006A2232 /* ListThreeColumnDataUsage.swift in Sources */,
|
8DDD6C1D244D90B8006A2232 /* ListThreeColumnDataUsage.swift in Sources */,
|
||||||
0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */,
|
0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */,
|
||||||
D28764FB245A33A500CB882D /* TwoLinkViewModel.swift in Sources */,
|
D28764FB245A33A500CB882D /* TwoLinkViewModel.swift in Sources */,
|
||||||
|
AFA4932029E5CA73001A9663 /* AlertOperation.swift in Sources */,
|
||||||
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */,
|
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */,
|
||||||
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */,
|
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */,
|
||||||
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
|
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
|
||||||
@ -2899,6 +2876,7 @@
|
|||||||
D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */,
|
D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */,
|
||||||
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
|
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
|
||||||
0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */,
|
0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */,
|
||||||
|
AFA4933F29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift in Sources */,
|
||||||
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
||||||
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
|
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
|
||||||
AF1C33712885AE76006B1001 /* MVMCoreUIActionHandler.swift in Sources */,
|
AF1C33712885AE76006B1001 /* MVMCoreUIActionHandler.swift in Sources */,
|
||||||
@ -2922,7 +2900,6 @@
|
|||||||
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */,
|
D2092357244FA1EF0044AD09 /* ThreeLayerModelBase.swift in Sources */,
|
||||||
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */,
|
D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */,
|
||||||
D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */,
|
D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */,
|
||||||
D2ED2803254B0E0300A1C293 /* MVMCoreAlertHandler.m in Sources */,
|
|
||||||
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
|
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
|
||||||
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */,
|
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */,
|
||||||
D20923592450ECE00044AD09 /* TableView.swift in Sources */,
|
D20923592450ECE00044AD09 /* TableView.swift in Sources */,
|
||||||
@ -2977,6 +2954,7 @@
|
|||||||
AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */,
|
AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */,
|
||||||
AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */,
|
AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */,
|
||||||
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
|
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
|
||||||
|
AF7E509829E477C1009DC2AD /* AlertHandler.swift in Sources */,
|
||||||
D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */,
|
D2ED27EB254B0CE700A1C293 /* UIAlertActionStyle+Codable.swift in Sources */,
|
||||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||||
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
||||||
@ -3012,6 +2990,7 @@
|
|||||||
D23118B325124E18001C8440 /* Notification.swift in Sources */,
|
D23118B325124E18001C8440 /* Notification.swift in Sources */,
|
||||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
||||||
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
||||||
|
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */,
|
||||||
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
|
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
|
||||||
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
||||||
27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */,
|
27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */,
|
||||||
@ -3021,7 +3000,6 @@
|
|||||||
3265B30224BCA737000D154B /* HeadersH1NoButtonsBodyTextModel.swift in Sources */,
|
3265B30224BCA737000D154B /* HeadersH1NoButtonsBodyTextModel.swift in Sources */,
|
||||||
D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */,
|
D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */,
|
||||||
D264FAAC2441009400D98315 /* RadioBoxCollectionViewCell.swift in Sources */,
|
D264FAAC2441009400D98315 /* RadioBoxCollectionViewCell.swift in Sources */,
|
||||||
D2ED27FD254B0E0300A1C293 /* MVMCoreAlertOperation.m in Sources */,
|
|
||||||
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */,
|
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */,
|
||||||
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */,
|
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */,
|
||||||
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
|
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
|
||||||
@ -3057,6 +3035,7 @@
|
|||||||
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */,
|
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */,
|
||||||
D29C558A25C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift in Sources */,
|
D29C558A25C05C7D0082E7D6 /* BGVideoImageMoleculeModel.swift in Sources */,
|
||||||
8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */,
|
8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */,
|
||||||
|
AFA4932229E5EF2E001A9663 /* TopNotificationHandler.swift in Sources */,
|
||||||
BB2FB3BD247E7EF200DF73CD /* Tags.swift in Sources */,
|
BB2FB3BD247E7EF200DF73CD /* Tags.swift in Sources */,
|
||||||
AA104ADC244734EA004D2810 /* HeadersH1LandingPageHeaderModel.swift in Sources */,
|
AA104ADC244734EA004D2810 /* HeadersH1LandingPageHeaderModel.swift in Sources */,
|
||||||
BBAA4F03243D8E3B005AAD5F /* RadioBoxes.swift in Sources */,
|
BBAA4F03243D8E3B005AAD5F /* RadioBoxes.swift in Sources */,
|
||||||
@ -3085,6 +3064,7 @@
|
|||||||
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
|
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
|
||||||
0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */,
|
0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */,
|
||||||
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */,
|
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */,
|
||||||
|
AF7E509929E477C1009DC2AD /* AlertController.swift in Sources */,
|
||||||
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
|
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
|
||||||
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */,
|
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */,
|
||||||
D253BB9C245874F8002DE544 /* BGImageMolecule.swift in Sources */,
|
D253BB9C245874F8002DE544 /* BGImageMolecule.swift in Sources */,
|
||||||
|
|||||||
38
MVMCoreUI/Alerts/AlertController.swift
Normal file
38
MVMCoreUI/Alerts/AlertController.swift
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// AlertController.swift
|
||||||
|
// MVMCore
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 3/24/23.
|
||||||
|
// Copyright © 2023 myverizon. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
|
public class AlertController: UIAlertController {
|
||||||
|
@objc dynamic public var visible = false
|
||||||
|
private let visibleKey = "isVisible"
|
||||||
|
|
||||||
|
public override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||||
|
return MVMCoreGetterUtility.isOnIPad() ? .all : .portrait
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var description: String {
|
||||||
|
return "\(super.description)|title=\(title ?? "")|message=\(message ?? "")"
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
willChangeValue(forKey: visibleKey)
|
||||||
|
visible = true
|
||||||
|
didChangeValue(forKey: visibleKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func viewDidDisappear(_ animated: Bool) {
|
||||||
|
super.viewDidDisappear(animated)
|
||||||
|
willChangeValue(forKey: visibleKey)
|
||||||
|
visible = false
|
||||||
|
didChangeValue(forKey: visibleKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
19
MVMCoreUI/Alerts/AlertDelegateProtocol.swift
Normal file
19
MVMCoreUI/Alerts/AlertDelegateProtocol.swift
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// AlertDelegateProtocol.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 4/17/23.
|
||||||
|
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public protocol AlertDelegateProtocol {
|
||||||
|
// All are performed on the main thread.
|
||||||
|
@MainActor func alertShown(_ alertController: UIAlertController)
|
||||||
|
@MainActor func alertCancelled(_ alertController: UIAlertController)
|
||||||
|
@MainActor func alertDismissed(_ alertController: UIAlertController)
|
||||||
|
@MainActor func alertPaused(_ alertController: UIAlertController)
|
||||||
|
@MainActor func alertUnpaused(_ alertController: UIAlertController)
|
||||||
|
}
|
||||||
102
MVMCoreUI/Alerts/AlertHandler.swift
Normal file
102
MVMCoreUI/Alerts/AlertHandler.swift
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
//
|
||||||
|
// AlertHandler.swift
|
||||||
|
// MVMCore
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 4/10/23.
|
||||||
|
// Copyright © 2023 myverizon. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
|
public class AlertHandler {
|
||||||
|
|
||||||
|
/// Returns the handler stored in the CoreUIObject
|
||||||
|
public static func shared() -> Self {
|
||||||
|
return MVMCoreActionUtility.fatalClassCheck(object: CoreUIObject.sharedInstance()?.alertHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The operation queue of alert operations.
|
||||||
|
private var queue = {
|
||||||
|
let queue = OperationQueue()
|
||||||
|
queue.maxConcurrentOperationCount = 1
|
||||||
|
return queue
|
||||||
|
}()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
|
||||||
|
/// Returns if an alert is currently showing in the hierarchy, even if it is not the top presented view.
|
||||||
|
public func isAlertShowing() -> Bool {
|
||||||
|
return queue.operations.contains(where: { operation in
|
||||||
|
return !operation.isCancelled &&
|
||||||
|
!operation.isFinished &&
|
||||||
|
operation.isExecuting
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns if a greedy alert is currently showing in the hierarchy, even if it is not the top presented view.
|
||||||
|
public func isGreedyAlertShowing() -> Bool {
|
||||||
|
return queue.operations.contains(where: { operation in
|
||||||
|
return !operation.isCancelled &&
|
||||||
|
!operation.isFinished &&
|
||||||
|
operation.isExecuting &&
|
||||||
|
(operation as? AlertOperation)?.alertObject.isGreedy ?? false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
public func createAlertController(with alertModel: AlertModel) -> AlertController {
|
||||||
|
// ActionSheets are not supported on iPad interfaces without a source rect (i.e. a source element) which isn't currently supported for our generic handling.
|
||||||
|
// TODO: Find a way to support this.
|
||||||
|
var alertStyle = alertModel.style
|
||||||
|
if alertStyle == .actionSheet, UIDevice.current.userInterfaceIdiom != .phone {
|
||||||
|
alertStyle = .alert
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the alert. Adds the actions one by one.
|
||||||
|
let alertController = AlertController(title: alertModel.title, message: alertModel.message, preferredStyle: alertStyle)
|
||||||
|
for action in alertModel.actions {
|
||||||
|
alertController.addAction(action)
|
||||||
|
}
|
||||||
|
return alertController
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows an alert using the alert object.
|
||||||
|
@MainActor
|
||||||
|
public func queueAlertToShow(with alertObject: AlertObject) -> UIAlertController {
|
||||||
|
|
||||||
|
// It's a greedy alert! Clear all alerts that are queued up and the one that is showing
|
||||||
|
if alertObject.isGreedy {
|
||||||
|
removeAllAlertViews()
|
||||||
|
}
|
||||||
|
|
||||||
|
let alertController = createAlertController(with: alertObject.alertModel)
|
||||||
|
let alertOperation = AlertOperation(with: alertController, alertObject: alertObject)
|
||||||
|
queue.addOperation(alertOperation)
|
||||||
|
return alertController
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel Alert with ID.
|
||||||
|
public func cancelAlert(with id: String) {
|
||||||
|
queue.operations.first { operation in
|
||||||
|
guard let operation = operation as? AlertOperation,
|
||||||
|
operation.alertObject.alertModel.id == id else { return false }
|
||||||
|
return true
|
||||||
|
}?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
*/
|
||||||
|
public func cancelAlert(using predicate: ((AlertObject) -> Bool)) {
|
||||||
|
for case let operation as AlertOperation in queue.operations {
|
||||||
|
if predicate(operation.alertObject) {
|
||||||
|
operation.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancels all current alerts
|
||||||
|
public func removeAllAlertViews() {
|
||||||
|
queue.cancelAllOperations()
|
||||||
|
}
|
||||||
|
}
|
||||||
27
MVMCoreUI/Alerts/AlertObject.swift
Normal file
27
MVMCoreUI/Alerts/AlertObject.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// AlertObject.swift
|
||||||
|
// MVMCore
|
||||||
|
//
|
||||||
|
// Created by Suresh, Kamlesh on 7/10/20.
|
||||||
|
// Copyright © 2020 myverizon. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
|
/// An object with properties for managing the alert.
|
||||||
|
public struct AlertObject {
|
||||||
|
|
||||||
|
/// Greedy alerts dismiss any other alerts and do not allow any other alerts to show until finished.
|
||||||
|
public var isGreedy = false
|
||||||
|
|
||||||
|
/// The alert model for the alert to show.
|
||||||
|
public var alertModel: AlertModel
|
||||||
|
|
||||||
|
public weak var alertDelegate: AlertDelegateProtocol?
|
||||||
|
|
||||||
|
public init(alertModel: AlertModel, isGreedy: Bool = false, alertDelegate: AlertDelegateProtocol? = nil) {
|
||||||
|
self.alertModel = alertModel
|
||||||
|
self.isGreedy = isGreedy
|
||||||
|
self.alertDelegate = alertDelegate
|
||||||
|
}
|
||||||
|
}
|
||||||
132
MVMCoreUI/Alerts/AlertOperation.swift
Normal file
132
MVMCoreUI/Alerts/AlertOperation.swift
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//
|
||||||
|
// AlertOperation.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 4/11/23.
|
||||||
|
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MVMCore
|
||||||
|
import Dispatch
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
public class AlertOperation: MVMCoreOperation {
|
||||||
|
|
||||||
|
private actor Properties {
|
||||||
|
private var isDisplayed: Bool = false
|
||||||
|
|
||||||
|
func set(displayed: Bool) {
|
||||||
|
isDisplayed = displayed
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIsDisplayed() -> Bool {
|
||||||
|
return isDisplayed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var properties = Properties()
|
||||||
|
|
||||||
|
public let alertController: AlertController
|
||||||
|
|
||||||
|
public let alertObject: AlertObject
|
||||||
|
|
||||||
|
/// For tracking isVisible changes of the alert controller.
|
||||||
|
private var cancellable: Cancellable?
|
||||||
|
|
||||||
|
/// Blocks the navigation queue to ensure no other navigation happens while an alert is displayed.
|
||||||
|
private var blockingOperation: MVMCoreOperation?
|
||||||
|
|
||||||
|
public init(with alert: AlertController, alertObject: AlertObject) {
|
||||||
|
self.alertController = alert
|
||||||
|
self.alertObject = alertObject
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
stopObservingAlertView()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func main() {
|
||||||
|
guard !checkAndHandleForCancellation() else { return }
|
||||||
|
|
||||||
|
// Observe for when it is removed.
|
||||||
|
observeForCurrentAlertViewDismissal()
|
||||||
|
|
||||||
|
// Adds the presentation to the animation queue.
|
||||||
|
let blockingOperation = MVMCoreOperation()
|
||||||
|
self.blockingOperation = blockingOperation
|
||||||
|
Task { @MainActor in
|
||||||
|
MVMCoreNavigationHandler.shared()?.present(alertController, animated: true, delegate: nil) { [weak self] in
|
||||||
|
guard let self = self else {
|
||||||
|
blockingOperation.markAsFinished()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Task {
|
||||||
|
// We finished but it was not displayed yet. It's possible that it was cancelled. Finish this task
|
||||||
|
if await !self.properties.getIsDisplayed() {
|
||||||
|
self.markAsFinished()
|
||||||
|
} else {
|
||||||
|
(CoreUIObject.sharedInstance()?.loggingDelegate as? MVMCoreUILoggingDelegateProtocol)?.logAlert(with: self.alertObject)
|
||||||
|
if self.isCancelled {
|
||||||
|
await self.dismissAlertView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block navigations until this alert is removed.
|
||||||
|
MVMCoreNavigationHandler.shared()?.addNavigationOperation(blockingOperation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func cancel() {
|
||||||
|
super.cancel()
|
||||||
|
Task { @MainActor in
|
||||||
|
self.alertObject.alertDelegate?.alertCancelled(self.alertController)
|
||||||
|
await self.dismissAlertView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismissAlertView() async {
|
||||||
|
guard await properties.getIsDisplayed() else { return }
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
Task { @MainActor in
|
||||||
|
MVMCoreNavigationHandler.shared()?.dismiss(alertController, animated: true, delegate: nil) {
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func markAsFinished() {
|
||||||
|
blockingOperation?.markAsFinished()
|
||||||
|
super.markAsFinished()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Observer Functions
|
||||||
|
|
||||||
|
private func observeForCurrentAlertViewDismissal() {
|
||||||
|
stopObservingAlertView()
|
||||||
|
cancellable = alertController.publisher(for: \AlertController.visible).sink() { [weak self] visible in
|
||||||
|
guard let self = self else { return }
|
||||||
|
Task {
|
||||||
|
guard await self.properties.getIsDisplayed() != visible else { return }
|
||||||
|
await self.properties.set(displayed: visible)
|
||||||
|
Task { @MainActor in
|
||||||
|
if visible {
|
||||||
|
self.alertObject.alertDelegate?.alertShown(self.alertController)
|
||||||
|
} else {
|
||||||
|
self.alertObject.alertDelegate?.alertDismissed(self.alertController)
|
||||||
|
|
||||||
|
// Is visible was set to NO, meaning that the alertview is no longer visible.
|
||||||
|
self.stopObservingAlertView()
|
||||||
|
self.markAsFinished()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func stopObservingAlertView() {
|
||||||
|
cancellable?.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 <Foundation/Foundation.h>
|
|
||||||
@class MVMCoreAlertObject;
|
|
||||||
@class MVMCoreLoadObject;
|
|
||||||
@class MVMCoreErrorObject;
|
|
||||||
|
|
||||||
@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;
|
|
||||||
|
|
||||||
/** 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
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
//
|
|
||||||
// MVMCoreAlertHandler+Extension.swift
|
|
||||||
// MVMCore
|
|
||||||
//
|
|
||||||
// Created by Scott Pfeil on 9/15/20.
|
|
||||||
// Copyright © 2020 myverizon. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public extension MVMCoreAlertHandler {
|
|
||||||
|
|
||||||
/// Re-evaluates the queue operations
|
|
||||||
@objc func reevaluteQueue() {
|
|
||||||
var highestReadyOperation: MVMCoreTopAlertOperation?
|
|
||||||
var executingOperation: MVMCoreTopAlertOperation?
|
|
||||||
for case let operation as MVMCoreTopAlertOperation in topAlertQueue.operations {
|
|
||||||
guard !operation.isCancelled,
|
|
||||||
!operation.isFinished else { continue }
|
|
||||||
if operation.isReady,
|
|
||||||
highestReadyOperation == nil || operation.queuePriority.rawValue > highestReadyOperation!.queuePriority.rawValue {
|
|
||||||
highestReadyOperation = operation
|
|
||||||
}
|
|
||||||
if operation.isExecuting {
|
|
||||||
executingOperation = operation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
guard let currentOperation = executingOperation else { return }
|
|
||||||
|
|
||||||
// Cancel the executing operation if it is no longer ready to run. Re-add for later if it is persistent.
|
|
||||||
guard currentOperation.isReady else {
|
|
||||||
currentOperation.reAddAfterCancel = currentOperation.topAlertObject.persistent
|
|
||||||
currentOperation.cancel()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the highest priority operation is not executing, and the executing operation is persistent, cancel it.
|
|
||||||
if let newOperation = highestReadyOperation,
|
|
||||||
currentOperation != newOperation,
|
|
||||||
currentOperation.topAlertObject.persistent {
|
|
||||||
currentOperation.reAddAfterCancel = true
|
|
||||||
currentOperation.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Registers to know when pages change.
|
|
||||||
@objc func registerForPageChanges() {
|
|
||||||
MVMCoreNavigationHandler.shared()?.addDelegate(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension MVMCoreAlertHandler: MVMCorePresentationDelegateProtocol {
|
|
||||||
// Update displayable for each top alert operation when page type changes, in top queue priority order.
|
|
||||||
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
|
|
||||||
guard topAlertQueue.operations.count > 0 else { return }
|
|
||||||
let viewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController)
|
|
||||||
guard viewController == MVMCoreUISplitViewController.main()?.getCurrentViewController() else { return }
|
|
||||||
let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
|
|
||||||
topAlertQueue.operations.compactMap {
|
|
||||||
$0 as? MVMCoreTopAlertOperation
|
|
||||||
}.sorted {
|
|
||||||
$0.queuePriority.rawValue > $1.queuePriority.rawValue
|
|
||||||
}.forEach {
|
|
||||||
$0.updateDisplayable(byPageType: pageType)
|
|
||||||
}
|
|
||||||
reevaluteQueue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,119 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertDelegateProtocol.h>
|
|
||||||
|
|
||||||
@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;
|
|
||||||
|
|
||||||
/// 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<UIAlertAction *>*)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<UIAlertAction *>*)actions alertStyle:(UIAlertControllerStyle)alertStyle isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject <MVMCoreAlertDelegateProtocol>*)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;
|
|
||||||
|
|
||||||
/// Hides a alert based on the type string.
|
|
||||||
- (void)hideTopAlertViewOfType:(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
|
|
||||||
@ -1,274 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 MVMCore.MVMCoreAlertController;
|
|
||||||
#import "MVMCoreAlertOperation.h"
|
|
||||||
#import "MVMCoreTopAlertOperation.h"
|
|
||||||
@import MVMCore.MVMCoreJSONConstants;
|
|
||||||
@import MVMCore.NSDictionary_MFConvenience;
|
|
||||||
@import MVMCore.NSArray_MFConvenience;
|
|
||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
|
||||||
|
|
||||||
@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 registerForPageChanges];
|
|
||||||
}
|
|
||||||
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<UIAlertAction *>*)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<UIAlertAction *>*)actions isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject <MVMCoreAlertDelegateProtocol>*)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<UIAlertAction *>*)actions alertStyle:(UIAlertControllerStyle)alertStyle isGreedy:(BOOL)isGreedy alertDelegate:(nullable NSObject <MVMCoreAlertDelegateProtocol>*)alertDelegate {
|
|
||||||
|
|
||||||
// It's a greedy alert! Clear all alerts that are queued up and the one that is showing
|
|
||||||
if (isGreedy) {
|
|
||||||
[self removeAllAlertViews];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alertStyle == UIAlertControllerStyleActionSheet && UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPhone) {
|
|
||||||
// ActionSheets are not supported on iPad interfaces without a source rect (i.e. a source element) which isn't currently supported for our generic handling.
|
|
||||||
alertStyle = UIAlertControllerStyleAlert;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}];
|
|
||||||
|
|
||||||
NSString *currentPageType = ((UIViewController<MVMCoreViewControllerProtocol> *)[[MVMCoreUISplitViewController mainSplitViewController] getCurrentDetailViewController]).pageType;
|
|
||||||
[alertOperation updateDisplayableByPageType:currentPageType];
|
|
||||||
|
|
||||||
[self.topAlertQueue addOperation:alertOperation];
|
|
||||||
[self reevaluteQueue];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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)hideTopAlertViewOfType:(nullable NSString *)type {
|
|
||||||
if (type) {
|
|
||||||
for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) {
|
|
||||||
|
|
||||||
// Cancel all operations of this type.
|
|
||||||
if ([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
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
//
|
|
||||||
// MVMCoreAlertObject+Swift.swift
|
|
||||||
// MVMCore
|
|
||||||
//
|
|
||||||
// Created by Suresh, Kamlesh on 7/10/20.
|
|
||||||
// Copyright © 2020 myverizon. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
public extension MVMCoreAlertObject {
|
|
||||||
|
|
||||||
static func alertObject(from alertModel: AlertModel, actions: [UIAlertAction]? = nil, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> MVMCoreAlertObject? {
|
|
||||||
|
|
||||||
let actionsForAlert = actions ?? generateActions(from: alertModel.alertActions, additionalData: additionalData, delegateObject: delegateObject)
|
|
||||||
|
|
||||||
let alertObject = MVMCoreAlertObject(popupAlertWithTitle: alertModel.title,
|
|
||||||
message: alertModel.message,
|
|
||||||
actions: actionsForAlert,
|
|
||||||
isGreedy: false)
|
|
||||||
|
|
||||||
alertObject?.alertStyle = alertModel.style
|
|
||||||
alertObject?.pageJson = alertModel.analyticsData
|
|
||||||
|
|
||||||
return alertObject
|
|
||||||
}
|
|
||||||
|
|
||||||
static func generateActions(from buttonModels: [AlertButtonModel], additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalHandling: ((AlertButtonModel, UIAlertAction)->())? = nil) -> [UIAlertAction] {
|
|
||||||
return buttonModels.map { alertButtonModel in
|
|
||||||
let alertAction = UIAlertAction(title: alertButtonModel.title, style: alertButtonModel.style) { action in
|
|
||||||
Task(priority: .userInitiated) {
|
|
||||||
do {
|
|
||||||
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(
|
|
||||||
with: alertButtonModel.action,
|
|
||||||
additionalData: additionalData,
|
|
||||||
delegateObject: delegateObject
|
|
||||||
)
|
|
||||||
} catch {
|
|
||||||
|
|
||||||
}
|
|
||||||
additionalHandling?(alertButtonModel, action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return alertAction
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc static func alertObjectWith(action actionJson: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let analyticsData = alertJson.optionalDictionaryForKey("analyticsData") {
|
|
||||||
alertObject?.pageJson = ["analyticsData": analyticsData]
|
|
||||||
}
|
|
||||||
|
|
||||||
return alertObject
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 <Foundation/Foundation.h>
|
|
||||||
@import MVMCore.MVMCoreActionDelegateProtocol;
|
|
||||||
@import MVMCore.MVMCoreLoadDelegateProtocol;
|
|
||||||
@import MVMCore.MVMCorePresentationDelegateProtocol;
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertDelegateProtocol.h>
|
|
||||||
|
|
||||||
@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 <MVMCoreAlertDelegateProtocol> *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;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,197 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 MVMCore.MVMCoreCache;
|
|
||||||
@import MVMCore.MVMCoreErrorConstants;
|
|
||||||
@import MVMCore.MVMCoreErrorObject;
|
|
||||||
@import MVMCore.MVMCoreLoadObject;
|
|
||||||
@import MVMCore.MVMCoreGetterUtility;
|
|
||||||
@import MVMCore.NSDictionary_MFConvenience;
|
|
||||||
@import MVMCore.MVMCoreHardcodedStringsConstants;
|
|
||||||
@import MVMCore.MVMCoreJSONConstants;
|
|
||||||
@import MVMCore.Swift;
|
|
||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
|
||||||
|
|
||||||
@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 {
|
|
||||||
MVMCoreUIDelegateObject *alertDelegateObject = nil;
|
|
||||||
if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) {
|
|
||||||
alertDelegateObject = (MVMCoreUIDelegateObject *)delegateObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
__block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
|
|
||||||
alert.title = [responseInfo string:KeyErrorHeading] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
|
|
||||||
alert.message = [responseInfo string:KeyUserMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
|
|
||||||
|
|
||||||
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 = alertDelegateObject.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 = alertDelegateObject.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 string:KeyTitle];
|
|
||||||
alert.pageJson = page;
|
|
||||||
alert.message = [page string:KeyMessage];
|
|
||||||
alert.isGreedy = isGreedy;
|
|
||||||
alert.type = MFAlertTypePopup;
|
|
||||||
alert.alertStyle = UIAlertControllerStyleAlert;
|
|
||||||
|
|
||||||
NSArray <NSDictionary *> *actions = [page array:KeyLinks];
|
|
||||||
NSMutableArray <UIAlertAction *> *actionsForAlert = [NSMutableArray array];
|
|
||||||
for (NSDictionary *actionMap in actions) {
|
|
||||||
[actionsForAlert addObject:[UIAlertAction actionWithTitle:[actionMap stringForKey:KeyTitle] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
|
||||||
[[MVMCoreUIActionHandler 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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
@import MVMCore.MVMCoreOperation;
|
|
||||||
#import <MVMCoreUI/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 <MVMCoreAlertDelegateProtocol> *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 <MVMCoreAlertDelegateProtocol>)alertDelegate;
|
|
||||||
|
|
||||||
/// Pauses the operation. Temporarily removes any alert.
|
|
||||||
- (void)pause;
|
|
||||||
|
|
||||||
/// Unpauses the operation, resuming any alert.
|
|
||||||
- (void)unpause;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,242 +0,0 @@
|
|||||||
//
|
|
||||||
// MVMCoreAlertOperation.m
|
|
||||||
// myverizon
|
|
||||||
//
|
|
||||||
// Created by Scott Pfeil on 9/28/15.
|
|
||||||
// Copyright © 2015 Verizon Wireless. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MVMCoreAlertOperation.h"
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertHandler.h>
|
|
||||||
@import MVMCore.MVMCoreAlertController;
|
|
||||||
@import MVMCore.MVMCoreNavigationHandler;
|
|
||||||
|
|
||||||
@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 <MVMCoreAlertDelegateProtocol> *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 <MVMCoreAlertDelegateProtocol>*)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
|
|
||||||
236
MVMCoreUI/Alerts/TopNotificationHandler.swift
Normal file
236
MVMCoreUI/Alerts/TopNotificationHandler.swift
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
//
|
||||||
|
// TopNotificationHandler.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 4/11/23.
|
||||||
|
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
|
public class TopNotificationHandler {
|
||||||
|
|
||||||
|
/// The operation queue of top notification operations.
|
||||||
|
private var queue = OperationQueue()
|
||||||
|
|
||||||
|
/// Returns the handler stored in the CoreUIObject
|
||||||
|
public static func shared() -> Self {
|
||||||
|
return MVMCoreActionUtility.fatalClassCheck(object: CoreUIObject.sharedInstance()?.topNotificationHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
registerWithNotificationCenter()
|
||||||
|
registerForPageChanges()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - JSON Handling
|
||||||
|
|
||||||
|
/// Registers with the notification center to know when json is updated.
|
||||||
|
private func registerWithNotificationCenter() {
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers to know when pages change.
|
||||||
|
private func registerForPageChanges() {
|
||||||
|
MVMCoreNavigationHandler.shared()?.addDelegate(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getDelegateObject() -> MVMCoreUIDelegateObject? {
|
||||||
|
// TODO: Top alert view is current delegate. Should move to current view controller eventually?
|
||||||
|
guard let alertView = MVMCoreUISplitViewController.main()?.topAlertView else { return nil }
|
||||||
|
return MVMCoreUIDelegateObject.create(withDelegateForAll: alertView)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for new top alert json
|
||||||
|
@objc private func responseJSONUpdated(notification: Notification) {
|
||||||
|
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") {
|
||||||
|
TopNotificationHandler.shared().hideTopAlertView(of: disableType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show any new top alert.
|
||||||
|
guard let responseJSON = loadObject.responseJSON,
|
||||||
|
let json = responseJSON.optionalDictionaryForKey(KeyTopAlert) else { return }
|
||||||
|
showTopNotification(with: json)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes the json into a TopNotificationModel
|
||||||
|
public func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? {
|
||||||
|
do {
|
||||||
|
return try TopNotificationModel.decode(json: json, delegateObject: delegateObject)
|
||||||
|
} catch {
|
||||||
|
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") {
|
||||||
|
MVMCoreUILoggingHandler.addError(toLog: errorObject)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Operation Handling
|
||||||
|
|
||||||
|
private func add(operation: MVMCoreTopAlertOperation) {
|
||||||
|
operation.completionBlock = { [weak self] in
|
||||||
|
// If the alert was cancelled to show another with higher priority, re-add to the operation when cancelled to the queue.
|
||||||
|
if operation.reAddAfterCancel {
|
||||||
|
let newOperation: MVMCoreTopAlertOperation = operation.copy() as! MVMCoreTopAlertOperation
|
||||||
|
newOperation.reAddAfterCancel = false
|
||||||
|
self?.add(operation: newOperation)
|
||||||
|
}
|
||||||
|
operation.completionBlock = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentPageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType
|
||||||
|
operation.updateDisplayable(byPageType: currentPageType)
|
||||||
|
|
||||||
|
queue.addOperation(operation)
|
||||||
|
reevaluteQueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for existing top alert object of same type and updates it. Only happens for molecular top alerts. Returns true if we updated.
|
||||||
|
private func checkAndUpdateExisting(with topAlertObject: MVMCoreTopAlertObject) -> Bool {
|
||||||
|
for case let operation as MVMCoreTopAlertOperation in queue.operations {
|
||||||
|
guard topAlertObject.json != nil,
|
||||||
|
operation.topAlertObject.type == topAlertObject.type else { continue }
|
||||||
|
operation.update(with: topAlertObject)
|
||||||
|
let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType
|
||||||
|
operation.updateDisplayable(byPageType: pageType)
|
||||||
|
reevaluteQueue()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-evaluates the queue operations
|
||||||
|
private func reevaluteQueue() {
|
||||||
|
var highestReadyOperation: MVMCoreTopAlertOperation?
|
||||||
|
var executingOperation: MVMCoreTopAlertOperation?
|
||||||
|
for case let operation as MVMCoreTopAlertOperation in queue.operations {
|
||||||
|
guard !operation.isCancelled,
|
||||||
|
!operation.isFinished else { continue }
|
||||||
|
if operation.isReady,
|
||||||
|
highestReadyOperation == nil || operation.queuePriority.rawValue > highestReadyOperation!.queuePriority.rawValue {
|
||||||
|
highestReadyOperation = operation
|
||||||
|
}
|
||||||
|
if operation.isExecuting {
|
||||||
|
executingOperation = operation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard let currentOperation = executingOperation else { return }
|
||||||
|
|
||||||
|
// Cancel the executing operation if it is no longer ready to run. Re-add for later if it is persistent.
|
||||||
|
guard currentOperation.isReady else {
|
||||||
|
currentOperation.reAddAfterCancel = currentOperation.topAlertObject.persistent
|
||||||
|
currentOperation.cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the highest priority operation is not executing, and the executing operation is persistent, cancel it.
|
||||||
|
if let newOperation = highestReadyOperation,
|
||||||
|
currentOperation != newOperation,
|
||||||
|
currentOperation.topAlertObject.persistent {
|
||||||
|
currentOperation.reAddAfterCancel = true
|
||||||
|
currentOperation.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Show and hide
|
||||||
|
|
||||||
|
public func isTopAlertShowing() -> Bool {
|
||||||
|
return queue.operations.first(where: { operation in
|
||||||
|
return operation.isExecuting
|
||||||
|
}) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hasPersistentTopAlert(of type: String) -> Bool {
|
||||||
|
return queue.operations.first(where: { operation in
|
||||||
|
guard operation.isExecuting,
|
||||||
|
let operation = operation as? MVMCoreTopAlertOperation else { return false }
|
||||||
|
return operation.topAlertObject.persistent && operation.topAlertObject.type == type
|
||||||
|
}) as? MVMCoreTopAlertOperation != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows the top alert with the json.
|
||||||
|
func showTopNotification(with json: [AnyHashable: Any]) {
|
||||||
|
guard let model = decodeTopNotification(with: json, delegateObject: getDelegateObject()) else { return }
|
||||||
|
showTopNotification(with: model)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows the top notification with the model.
|
||||||
|
func showTopNotification(with model: TopNotificationModel) {
|
||||||
|
let object = model.createTopAlertObject()
|
||||||
|
guard !checkAndUpdateExisting(with: object),
|
||||||
|
let operation = MVMCoreTopAlertOperation(topAlertObject: object) else { return }
|
||||||
|
TopNotificationHandler.shared().add(operation: operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the top alert with the legacy object.
|
||||||
|
public func showTopAlert(with topAlertObject: MVMCoreTopAlertObject) {
|
||||||
|
let alertOperation = MVMCoreTopAlertOperation(topAlertObject: topAlertObject)!
|
||||||
|
add(operation: alertOperation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel the current top alert view.
|
||||||
|
public func hideTopAlertView() {
|
||||||
|
guard let currentOperation = queue.operations.first(where: { operation in
|
||||||
|
return operation.isExecuting
|
||||||
|
}) as? MVMCoreTopAlertOperation else { return }
|
||||||
|
currentOperation.topAlertObject.persistent = false
|
||||||
|
currentOperation.reAddAfterCancel = false
|
||||||
|
currentOperation.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel all operations of this type.
|
||||||
|
public func hideTopAlertView(of type: String) {
|
||||||
|
for operation in queue.operations {
|
||||||
|
guard let operation = operation as? MVMCoreTopAlertOperation,
|
||||||
|
operation.topAlertObject.type == type else { continue }
|
||||||
|
operation.reAddAfterCancel = false
|
||||||
|
operation.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel all persistent operations of this type.
|
||||||
|
public func hidePersistentTopAlertView(of type: String) {
|
||||||
|
for operation in queue.operations {
|
||||||
|
guard let operation = operation as? MVMCoreTopAlertOperation,
|
||||||
|
operation.topAlertObject.persistent,
|
||||||
|
operation.topAlertObject.type == type else { continue }
|
||||||
|
operation.reAddAfterCancel = false
|
||||||
|
operation.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds an cancels top alerts associated with the object.
|
||||||
|
public func removeTopAlert(for object: MVMCoreTopAlertObject) {
|
||||||
|
for operation in queue.operations {
|
||||||
|
guard let operation = operation as? MVMCoreTopAlertOperation,
|
||||||
|
operation.topAlertObject === object else { return }
|
||||||
|
operation.reAddAfterCancel = false
|
||||||
|
operation.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func removeAllTopAlerts() {
|
||||||
|
queue.cancelAllOperations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TopNotificationHandler: MVMCorePresentationDelegateProtocol {
|
||||||
|
// Update displayable for each top alert operation when page type changes, in top queue priority order.
|
||||||
|
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
|
||||||
|
guard queue.operations.count > 0 else { return }
|
||||||
|
let viewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController)
|
||||||
|
guard viewController == MVMCoreUISplitViewController.main()?.getCurrentViewController() else { return }
|
||||||
|
let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
|
||||||
|
queue.operations.compactMap {
|
||||||
|
$0 as? MVMCoreTopAlertOperation
|
||||||
|
}.sorted {
|
||||||
|
$0.queuePriority.rawValue > $1.queuePriority.rawValue
|
||||||
|
}.forEach {
|
||||||
|
$0.updateDisplayable(byPageType: pageType)
|
||||||
|
}
|
||||||
|
reevaluteQueue()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,29 +10,12 @@ import Foundation
|
|||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
/// Shows an alert using the model.
|
/// Shows an alert using the model.
|
||||||
open class ActionAlertHandler: MVMCoreJSONActionHandlerProtocol {
|
open class ActionAlertHandler: MVMCoreActionHandlerProtocol {
|
||||||
required public init() {}
|
required public init() {}
|
||||||
|
|
||||||
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
public func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
||||||
var error: MVMCoreErrorObject? = nil
|
|
||||||
guard let alertObject = MVMCoreAlertObject.alertObjectWith(action: JSON, additionalData: additionalData, delegateObject: delegateObject, error: &error) else {
|
|
||||||
throw MVMCoreError.errorObject(error!)
|
|
||||||
}
|
|
||||||
(delegateObject?.actionDelegate as? MVMCoreUIActionDelegateProtocol)?.willShowPopup(with: alertObject, alertJson: JSON)
|
|
||||||
_ = await MainActor.run {
|
|
||||||
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
|
||||||
guard let model = model as? ActionAlertModel else { return }
|
guard let model = model as? ActionAlertModel else { return }
|
||||||
var error: MVMCoreErrorObject? = nil
|
let alertObject = AlertObject(alertModel: model.alert, alertDelegate: (delegateObject as? MVMCoreUIDelegateObject)?.alertDelegate)
|
||||||
guard let alertObject = MVMCoreAlertObject.alertObject(from: model.alert, additionalData: additionalData, delegateObject: delegateObject, error: &error) else {
|
_ = await AlertHandler.shared().queueAlertToShow(with: alertObject)
|
||||||
throw MVMCoreError.errorObject(error!)
|
|
||||||
}
|
|
||||||
(delegateObject?.actionDelegate as? MVMCoreUIActionDelegateProtocol)?.willShowPopup(with: alertObject, alertJson: try MVMCoreActionHandler.convertActionToJSON(model))
|
|
||||||
_ = await MainActor.run {
|
|
||||||
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
//
|
|
||||||
// ActionPopupHandler.swift
|
|
||||||
// MVMCoreUI
|
|
||||||
//
|
|
||||||
// Created by Scott Pfeil on 7/16/22.
|
|
||||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import MVMCore
|
|
||||||
|
|
||||||
/// Shows a popup alert by grabbing the content from a Page in the cache using the pageType.
|
|
||||||
open class ActionPopupHandler: MVMCoreActionHandlerProtocol {
|
|
||||||
required public init() {}
|
|
||||||
|
|
||||||
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
|
||||||
guard let model = model as? ActionPopupModel else { return }
|
|
||||||
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
|
|
||||||
MVMCoreCache.shared()?.fetchJSON(forPageType: model.pageType, queue: nil, waitUntilFinished: true, completionHandler: { json in
|
|
||||||
var error: MVMCoreErrorObject? = nil
|
|
||||||
guard let alertObject = MVMCoreAlertObject(page: json, isGreedy: false, additionalData: additionalData, delegateObject: delegateObject, error: &error) else {
|
|
||||||
continuation.resume(throwing: MVMCoreError.errorObject(error!))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
(delegateObject?.actionDelegate as? MVMCoreUIActionDelegateProtocol)?.willShowPopup(with: alertObject, alertJson: json!)
|
|
||||||
Task { @MainActor in
|
|
||||||
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
|
|
||||||
continuation.resume()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
//
|
|
||||||
// ActionPopupModel.swift
|
|
||||||
// MVMCore
|
|
||||||
//
|
|
||||||
// Created by Suresh, Kamlesh on 12/16/19.
|
|
||||||
// Copyright © 2019 myverizon. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import MVMCore
|
|
||||||
|
|
||||||
public struct 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -22,12 +22,10 @@ open class ActionTopAlertHandler: MVMCoreActionHandlerProtocol {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var alertObject = MVMCoreAlertObject(forPageType: model.pageType, responseInfo: responseInfo, additionalData: additionalData, delegateObject: delegateObject)
|
let topAlertObject = MVMCoreTopAlertObject(responseInfo: responseInfo)!
|
||||||
if let object = alertObject,
|
topAlertObject.delegate = (delegateObject as? MVMCoreUIDelegateObject)?.topAlertDelegate
|
||||||
let closure = (delegateObject?.actionDelegate as? MVMCoreUIActionDelegateProtocol)?.willShowTopAlert {
|
topAlertObject.pageType = model.pageType
|
||||||
alertObject = closure(object, json!)
|
TopNotificationHandler.shared().showTopAlert(with: topAlertObject)
|
||||||
}
|
|
||||||
alertObject?.showAlert()
|
|
||||||
continuation.resume()
|
continuation.resume()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,6 @@ open class ActionTopNotificationHandler: MVMCoreActionHandlerProtocol {
|
|||||||
|
|
||||||
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
||||||
guard let model = model as? ActionTopNotificationModel else { return }
|
guard let model = model as? ActionTopNotificationModel else { return }
|
||||||
await MVMCoreUITopAlertView.sharedGlobal()?.showTopAlert(with: model.topNotification)
|
TopNotificationHandler.shared().showTopNotification(with: model.topNotification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
|
public struct AlertButtonModel: Codable {
|
||||||
public class AlertButtonModel: Codable {
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -43,7 +42,7 @@ public class AlertButtonModel: Codable {
|
|||||||
// MARK: - Codec
|
// MARK: - Codec
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
title = try typeContainer.decode(String.self, forKey: .title)
|
title = try typeContainer.decode(String.self, forKey: .title)
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ public class AlertButtonModel: Codable {
|
|||||||
action = try typeContainer.decodeModel(codingKey: .action)
|
action = try typeContainer.decodeModel(codingKey: .action)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(title, forKey: .title)
|
try container.encode(title, forKey: .title)
|
||||||
try container.encode(style.rawValueString, forKey: .style)
|
try container.encode(style.rawValueString, forKey: .style)
|
||||||
@ -61,7 +60,7 @@ public class AlertButtonModel: Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AlertModel: Codable {
|
public struct AlertModel: Codable, Identifiable {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -69,18 +68,32 @@ public class AlertModel: Codable {
|
|||||||
public var title: String
|
public var title: String
|
||||||
public var message: String
|
public var message: String
|
||||||
public var style: UIAlertController.Style = .alert
|
public var style: UIAlertController.Style = .alert
|
||||||
public var alertActions: [AlertButtonModel]
|
public var actions: [UIAlertAction]
|
||||||
|
public var buttonModels: [AlertButtonModel]?
|
||||||
public var analyticsData: JSONValueDictionary?
|
public var analyticsData: JSONValueDictionary?
|
||||||
|
public var id: String
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(title: String, message: String, alertActions: [AlertButtonModel], style: UIAlertController.Style = .alert) {
|
public init(title: String, message: String, actions: [UIAlertAction], style: UIAlertController.Style = .alert, id: String = UUID().uuidString) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.message = message
|
self.message = message
|
||||||
self.alertActions = alertActions
|
self.actions = actions
|
||||||
self.style = style
|
self.style = style
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(title: String, message: String, buttonModels: [AlertButtonModel], style: UIAlertController.Style = .alert, delegateObject: DelegateObject?, id: String = UUID().uuidString) {
|
||||||
|
self.title = title
|
||||||
|
self.message = message
|
||||||
|
self.buttonModels = buttonModels
|
||||||
|
actions = buttonModels.map({ alertButtonModel in
|
||||||
|
return alertButtonModel.generateAction(delegateObject: delegateObject)
|
||||||
|
})
|
||||||
|
self.style = style
|
||||||
|
self.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -93,30 +106,49 @@ public class AlertModel: Codable {
|
|||||||
case alertActions
|
case alertActions
|
||||||
case style
|
case style
|
||||||
case analyticsData
|
case analyticsData
|
||||||
|
case id
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Codec
|
// MARK: - Codec
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
let delegateObject = try decoder.get()
|
||||||
title = try typeContainer.decode(String.self, forKey: .title)
|
title = try typeContainer.decode(String.self, forKey: .title)
|
||||||
message = try typeContainer.decode(String.self, forKey: .message)
|
message = try typeContainer.decode(String.self, forKey: .message)
|
||||||
alertActions = try typeContainer.decode([AlertButtonModel].self, forKey: .alertActions)
|
buttonModels = try typeContainer.decode([AlertButtonModel].self, forKey: .alertActions)
|
||||||
|
actions = buttonModels!.map({ alertButtonModel in
|
||||||
|
return alertButtonModel.generateAction(delegateObject: delegateObject)
|
||||||
|
})
|
||||||
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
||||||
|
|
||||||
if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) {
|
if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) {
|
||||||
self.style = UIAlertController.Style(rawValue: style)
|
self.style = UIAlertController.Style(rawValue: style)
|
||||||
}
|
}
|
||||||
|
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
||||||
}
|
}
|
||||||
|
|
||||||
open func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(title, forKey: .title)
|
try container.encode(title, forKey: .title)
|
||||||
try container.encode(message, forKey: .message)
|
try container.encode(message, forKey: .message)
|
||||||
try container.encode(alertActions, forKey: .alertActions)
|
try container.encodeIfPresent(buttonModels, forKey: .alertActions)
|
||||||
try container.encode(style.rawValueString, forKey: .style)
|
try container.encode(style.rawValueString, forKey: .style)
|
||||||
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
||||||
|
try container.encode(id, forKey: .id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension AlertButtonModel {
|
||||||
|
func generateAction(with additionalData: [AnyHashable: Any]? = nil, delegateObject: DelegateObject? = nil, additionalHandling: ((AlertButtonModel, UIAlertAction)->())? = nil) -> UIAlertAction {
|
||||||
|
let alertAction = UIAlertAction(title: title, style: style) { action in
|
||||||
|
Task(priority: .userInitiated) {
|
||||||
|
try? await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: self.action, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
|
additionalHandling?(self, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alertAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -235,7 +235,9 @@ extension Tabs: UICollectionViewDelegateFlowLayout {
|
|||||||
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
||||||
guard let tabCell = cell as? TabItemCell else { return }
|
guard let tabCell = cell as? TabItemCell else { return }
|
||||||
if indexPath.row == selectedIndex {
|
if indexPath.row == selectedIndex {
|
||||||
moveSelectionLine(toIndex: indexPath, animated: false, cell: tabCell)
|
DispatchQueue.main.async {
|
||||||
|
self.moveSelectionLine(toIndex: indexPath, animated: false, cell: tabCell)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -496,7 +496,7 @@ import MVMCore
|
|||||||
errorObject.silentError = false
|
errorObject.silentError = false
|
||||||
}
|
}
|
||||||
|
|
||||||
MVMCoreUIActionHandler.shared()?.defaultHandleActionError(errorObject, additionalData: additionalData)
|
MVMCoreUIActionHandler.shared()?.defaultHandleActionError(errorObject, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -20,13 +20,6 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
|
|||||||
#import <MVMCoreUI/MVMCoreUILoggingHandler.h>
|
#import <MVMCoreUI/MVMCoreUILoggingHandler.h>
|
||||||
#import <MVMCoreUI/MVMCoreUIViewControllerMappingObject.h>
|
#import <MVMCoreUI/MVMCoreUIViewControllerMappingObject.h>
|
||||||
#import <MVMCoreUI/MVMCoreUIViewConstrainingProtocol.h>
|
#import <MVMCoreUI/MVMCoreUIViewConstrainingProtocol.h>
|
||||||
#import <MVMCoreUI/MVMCoreUIActionDelegateProtocol.h>
|
|
||||||
|
|
||||||
// Alert Handling
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertObject.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertOperation.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertHandler.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertDelegateProtocol.h>
|
|
||||||
|
|
||||||
#pragma mark - TopAlert
|
#pragma mark - TopAlert
|
||||||
#import <MVMCoreUI/MVMCoreGlobalTopAlertDelegateProtocol.h>
|
#import <MVMCoreUI/MVMCoreGlobalTopAlertDelegateProtocol.h>
|
||||||
|
|||||||
@ -231,7 +231,6 @@ open class CoreUIModelMapping: ModelMapping {
|
|||||||
|
|
||||||
open override class func registerActions() {
|
open override class func registerActions() {
|
||||||
super.registerActions()
|
super.registerActions()
|
||||||
ModelRegistry.register(handler: ActionPopupHandler.self, for: ActionPopupModel.self)
|
|
||||||
ModelRegistry.register(handler: ActionAlertHandler.self, for: ActionAlertModel.self)
|
ModelRegistry.register(handler: ActionAlertHandler.self, for: ActionAlertModel.self)
|
||||||
ModelRegistry.register(handler: ActionTopAlertHandler.self, for: ActionTopAlertModel.self)
|
ModelRegistry.register(handler: ActionTopAlertHandler.self, for: ActionTopAlertModel.self)
|
||||||
ModelRegistry.register(handler: ActionCollapseNotificationHandler.self, for: ActionCollapseNotificationModel.self)
|
ModelRegistry.register(handler: ActionCollapseNotificationHandler.self, for: ActionCollapseNotificationModel.self)
|
||||||
|
|||||||
@ -7,9 +7,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
@objcMembers open class CoreUIObject: MVMCoreObject {
|
@objcMembers open class CoreUIObject: MVMCoreObject {
|
||||||
public var globalTopAlertDelegate: MVMCoreGlobalTopAlertDelegateProtocol?
|
public var globalTopAlertDelegate: MVMCoreGlobalTopAlertDelegateProtocol?
|
||||||
|
public var alertHandler: AlertHandler?
|
||||||
|
public var topNotificationHandler: TopNotificationHandler?
|
||||||
|
|
||||||
open override func defaultInitialSetup() {
|
open override func defaultInitialSetup() {
|
||||||
CoreUIModelMapping.registerObjects()
|
CoreUIModelMapping.registerObjects()
|
||||||
@ -20,5 +23,7 @@ import UIKit
|
|||||||
session = MVMCoreUISession()
|
session = MVMCoreUISession()
|
||||||
viewControllerMapping = MVMCoreUIViewControllerMappingObject()
|
viewControllerMapping = MVMCoreUIViewControllerMappingObject()
|
||||||
loggingDelegate = MVMCoreUILoggingHandler()
|
loggingDelegate = MVMCoreUILoggingHandler()
|
||||||
|
alertHandler = AlertHandler()
|
||||||
|
topNotificationHandler = TopNotificationHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
//
|
|
||||||
// MVMCoreUIActionDelegateProtocol.h
|
|
||||||
// MVMCoreUI
|
|
||||||
//
|
|
||||||
// Created by Scott Pfeil on 10/28/20.
|
|
||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
|
||||||
//
|
|
||||||
@import MVMCore.MVMCoreActionDelegateProtocol;
|
|
||||||
@class MVMCoreAlertObject;
|
|
||||||
|
|
||||||
@protocol MVMCoreUIActionDelegateProtocol <MVMCoreActionDelegateProtocol>
|
|
||||||
|
|
||||||
// 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
|
|
||||||
@ -38,13 +38,13 @@ import SafariServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Logs the error and shows a popup if the error is not silent.
|
/// Logs the error and shows a popup if the error is not silent.
|
||||||
open override func defaultHandleActionError(_ error: MVMCoreErrorObject, additionalData: [AnyHashable : Any]?) {
|
open override func defaultHandleActionError(_ error: MVMCoreErrorObject, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject? = nil) {
|
||||||
super.defaultHandleActionError(error, additionalData: additionalData)
|
super.defaultHandleActionError(error, additionalData: additionalData)
|
||||||
guard !error.silentError else { return }
|
guard !error.silentError else { return }
|
||||||
error.silentError = true // Silence if this error is triggered again. (Legacy action handler flow.)
|
error.silentError = true // Silence if this error is triggered again. (Legacy action handler flow.)
|
||||||
Task(priority: .userInitiated) { @MainActor in
|
Task(priority: .userInitiated) { @MainActor in
|
||||||
let alertObject = MVMCoreAlertObject.init(popupAlertWithError: error, isGreedy: false)!
|
let alertAction = ActionAlertModel(alert: AlertModel(title: error.title ?? "", message: "\(String(describing: error.messageToDisplay)) (\(error.stringErrorCode()))", buttonModels: [AlertButtonModel(MVMCoreGetterUtility.hardcodedString(withKey: HardcodedOK) ?? "OK", ActionCancelModel())], delegateObject: delegateObject))
|
||||||
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
|
try? await MVMCoreUIActionHandler.shared()?.handleAction(with: alertAction, additionalData: additionalData, delegateObject: delegateObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
open class MVMCoreUIDelegateObject: DelegateObject {
|
open class MVMCoreUIDelegateObject: DelegateObject {
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ open class MVMCoreUIDelegateObject: DelegateObject {
|
|||||||
public weak var uiTextViewDelegate: UITextViewDelegate?
|
public weak var uiTextViewDelegate: UITextViewDelegate?
|
||||||
public weak var observingTextFieldDelegate: ObservingTextFieldDelegate?
|
public weak var observingTextFieldDelegate: ObservingTextFieldDelegate?
|
||||||
public weak var moleculeDelegate: MoleculeDelegateProtocol?
|
public weak var moleculeDelegate: MoleculeDelegateProtocol?
|
||||||
public weak var alertDelegate: (MVMCoreAlertDelegateProtocol & NSObjectProtocol)?
|
public weak var alertDelegate: (AlertDelegateProtocol & NSObjectProtocol)?
|
||||||
public weak var topAlertDelegate: (MVMCoreTopAlertDelegateProtocol & NSObjectProtocol)?
|
public weak var topAlertDelegate: (MVMCoreTopAlertDelegateProtocol & NSObjectProtocol)?
|
||||||
|
|
||||||
open override func setAll(withDelegate delegate: Any) {
|
open override func setAll(withDelegate delegate: Any) {
|
||||||
@ -28,7 +28,7 @@ open class MVMCoreUIDelegateObject: DelegateObject {
|
|||||||
uiTextViewDelegate = delegate as? UITextViewDelegate
|
uiTextViewDelegate = delegate as? UITextViewDelegate
|
||||||
observingTextFieldDelegate = delegate as? ObservingTextFieldDelegate
|
observingTextFieldDelegate = delegate as? ObservingTextFieldDelegate
|
||||||
moleculeDelegate = delegate as? MoleculeDelegateProtocol
|
moleculeDelegate = delegate as? MoleculeDelegateProtocol
|
||||||
alertDelegate = delegate as? (MVMCoreAlertDelegateProtocol & NSObjectProtocol)
|
alertDelegate = delegate as? (AlertDelegateProtocol & NSObjectProtocol)
|
||||||
topAlertDelegate = delegate as? (MVMCoreTopAlertDelegateProtocol & NSObjectProtocol)
|
topAlertDelegate = delegate as? (MVMCoreTopAlertDelegateProtocol & NSObjectProtocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// MVMCoreUILoggingDelegateProtocol.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Scott Pfeil on 4/13/23.
|
||||||
|
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MVMCore
|
||||||
|
|
||||||
|
public protocol MVMCoreUILoggingDelegateProtocol: MVMCoreLoggingDelegateProtocol {
|
||||||
|
func logAlert(with alertObject: AlertObject)
|
||||||
|
}
|
||||||
@ -10,7 +10,6 @@
|
|||||||
@import MVMCore.NSDictionary_MFConvenience;
|
@import MVMCore.NSDictionary_MFConvenience;
|
||||||
@import MVMCore.MVMCoreGetterUtility;
|
@import MVMCore.MVMCoreGetterUtility;
|
||||||
@import MVMCore.MVMCoreJSONConstants;
|
@import MVMCore.MVMCoreJSONConstants;
|
||||||
#import "MVMCoreAlertHandler.h"
|
|
||||||
|
|
||||||
NSUInteger const TopAlertDismissTime = 5;
|
NSUInteger const TopAlertDismissTime = 5;
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#import "MVMCoreTopAlertOperation.h"
|
#import "MVMCoreTopAlertOperation.h"
|
||||||
#import "MVMCoreTopAlertObject.h"
|
#import "MVMCoreTopAlertObject.h"
|
||||||
#import "MVMCoreAlertHandler.h"
|
|
||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
#import <MVMCoreUI/MVMCoreUISplitViewController.h>
|
#import <MVMCoreUI/MVMCoreUISplitViewController.h>
|
||||||
|
|
||||||
@ -31,6 +30,9 @@
|
|||||||
|
|
||||||
@property (nonatomic, strong) dispatch_source_t timerSource;
|
@property (nonatomic, strong) dispatch_source_t timerSource;
|
||||||
|
|
||||||
|
// A reference to the show operation so it can be cancelled.
|
||||||
|
@property (nonatomic, weak) NSOperation *operation;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MVMCoreTopAlertOperation
|
@implementation MVMCoreTopAlertOperation
|
||||||
@ -165,38 +167,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing if paused
|
// Do nothing if paused
|
||||||
if (!self.isPaused) {
|
if (self.isPaused) {
|
||||||
|
return;
|
||||||
// Display alert only if alerts aren't supressed.
|
|
||||||
if (![[MVMCoreAlertHandler sharedAlertHandler] mfAlertsSupressed]) {
|
|
||||||
|
|
||||||
// Show
|
|
||||||
if (![[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) {
|
|
||||||
|
|
||||||
// Needs to be a top alert view....
|
|
||||||
[self markAsFinished];
|
|
||||||
} else {
|
|
||||||
UIView <MVMCoreTopAlertViewProtocol>*topAlertView = [[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView];
|
|
||||||
[topAlertView showWithTopAlertObject:self.topAlertObject animationDelegate:self completionHandler:^(BOOL finished) {
|
|
||||||
|
|
||||||
self.displayed = YES;
|
|
||||||
if (self.isCancelled) {
|
|
||||||
|
|
||||||
// Cancelled, dismiss immediately.
|
|
||||||
[self dismissAlertView:YES];
|
|
||||||
} else if (self.isPaused) {
|
|
||||||
|
|
||||||
// Paused, dismiss for the time being if persistent.
|
|
||||||
[self dismissAlertView:YES];
|
|
||||||
} else {
|
|
||||||
[self updateDismissTimer];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
[self pause];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show
|
||||||
|
if (![[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) {
|
||||||
|
|
||||||
|
// Needs to be a top alert view....
|
||||||
|
[self markAsFinished];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIView <MVMCoreTopAlertViewProtocol>*topAlertView = [[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView];
|
||||||
|
self.operation = [topAlertView showWithTopAlertObject:self.topAlertObject animationDelegate:self completionHandler:^(BOOL finished) {
|
||||||
|
|
||||||
|
self.displayed = YES;
|
||||||
|
if (self.isCancelled) {
|
||||||
|
|
||||||
|
// Cancelled, dismiss immediately.
|
||||||
|
[self dismissAlertView:YES];
|
||||||
|
} else if (self.isPaused) {
|
||||||
|
|
||||||
|
// Paused, dismiss for the time being if persistent.
|
||||||
|
[self dismissAlertView:YES];
|
||||||
|
} else {
|
||||||
|
[self updateDismissTimer];
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the timer to dismiss the top alert.
|
/// Updates the timer to dismiss the top alert.
|
||||||
@ -231,6 +229,8 @@
|
|||||||
- (void)cancel {
|
- (void)cancel {
|
||||||
[super cancel];
|
[super cancel];
|
||||||
|
|
||||||
|
[self.operation cancel];
|
||||||
|
|
||||||
// Do nothing if animating.
|
// Do nothing if animating.
|
||||||
if (!self.isAnimating) {
|
if (!self.isAnimating) {
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
@optional
|
@optional
|
||||||
|
|
||||||
/// Show based on the object
|
/// Show based on the object
|
||||||
- (void)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler;
|
- (nonnull NSOperation *)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler;
|
||||||
|
|
||||||
/// Removes the notification
|
/// Removes the notification
|
||||||
- (void)hideAlertView:(BOOL)forceful completionHandler:(void (^ __nullable)(BOOL finished))completionHandler;
|
- (void)hideAlertView:(BOOL)forceful completionHandler:(void (^ __nullable)(BOOL finished))completionHandler;
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
#import "MVMCoreUITopAlertMainView.h"
|
#import "MVMCoreUITopAlertMainView.h"
|
||||||
@import MVMCore.MVMCoreDispatchUtility;
|
@import MVMCore.MVMCoreDispatchUtility;
|
||||||
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
|
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
|
||||||
#import <MVMCoreUI/MVMCoreAlertHandler.h>
|
|
||||||
@import MVMCore.MVMCoreBlockOperation;
|
@import MVMCore.MVMCoreBlockOperation;
|
||||||
@import MVMCore.MVMCoreNavigationHandler;
|
@import MVMCore.MVMCoreNavigationHandler;
|
||||||
#import "MFStyler.h"
|
#import "MFStyler.h"
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
@import MVMCore.MVMCoreDispatchUtility;
|
@import MVMCore.MVMCoreDispatchUtility;
|
||||||
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
|
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
|
||||||
#import "UIColor+MFConvenience.h"
|
#import "UIColor+MFConvenience.h"
|
||||||
#import <MVMCoreUI/MVMCoreAlertHandler.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
#import <MVMCoreUI/MVMCoreUI-Swift.h>
|
||||||
@import MVMCore.MVMCoreJSONConstants;
|
@import MVMCore.MVMCoreJSONConstants;
|
||||||
#import "MVMCoreUICommonViewsUtility.h"
|
#import "MVMCoreUICommonViewsUtility.h"
|
||||||
|
|||||||
@ -16,82 +16,20 @@ protocol StatusBarUI {
|
|||||||
|
|
||||||
public extension MVMCoreUITopAlertView {
|
public extension MVMCoreUITopAlertView {
|
||||||
|
|
||||||
/// Registers with the notification center to know when json is updated.
|
|
||||||
@objc func registerWithNotificationCenter() {
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getDelegateObject() -> MVMCoreUIDelegateObject {
|
|
||||||
// TODO: Top alert view is current delegate. Should move to current view controller eventually?
|
|
||||||
return MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks for new top alert json
|
|
||||||
@objc private func responseJSONUpdated(notification: Notification) {
|
|
||||||
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()?.hideTopAlertView(ofType: disableType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show any new top alert.
|
|
||||||
guard let responseJSON = loadObject.responseJSON,
|
|
||||||
let json = responseJSON.optionalDictionaryForKey(KeyTopAlert),
|
|
||||||
let model = decodeTopNotification(with: json, delegateObject: getDelegateObject()) else { return }
|
|
||||||
showTopAlert(with: model)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decodes the json into a TopNotificationModel
|
|
||||||
private func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? {
|
|
||||||
do {
|
|
||||||
return try TopNotificationModel.decode(json: json, delegateObject: delegateObject)
|
|
||||||
} catch {
|
|
||||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") {
|
|
||||||
MVMCoreUILoggingHandler.addError(toLog: errorObject)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shows the top alert with the model.
|
|
||||||
func showTopAlert(with model: TopNotificationModel) {
|
|
||||||
let object = model.createTopAlertObject()
|
|
||||||
guard !checkAndUpdateExisting(with: object),
|
|
||||||
let operation = MVMCoreTopAlertOperation(topAlertObject: object) else { return }
|
|
||||||
MVMCoreAlertHandler.shared()?.add(operation)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shows the top alert with the json.
|
/// Shows the top alert with the json.
|
||||||
@objc func showTopAlert(with json: [AnyHashable: Any]) {
|
@objc func showTopAlert(with json: [AnyHashable: Any]) {
|
||||||
guard let model = decodeTopNotification(with: json, delegateObject: getDelegateObject()) else { return }
|
TopNotificationHandler.shared().showTopNotification(with: json)
|
||||||
showTopAlert(with: model)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks for existing top alert object of same type and updates it. Only happens for molecular top alerts. Returns true if we updated.
|
|
||||||
private func checkAndUpdateExisting(with topAlertObject: MVMCoreTopAlertObject) -> Bool {
|
|
||||||
guard let queue = MVMCoreAlertHandler.shared()?.topAlertQueue.operations else { return false }
|
|
||||||
for case let operation as MVMCoreTopAlertOperation in queue {
|
|
||||||
guard topAlertObject.json != nil,
|
|
||||||
operation.topAlertObject.type == topAlertObject.type else { continue }
|
|
||||||
operation.update(with: topAlertObject)
|
|
||||||
let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType
|
|
||||||
operation.updateDisplayable(byPageType: pageType)
|
|
||||||
MVMCoreAlertHandler.shared()?.reevaluteQueue()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the current top alert molecule with the new object
|
/// Updates the current top alert molecule with the new object
|
||||||
@objc func updateMolecule(with topAlertObject: MVMCoreTopAlertObject) {
|
@objc func updateMolecule(with topAlertObject: MVMCoreTopAlertObject) {
|
||||||
guard topAlertObject.type == self.topAlertObject?.type else { return }
|
guard topAlertObject.type == self.topAlertObject?.type else { return }
|
||||||
let delegateObject = getDelegateObject()
|
let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
||||||
guard let newJson = topAlertObject.json,
|
guard let newJson = topAlertObject.json,
|
||||||
let newModel = decodeTopNotification(with: newJson, delegateObject: delegateObject),
|
let newModel = TopNotificationHandler.shared().decodeTopNotification(with: newJson, delegateObject: delegateObject),
|
||||||
let newModelName = ModelRegistry.getMoleculeClass(newModel.molecule)?.nameForReuse(with: newModel.molecule, delegateObject),
|
let newModelName = ModelRegistry.getMoleculeClass(newModel.molecule)?.nameForReuse(with: newModel.molecule, delegateObject),
|
||||||
let currentJson = self.topAlertObject?.json,
|
let currentJson = self.topAlertObject?.json,
|
||||||
let currentModel = decodeTopNotification(with: currentJson, delegateObject: delegateObject),
|
let currentModel = TopNotificationHandler.shared().decodeTopNotification(with: currentJson, delegateObject: delegateObject),
|
||||||
let currentModelName = ModelRegistry.getMoleculeClass(currentModel.molecule)?.nameForReuse(with: currentModel.molecule, delegateObject),
|
let currentModelName = ModelRegistry.getMoleculeClass(currentModel.molecule)?.nameForReuse(with: currentModel.molecule, delegateObject),
|
||||||
newModelName == currentModelName,
|
newModelName == currentModelName,
|
||||||
let molecule = currentAlert as? MoleculeViewProtocol else {
|
let molecule = currentAlert as? MoleculeViewProtocol else {
|
||||||
|
|||||||
@ -21,8 +21,6 @@
|
|||||||
@import MVMCore.MVMCoreLoadHandler;
|
@import MVMCore.MVMCoreLoadHandler;
|
||||||
@import MVMCore.MVMCoreNavigationHandler;
|
@import MVMCore.MVMCoreNavigationHandler;
|
||||||
@import MVMCore.MVMCoreBlockOperation;
|
@import MVMCore.MVMCoreBlockOperation;
|
||||||
#import <MVMCoreUI/MVMCoreAlertObject.h>
|
|
||||||
#import <MVMCoreUI/MVMCoreAlertHandler.h>
|
|
||||||
@import MVMCore.NSDictionary_MFConvenience;
|
@import MVMCore.NSDictionary_MFConvenience;
|
||||||
@import MVMCore.MVMCoreRequestParameters;
|
@import MVMCore.MVMCoreRequestParameters;
|
||||||
@import MVMCore.MVMCoreJSONConstants;
|
@import MVMCore.MVMCoreJSONConstants;
|
||||||
@ -87,7 +85,6 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
|||||||
self.clipsToBounds = YES;
|
self.clipsToBounds = YES;
|
||||||
self.height = [self.heightAnchor constraintEqualToConstant:0];
|
self.height = [self.heightAnchor constraintEqualToConstant:0];
|
||||||
self.height.active = YES;
|
self.height.active = YES;
|
||||||
[self registerWithNotificationCenter];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateView:(CGFloat)size {
|
- (void)updateView:(CGFloat)size {
|
||||||
@ -144,7 +141,7 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showAlertView:(nullable UIView *)view topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
- (nonnull NSOperation *)showAlertView:(nullable UIView *)view topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
||||||
|
|
||||||
__weak typeof(self) weakSelf = self;
|
__weak typeof(self) weakSelf = self;
|
||||||
MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
|
MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
|
||||||
@ -179,6 +176,7 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
|||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
[[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
|
[[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
|
||||||
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -193,11 +191,11 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
|||||||
|
|
||||||
#pragma mark - MVMCoreTopAlertViewProtocol
|
#pragma mark - MVMCoreTopAlertViewProtocol
|
||||||
|
|
||||||
- (void)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
- (nonnull NSOperation *)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
||||||
|
|
||||||
self.animationDelegate = animationDelegate;
|
self.animationDelegate = animationDelegate;
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
__block NSOperation *operation = nil;
|
||||||
|
[MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
|
||||||
self.topAlertObject = topAlertObject;
|
self.topAlertObject = topAlertObject;
|
||||||
self.topAlertClearspotView = nil;
|
self.topAlertClearspotView = nil;
|
||||||
|
|
||||||
@ -211,8 +209,9 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
|||||||
self.currentAlertOverridingStatusBar = YES;
|
self.currentAlertOverridingStatusBar = YES;
|
||||||
[[MVMCoreUISplitViewController mainSplitViewController] setStatusBarBackgroundColor:statusBarColor style:statusBarStyle];
|
[[MVMCoreUISplitViewController mainSplitViewController] setStatusBarBackgroundColor:statusBarColor style:statusBarStyle];
|
||||||
}
|
}
|
||||||
[self showAlertView:view topAlertObject:topAlertObject completionHandler:completionHandler];
|
operation = [self showAlertView:view topAlertObject:topAlertObject completionHandler:completionHandler];
|
||||||
});
|
}];
|
||||||
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)hideAlertView:(BOOL)forceful completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
- (void)hideAlertView:(BOOL)forceful completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user