diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index dff3445..a90b168 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -21,7 +21,16 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 01C851CF23CF7B260021F976 /* JSONMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01C851CE23CF7B260021F976 /* JSONMap.swift */; }; + 01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01C851D023CF97FE0021F976 /* ActionBackModel.swift */; }; 01DF561421F90ADC00CC099B /* Dictionary+MFConvenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF561321F90ADC00CC099B /* Dictionary+MFConvenience.swift */; }; + 01F2A03623A80A7300D954D8 /* ActionModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03523A80A7300D954D8 /* ActionModelProtocol.swift */; }; + 01F2A03923A812DD00D954D8 /* ActionOpenUrlModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03823A812DD00D954D8 /* ActionOpenUrlModel.swift */; }; + 01F2A03B23A8159900D954D8 /* ActionOpenAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03A23A8159900D954D8 /* ActionOpenAppModel.swift */; }; + 01F2A04C23A82B1B00D954D8 /* ActionCallModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A04B23A82B1B00D954D8 /* ActionCallModel.swift */; }; + 01F2A04E23A82CF500D954D8 /* ActionPopupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A04D23A82CF500D954D8 /* ActionPopupModel.swift */; }; + 01F2A05023A82D0800D954D8 /* ActionTopAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A04F23A82D0800D954D8 /* ActionTopAlertModel.swift */; }; + 01F2A05223A8325100D954D8 /* ModelMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A05123A8325100D954D8 /* ModelMapping.swift */; }; 30349BF11FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30349BF21FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 30349BF01FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m */; }; 881D26931FCC9D180079C521 /* MVMCoreErrorObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */; }; @@ -39,6 +48,13 @@ 8876D5F31FB50AB000EB2E3D /* UIFont+MFSpacing.m in Sources */ = {isa = PBXBuildFile; fileRef = 8876D5E51FB50AB000EB2E3D /* UIFont+MFSpacing.m */; }; 8876D5F41FB50AB000EB2E3D /* UILabel+MFCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = 8876D5E61FB50AB000EB2E3D /* UILabel+MFCustom.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8876D5F51FB50AB000EB2E3D /* UILabel+MFCustom.m in Sources */ = {isa = PBXBuildFile; fileRef = 8876D5E71FB50AB000EB2E3D /* UILabel+MFCustom.m */; }; + 946EE1A3237B59C30036751F /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1A2237B59C30036751F /* Model.swift */; }; + 946EE1A7237B5B1C0036751F /* ModelRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1A6237B5B1C0036751F /* ModelRegistry.swift */; }; + 946EE1AB237B5C940036751F /* Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1AA237B5C940036751F /* Decoder.swift */; }; + 946EE1B0237B5EF70036751F /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1AF237B5EF70036751F /* JSONHelper.swift */; }; + 946EE1B2237B5F260036751F /* JSONValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1B1237B5F260036751F /* JSONValue.swift */; }; + 946EE1B4237B619D0036751F /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1B3237B619D0036751F /* Encoder.swift */; }; + 946EE1BC237B691A0036751F /* ActionOpenPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1BB237B691A0036751F /* ActionOpenPageModel.swift */; }; A332F33F20C7231700DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = A332F33E20C7231600DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF1201832108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1201812108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF26DDAE1FCE6A37004E8F65 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = AF26DDB01FCE6A37004E8F65 /* Localizable.strings */; }; @@ -142,11 +158,23 @@ AFFCFA681FCCC0D700FD0730 /* MVMCoreLoadingViewControllerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFFCFA641FCCC0D600FD0730 /* MVMCoreLoadingViewControllerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D282AAB62240085300C46919 /* MVMCoreGetterUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB52240085300C46919 /* MVMCoreGetterUtility+Extension.swift */; }; D282AAB82240342D00C46919 /* NSNumber+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB72240342D00C46919 /* NSNumber+Extension.swift */; }; + D2DEDCB723C63F3B00C44CC4 /* Clamping.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */; }; + D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */; }; + D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCBA23C65BC300C44CC4 /* Percent.swift */; }; D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 01C851CE23CF7B260021F976 /* JSONMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONMap.swift; sourceTree = ""; }; + 01C851D023CF97FE0021F976 /* ActionBackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionBackModel.swift; sourceTree = ""; }; 01DF561321F90ADC00CC099B /* Dictionary+MFConvenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+MFConvenience.swift"; sourceTree = ""; }; + 01F2A03523A80A7300D954D8 /* ActionModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelProtocol.swift; sourceTree = ""; }; + 01F2A03823A812DD00D954D8 /* ActionOpenUrlModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenUrlModel.swift; sourceTree = ""; }; + 01F2A03A23A8159900D954D8 /* ActionOpenAppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenAppModel.swift; sourceTree = ""; }; + 01F2A04B23A82B1B00D954D8 /* ActionCallModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCallModel.swift; sourceTree = ""; }; + 01F2A04D23A82CF500D954D8 /* ActionPopupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionPopupModel.swift; sourceTree = ""; }; + 01F2A04F23A82D0800D954D8 /* ActionTopAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionTopAlertModel.swift; sourceTree = ""; }; + 01F2A05123A8325100D954D8 /* ModelMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMapping.swift; sourceTree = ""; }; 0A11030B20864F94008ADD90 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 0A11030C20864F9A008ADD90 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = ""; }; 30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionTimeHandler.h; sourceTree = ""; }; @@ -168,6 +196,13 @@ 8876D5E51FB50AB000EB2E3D /* UIFont+MFSpacing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+MFSpacing.m"; sourceTree = ""; }; 8876D5E61FB50AB000EB2E3D /* UILabel+MFCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILabel+MFCustom.h"; sourceTree = ""; }; 8876D5E71FB50AB000EB2E3D /* UILabel+MFCustom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILabel+MFCustom.m"; sourceTree = ""; }; + 946EE1A2237B59C30036751F /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; + 946EE1A6237B5B1C0036751F /* ModelRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelRegistry.swift; sourceTree = ""; }; + 946EE1AA237B5C940036751F /* Decoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decoder.swift; sourceTree = ""; }; + 946EE1AF237B5EF70036751F /* JSONHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONHelper.swift; sourceTree = ""; }; + 946EE1B1237B5F260036751F /* JSONValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONValue.swift; sourceTree = ""; }; + 946EE1B3237B619D0036751F /* Encoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encoder.swift; sourceTree = ""; }; + 946EE1BB237B691A0036751F /* ActionOpenPageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenPageModel.swift; sourceTree = ""; }; A332F33E20C7231600DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewControllerAnimatedTransitioning.h; sourceTree = ""; }; AF1201812108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewManagerViewControllerProtocol.h; sourceTree = ""; }; AF26DDAF1FCE6A37004E8F65 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; @@ -275,6 +310,9 @@ AFFCFA641FCCC0D600FD0730 /* MVMCoreLoadingViewControllerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoadingViewControllerProtocol.h; sourceTree = ""; }; D282AAB52240085300C46919 /* MVMCoreGetterUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreGetterUtility+Extension.swift"; sourceTree = ""; }; D282AAB72240342D00C46919 /* NSNumber+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSNumber+Extension.swift"; sourceTree = ""; }; + D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clamping.swift; sourceTree = ""; }; + D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInterval.swift; sourceTree = ""; }; + D2DEDCBA23C65BC300C44CC4 /* Percent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Percent.swift; sourceTree = ""; }; D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateObject.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -310,6 +348,7 @@ 8876D5CB1FB50A9E00EB2E3D /* MVMCore */ = { isa = PBXGroup; children = ( + 946EE19B237B4DB80036751F /* Models */, AFBB96311FBA341E0008D868 /* Constants */, 8876D5D41FB50AAB00EB2E3D /* Utility */, AF43A7191FC5BE9E008E9347 /* MainProtocols */, @@ -338,6 +377,7 @@ 881D26901FCC9D180079C521 /* MVMCoreOperation.m */, AFEA17A6209B6A1C00BC6740 /* MVMCoreBlockOperation.h */, AFEA17A7209B6A1C00BC6740 /* MVMCoreBlockOperation.m */, + D2DEDCB523C63F1800C44CC4 /* PropertyWrappers */, AFBB96E71FBA4A260008D868 /* HardCodedServerResponse */, AFBB96AB1FBA3B590008D868 /* Helpers */, ); @@ -363,6 +403,61 @@ path = Categories; sourceTree = ""; }; + 946EE19B237B4DB80036751F /* Models */ = { + isa = PBXGroup; + children = ( + 01F2A05123A8325100D954D8 /* ModelMapping.swift */, + 946EE1B6237B66630036751F /* ActionType */, + 946EE1A9237B5C720036751F /* Extensions */, + 946EE1A8237B5C650036751F /* Model */, + 946EE1AC237B5CB10036751F /* JSON */, + ); + path = Models; + sourceTree = ""; + }; + 946EE1A8237B5C650036751F /* Model */ = { + isa = PBXGroup; + children = ( + 946EE1A2237B59C30036751F /* Model.swift */, + 946EE1A6237B5B1C0036751F /* ModelRegistry.swift */, + ); + path = Model; + sourceTree = ""; + }; + 946EE1A9237B5C720036751F /* Extensions */ = { + isa = PBXGroup; + children = ( + 946EE1AA237B5C940036751F /* Decoder.swift */, + 946EE1B3237B619D0036751F /* Encoder.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 946EE1AC237B5CB10036751F /* JSON */ = { + isa = PBXGroup; + children = ( + 946EE1AF237B5EF70036751F /* JSONHelper.swift */, + 946EE1B1237B5F260036751F /* JSONValue.swift */, + 01C851CE23CF7B260021F976 /* JSONMap.swift */, + ); + path = JSON; + sourceTree = ""; + }; + 946EE1B6237B66630036751F /* ActionType */ = { + isa = PBXGroup; + children = ( + 01F2A03523A80A7300D954D8 /* ActionModelProtocol.swift */, + 946EE1BB237B691A0036751F /* ActionOpenPageModel.swift */, + 01F2A03823A812DD00D954D8 /* ActionOpenUrlModel.swift */, + 01F2A03A23A8159900D954D8 /* ActionOpenAppModel.swift */, + 01F2A04B23A82B1B00D954D8 /* ActionCallModel.swift */, + 01F2A04D23A82CF500D954D8 /* ActionPopupModel.swift */, + 01F2A04F23A82D0800D954D8 /* ActionTopAlertModel.swift */, + 01C851D023CF97FE0021F976 /* ActionBackModel.swift */, + ); + path = ActionType; + sourceTree = ""; + }; AF26DDAB1FCE5CF2004E8F65 /* Strings */ = { isa = PBXGroup; children = ( @@ -593,6 +688,16 @@ path = LoadingOverlay; sourceTree = ""; }; + D2DEDCB523C63F1800C44CC4 /* PropertyWrappers */ = { + isa = PBXGroup; + children = ( + D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */, + D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */, + D2DEDCBA23C65BC300C44CC4 /* Percent.swift */, + ); + path = PropertyWrappers; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -767,13 +872,17 @@ files = ( AFED77A71FCCA29400BAE689 /* MVMCoreViewControllerProgrammaticMappingObject.m in Sources */, AFBB96A01FBA3A9A0008D868 /* MVMCoreAlertOperation.m in Sources */, + 946EE1A7237B5B1C0036751F /* ModelRegistry.swift in Sources */, AFBB96641FBA3A570008D868 /* MVMCoreLoadHandler.m in Sources */, AFFCFA671FCCC0D700FD0730 /* MVMCoreLoadingOverlayHandler.m in Sources */, AFBB968E1FBA3A9A0008D868 /* MVMCoreNavigationHandler.m in Sources */, D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */, + 01F2A03623A80A7300D954D8 /* ActionModelProtocol.swift in Sources */, AFBB96991FBA3A9A0008D868 /* MVMCoreAlertController.m in Sources */, 881D26941FCC9D180079C521 /* MVMCoreOperation.m in Sources */, AFED77A41FCCA29400BAE689 /* MVMCoreViewControllerMappingObject.m in Sources */, + 01C851CF23CF7B260021F976 /* JSONMap.swift in Sources */, + 01F2A04C23A82B1B00D954D8 /* ActionCallModel.swift in Sources */, 8876D5ED1FB50AB000EB2E3D /* NSDictionary+MFConvenience.m in Sources */, AFBB968C1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.m in Sources */, AFBB96BA1FBA3CEC0008D868 /* MVMCoreActionHandler.m in Sources */, @@ -782,17 +891,24 @@ D282AAB62240085300C46919 /* MVMCoreGetterUtility+Extension.swift in Sources */, AFBB965F1FBA3A570008D868 /* MFFreebeeOperation.m in Sources */, AFBB96901FBA3A9A0008D868 /* MVMCoreNavigationObject.m in Sources */, + 946EE1AB237B5C940036751F /* Decoder.swift in Sources */, + 946EE1BC237B691A0036751F /* ActionOpenPageModel.swift in Sources */, AFBB96A61FBA3A9A0008D868 /* MVMCoreTopAlertOperation.m in Sources */, 881D26931FCC9D180079C521 /* MVMCoreErrorObject.m in Sources */, + 946EE1B0237B5EF70036751F /* JSONHelper.swift in Sources */, 30349BF21FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m in Sources */, + D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */, 8876D5E91FB50AB000EB2E3D /* NSArray+MFConvenience.m in Sources */, + 946EE1B2237B5F260036751F /* JSONValue.swift in Sources */, AFBB96971FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m in Sources */, AFBB96581FBA3A570008D868 /* FreeBeeAuthObject.m in Sources */, + 01F2A04E23A82CF500D954D8 /* ActionPopupModel.swift in Sources */, AF43A5781FBA5B7C008E9347 /* MVMCoreJSONConstants.m in Sources */, AFBB96691FBA3A570008D868 /* MVMCoreRequestParameters.m in Sources */, AFED77A31FCCA29400BAE689 /* MVMCoreViewControllerNibMappingObject.m in Sources */, 8876D5EB1FB50AB000EB2E3D /* NSDecimalNumber+MFConvenience.m in Sources */, AFBB96A41FBA3A9A0008D868 /* MVMCoreTopAlertObject.m in Sources */, + 01F2A03923A812DD00D954D8 /* ActionOpenUrlModel.swift in Sources */, AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */, AFBB969C1FBA3A9A0008D868 /* MVMCoreAlertHandler.m in Sources */, AF43A5881FBB67D6008E9347 /* MVMCoreActionUtility.m in Sources */, @@ -800,20 +916,28 @@ AF43A57C1FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.m in Sources */, AFBB965D1FBA3A570008D868 /* MFFreebeeHandler.m in Sources */, AFEEE81F1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m in Sources */, + 01F2A05223A8325100D954D8 /* ModelMapping.swift in Sources */, AFBB969E1FBA3A9A0008D868 /* MVMCoreAlertObject.m in Sources */, 8876D5F51FB50AB000EB2E3D /* UILabel+MFCustom.m in Sources */, AFBB96B31FBA3B590008D868 /* MVMCoreGetterUtility.m in Sources */, AF43A7071FC4D7A2008E9347 /* MVMCoreObject.m in Sources */, + D2DEDCB723C63F3B00C44CC4 /* Clamping.swift in Sources */, 01DF561421F90ADC00CC099B /* Dictionary+MFConvenience.swift in Sources */, AFBB96B11FBA3B590008D868 /* MVMCoreDispatchUtility.m in Sources */, + 946EE1A3237B59C30036751F /* Model.swift in Sources */, + 01F2A05023A82D0800D954D8 /* ActionTopAlertModel.swift in Sources */, AFBB965B1FBA3A570008D868 /* FreeBeeUrlObject.m in Sources */, AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */, AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */, AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */, + 01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */, + 01F2A03B23A8159900D954D8 /* ActionOpenAppModel.swift in Sources */, AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */, AFBB96611FBA3A570008D868 /* MVMCoreLoadObject.m in Sources */, + 946EE1B4237B619D0036751F /* Encoder.swift in Sources */, AFBB96941FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.m in Sources */, AF43A5841FBB66DE008E9347 /* MVMCoreConstants.m in Sources */, + D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */, AFBB966A1FBA3A570008D868 /* MVMCoreLoadRequestOperation.m in Sources */, 8876D5F31FB50AB000EB2E3D /* UIFont+MFSpacing.m in Sources */, D282AAB82240342D00C46919 /* NSNumber+Extension.swift in Sources */, diff --git a/MVMCore/MVMCore/Models/ActionType/ActionBackModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionBackModel.swift new file mode 100644 index 0000000..7c903ff --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionBackModel.swift @@ -0,0 +1,18 @@ +// +// File.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 1/15/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionBackModel: ActionModelProtocol { + public static var identifier: String = "back" + public var actionType: String? + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionCallModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionCallModel.swift new file mode 100644 index 0000000..a579e63 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionCallModel.swift @@ -0,0 +1,23 @@ +// +// ActionCallModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionCallModel: ActionModelProtocol { + public static var identifier: String = "call" + public var actionType: String? + public var callNumber: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + public init(callNumber: String) { + self.callNumber = callNumber + } +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift new file mode 100644 index 0000000..5a01d35 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift @@ -0,0 +1,22 @@ +// +// ActionModelProtocol.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public enum ActionCodingKey: String, CodingKey { + case actionType +} + +public protocol ActionModelProtocol: Model { + var actionType: String? { get set } + var extraParameters: JSONValueDictionary? { get set } + var analyticsData: JSONValueDictionary? { get set } + + // Temporary fix till server changes + var title: String? { get set } +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionOpenAppModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionOpenAppModel.swift new file mode 100644 index 0000000..8cc9c58 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionOpenAppModel.swift @@ -0,0 +1,23 @@ +// +// ActionOpenAppModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionOpenAppModel: ActionModelProtocol { + public static var identifier: String = "openApp" + public var actionType: String? + public var appURL: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + public init(appURL: String) { + self.appURL = appURL + } +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionOpenPageModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionOpenPageModel.swift new file mode 100644 index 0000000..63c679f --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionOpenPageModel.swift @@ -0,0 +1,23 @@ +// +// ActionModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 10/3/19. +// Copyright © 2019 Suresh, Kamlesh. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionOpenPageModel: ActionModelProtocol { + public static var identifier: String = "openPage" + public var actionType: String? + public var pageType: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + public init(pageType: String) { + self.pageType = pageType + } +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionOpenUrlModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionOpenUrlModel.swift new file mode 100644 index 0000000..09299e6 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionOpenUrlModel.swift @@ -0,0 +1,30 @@ +// +// ActionOpenUrlModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionOpenUrlModel: ActionModelProtocol { + public static var identifier: String = "openURL" + public var actionType: String? + public var browserUrl: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + + //TODO: Should be removed in future releases. This should be MF specific. + //Missing params + public var openOauthWebView: Bool? + public var showNativeNavigation: Bool? + public var openInWebview: Bool? + + public init(browserUrl: String) { + self.browserUrl = browserUrl + } +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionPopupModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionPopupModel.swift new file mode 100644 index 0000000..899f782 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionPopupModel.swift @@ -0,0 +1,21 @@ +// +// ActionPopupModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionPopupModel: ActionModelProtocol { + public static var identifier: String = "popup" + public var actionType: String? + public var title: String? + public var pageType: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + public init(pageType: String) { + self.pageType = pageType + } +} diff --git a/MVMCore/MVMCore/Models/ActionType/ActionTopAlertModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionTopAlertModel.swift new file mode 100644 index 0000000..6da6491 --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/ActionTopAlertModel.swift @@ -0,0 +1,23 @@ +// +// ActionTopAlertModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionTopAlertModel: ActionModelProtocol { + public static var identifier: String = "topAlert" + public var actionType: String? + public var pageType: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + public init(pageType: String) { + self.pageType = pageType + } +} diff --git a/MVMCore/MVMCore/Models/Extensions/Decoder.swift b/MVMCore/MVMCore/Models/Extensions/Decoder.swift new file mode 100644 index 0000000..5435b1d --- /dev/null +++ b/MVMCore/MVMCore/Models/Extensions/Decoder.swift @@ -0,0 +1,64 @@ +// +// Decoder.swift +// MVMCore +// +// Created by Matt Brunce on 11/12/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public protocol AnyDecoder { + func decode(_ type: T.Type, from data: Data) throws -> T +} + +extension JSONDecoder: AnyDecoder {} +extension PropertyListDecoder: AnyDecoder {} + +extension Data { + public func decode(using decoder: AnyDecoder = JSONDecoder()) throws -> T { + return try decoder.decode(T.self, from: self) + } +} + +extension KeyedDecodingContainerProtocol { + public func decode(forKey key: Key) throws -> T { + return try decode(T.self, forKey: key) + } + + public func decode( + forKey key: Key, + default defaultExpression: @autoclosure () -> T + ) throws -> T { + return try decodeIfPresent(T.self, forKey: key) ?? defaultExpression() + } +} + +extension Decodable { + public static func decode(jsonDict: [String: Any]) throws -> Self { + let jsonData = try JSONSerialization.data(withJSONObject: jsonDict) + do { + return try jsonData.decode() + } catch { + throw JSONError.other(error: error) + } + } + + public static func decode(fileName: String, bundle: Bundle = Bundle.main) throws -> Self { + guard let path = bundle.path(forResource: fileName, ofType: ".json") else { + throw JSONError.pathNotFound + } + + guard let jsonData = try? Data(contentsOf: URL(fileURLWithPath: path)) else { + throw JSONError.data(path: path) + } + + do { + return try jsonData.decode() + } catch { + throw JSONError.other(error: error) + } + } +} + + diff --git a/MVMCore/MVMCore/Models/Extensions/Encoder.swift b/MVMCore/MVMCore/Models/Extensions/Encoder.swift new file mode 100644 index 0000000..db9c762 --- /dev/null +++ b/MVMCore/MVMCore/Models/Extensions/Encoder.swift @@ -0,0 +1,37 @@ +// +// Encoder.swift +// MVMCore +// +// Created by Matt Brunce on 11/12/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public protocol AnyEncoder { + func encode(_ value: T) throws -> Data +} + +extension JSONEncoder: AnyEncoder {} +extension PropertyListEncoder: AnyEncoder {} + +extension Encodable { + public func encode(using encoder: AnyEncoder = JSONEncoder()) throws -> Data { + return try encoder.encode(self) + } + + public func toJSON() -> JSONDictionary? { + guard let data = try? self.encode() else { return nil } + return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? JSONDictionary } + } + + public func toJSONString() -> String? { + guard let json = self.toJSON(), + let data = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted), + let string = String(data: data, encoding: .utf8) else { + return nil + } + return string + } +} + diff --git a/MVMCore/MVMCore/Models/JSON/JSONHelper.swift b/MVMCore/MVMCore/Models/JSON/JSONHelper.swift new file mode 100644 index 0000000..eebb6ab --- /dev/null +++ b/MVMCore/MVMCore/Models/JSON/JSONHelper.swift @@ -0,0 +1,18 @@ +// +// JSONHelper.swift +// MVMCore +// +// Created by Matt Brunce on 11/12/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public typealias JSONArray = [[String: Any]] +public typealias JSONDictionary = [String: Any] + +public enum JSONError: Error { + case pathNotFound + case data(path: String) + case other(error: Error) +} diff --git a/MVMCore/MVMCore/Models/JSON/JSONMap.swift b/MVMCore/MVMCore/Models/JSON/JSONMap.swift new file mode 100644 index 0000000..28a3ee8 --- /dev/null +++ b/MVMCore/MVMCore/Models/JSON/JSONMap.swift @@ -0,0 +1,31 @@ +// +// JSONMap.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 1/15/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import Foundation + + +@propertyWrapper +public struct JSONMap { + public var wrappedValue: JSONValueDictionary + + public init(wrappedValue value: JSONValueDictionary) { + self.wrappedValue = value + } +} + +extension JSONMap: Codable { + public init(from decoder: Decoder) throws { + let typeContainer = try decoder.singleValueContainer() + self.wrappedValue = try typeContainer.decode(JSONValueDictionary.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(wrappedValue) + } +} diff --git a/MVMCore/MVMCore/Models/JSON/JSONValue.swift b/MVMCore/MVMCore/Models/JSON/JSONValue.swift new file mode 100644 index 0000000..fcb50fd --- /dev/null +++ b/MVMCore/MVMCore/Models/JSON/JSONValue.swift @@ -0,0 +1,132 @@ +// +// JSONValue.swift +// MVMCore +// +// Created by Matt Brunce on 11/12/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public typealias JSONValueArray = [[String: JSONValue]] +public typealias JSONValueDictionary = [String: JSONValue] + +public enum JSONValueError: Error { + case encode +} + +extension Optional { + func or(_ other: Optional) -> Optional { + switch self { + case .none: return other + case .some: return self + } + } + + func resolve(with error: @autoclosure () -> Error) throws -> Wrapped { + switch self { + case .none: throw error() + case .some(let wrapped): return wrapped + } + } +} + +public enum JSONValue: Codable, Equatable { + case string(String) + case int(Int) + case double(Double) + case bool(Bool) + case object([String: JSONValue]) + case array([JSONValue]) + case null + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let value = ((try? container.decode(String.self)).map(JSONValue.string)) + .or((try? container.decode(Int.self)).map(JSONValue.int)) + .or((try? container.decode(Double.self)).map(JSONValue.double)) + .or((try? container.decode(Bool.self)).map(JSONValue.bool)) + .or((try? container.decode([String: JSONValue].self)).map(JSONValue.object)) + .or((try? container.decode([JSONValue].self)).map(JSONValue.array)) + + self = value ?? JSONValue.null + } + + func decode() throws -> T { + let encoded = try JSONEncoder().encode(self) + return try JSONDecoder().decode(T.self, from: encoded) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .string(let string): try container.encode(string) + case .int(let int): try container.encode(int) + case .double(let double): try container.encode(double) + case .bool(let bool): try container.encode(bool) + case .object(let object): try container.encode(object) + case .array(let array): try container.encode(array) + case .null: break + } + } +} + +public func ==(lhs: JSONValue, rhs: JSONValue) -> Bool { + let ld = try? lhs.encode() + let rd = try? lhs.encode() + return ld == rd +} + +extension JSONValue: ExpressibleByStringLiteral { + public init(stringLiteral value: String) { + self = .string(value) + } +} + +extension JSONValue: ExpressibleByIntegerLiteral { + public init(integerLiteral value: Int) { + self = .int(value) + } +} + +extension JSONValue: ExpressibleByFloatLiteral { + public init(floatLiteral value: Double) { + self = .double(value) + } +} + +extension JSONValue: ExpressibleByBooleanLiteral { + public init(booleanLiteral value: Bool) { + self = .bool(value) + } +} + +extension JSONValue: ExpressibleByArrayLiteral { + public init(arrayLiteral elements: JSONValue...) { + self = .array(elements) + } +} + +extension JSONValue: ExpressibleByDictionaryLiteral { + public init(dictionaryLiteral elements: (String, JSONValue)...) { + self = .object([String: JSONValue](uniqueKeysWithValues: elements)) + } +} + +extension Dictionary where Key == String, Value == Any { + public func toJSONValue() throws -> [String: JSONValue] { + let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted) + return try JSONDecoder().decode([String:JSONValue].self, from: data) + } +} + +extension Dictionary where Key == String, Value == JSONValue { + public func toJSONObject() throws -> JSONDictionary { + let encoded = try JSONEncoder().encode(self) + guard let json = try JSONSerialization.jsonObject(with: encoded, options: .mutableContainers) as? JSONDictionary else { + throw JSONValueError.encode + } + return json + } +} + + diff --git a/MVMCore/MVMCore/Models/Model/Model.swift b/MVMCore/MVMCore/Models/Model/Model.swift new file mode 100644 index 0000000..936c548 --- /dev/null +++ b/MVMCore/MVMCore/Models/Model/Model.swift @@ -0,0 +1,42 @@ +// +// Model.swift +// MVMCore +// +// Created by Matt Brunce on 11/12/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public protocol Model: Codable { + + static var identifier: String { get } + + /// Convenience function to decode to model using a keyed container. + static func decode(keyedContainer: KeyedDecodingContainer, codingKey: K) throws -> Self? + /// Convenience function to decode to model using an unkeyed container. + static func decode(unkeyedContainer: inout UnkeyedDecodingContainer) throws -> Self? + /// Convenience function to encode model using a keyed container. + func encode(keyedContainer: inout KeyedEncodingContainer, codingKey: K) throws + /// Convenience function to encode model using an unkeyed container. + func encode(unkeyedContainer: inout UnkeyedEncodingContainer) throws +} + +extension Model { + static public func decode(keyedContainer: KeyedDecodingContainer, codingKey: K) throws -> Self? { + return try keyedContainer.decodeIfPresent(self, forKey: codingKey) + } + + static public func decode(unkeyedContainer: inout UnkeyedDecodingContainer) throws -> Self? { + return try unkeyedContainer.decodeIfPresent(self) + } + + public func encode(keyedContainer: inout KeyedEncodingContainer, codingKey: K) throws { + try keyedContainer.encode(self, forKey: codingKey) + } + + public func encode(unkeyedContainer: inout UnkeyedEncodingContainer) throws { + try unkeyedContainer.encode(self) + } +} + diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift new file mode 100644 index 0000000..c92727f --- /dev/null +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -0,0 +1,194 @@ + +// +// ModelRegistry.swift +// MVMCore +// +// Created by Matt Brunce on 11/12/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +public struct ModelRegistry { + public enum Error: Swift.Error { + case keyNotFound + case encoderError + case decoderError + case decoderErrorObjectNotPresent + case decoderErrorModelNotMapped + } + + fileprivate static var types = [String: Model.Type]() + + /// Register the model. + public static func register(_ type: M.Type) { + types[M.identifier] = type + } + + public static func getType(for name: String) -> Model.Type? { + return types[name] + } +} + +extension KeyedDecodingContainer where Key: CodingKey { + + //MARK: - Decode + /// Decodes to a registered model based on the identifier + public func decodeModel(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> M { + guard let model: Model = try decodeModelIfPresent(codingKey: codingKey, typeCodingKey: typeCodingKey) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") + throw ModelRegistry.Error.decoderErrorObjectNotPresent + } + + if let model = model as? M { + return model + } else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderError: \(codingKey)") + throw ModelRegistry.Error.decoderError + } + } + + //MARK: - DecodeIfPresent + /// Decodes to a registered model based on the identifier, optional. + public func decodeModelIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> M? { + //get the identifier string + guard contains(codingKey), + let container = try? nestedContainer(keyedBy: TypeKey.self, forKey: codingKey), + let identifier = try? container.decodeIfPresent(String.self, forKey: typeCodingKey) else { + return nil + } + + //get the type + guard let type = ModelRegistry.getType(for: identifier) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "Model not mapped: \(identifier)") + throw ModelRegistry.Error.decoderErrorModelNotMapped + } + + //decode the type using the decoder + let model = try type.decode(keyedContainer: self, codingKey: codingKey) + + if let model = model as? M { + return model + } else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderError: \(codingKey)") + throw ModelRegistry.Error.decoderError + } + } + + /// Decodes an array of registered model based on the identifiers, optional. + public func decodeModelsIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [Model]? { + guard contains(codingKey), + var container = try? nestedUnkeyedContainer(forKey: codingKey) else { + return nil + } + return try container.decodeModelsIfPresent(typeCodingKey: typeCodingKey) + } + + /// Decodes an array of registered model based on the identifiers. + public func decodeModels(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [Model] { + guard let models: [Model] = try decodeModelsIfPresent(codingKey: codingKey, typeCodingKey: typeCodingKey) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") + throw ModelRegistry.Error.decoderErrorObjectNotPresent + } + return models + } + + /// Decodes an array with arrays of models based on the identifiers, optional. + public func decodeModels2DIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [[Model]]? { + guard contains(codingKey), + var container = try? nestedUnkeyedContainer(forKey: codingKey) else { + return nil + } + return try container.decodeModels2DIfPresent(typeCodingKey: typeCodingKey) + } + + /// Decodes an array with arrays of models based on the identifiers. + public func decodeModels2D(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [[Model]] { + guard let models: [[Model]] = try decodeModels2DIfPresent(codingKey: codingKey, typeCodingKey: typeCodingKey) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") + throw ModelRegistry.Error.decoderErrorObjectNotPresent + } + return models + } +} + +extension KeyedEncodingContainer where Key: CodingKey { + + /// Encodes a model, optional. + public mutating func encodeModelIfPresent(_ value: Model?, forKey key: KeyedEncodingContainer.Key) throws { + if let value = value { + let encoder = self.superEncoder(forKey: key) + try value.encode(to: encoder) + } + } + + /// Encodes a model. + public mutating func encodeModel(_ value: Model, forKey key: KeyedEncodingContainer.Key) throws { + let encoder = self.superEncoder(forKey: key) + try value.encode(to: encoder) + } + + /// Encodes an array of models + public mutating func encodeModels(_ list: [Model], forKey key:KeyedEncodingContainer.Key) throws { + try encodeModelsIfPresent(list, forKey: key) + } + + /// Encodes an array of models, optional, need instance type as input paramaeter list + public mutating func encodeModelsIfPresent(_ list: [Model]?, forKey key:KeyedEncodingContainer.Key) throws { + guard let list = list else { return } + var unkeyedContainer = self.nestedUnkeyedContainer(forKey: key) + for model in list { + try model.encode(unkeyedContainer: &unkeyedContainer) + } + } + + /// Convenience function for encoding the container into a list of lists of Models. needs instance type as input paramaeter list + public mutating func encodeModels2D(_ list: [[Model]]?, forKey key:KeyedEncodingContainer.Key) throws { + guard let list = list else { return } + var unkeyedContainer = self.nestedUnkeyedContainer(forKey: key) + for models in list { + var arrayunkeyedContainer = unkeyedContainer.nestedUnkeyedContainer() + for model in models { + try model.encode(unkeyedContainer: &arrayunkeyedContainer) + } + } + } +} + +extension UnkeyedDecodingContainer { + /// Decodes the container into a list of Models. + public mutating func decodeModelsIfPresent(typeCodingKey: TypeKey) throws -> [Model]? { + var models = [Model]() + var containerCopy = self + while !containerCopy.isAtEnd { + let nestedContainer = try containerCopy.nestedContainer(keyedBy: TypeKey.self) + if let identifier = try nestedContainer.decodeIfPresent(String.self, forKey: typeCodingKey) { + //get the type + guard let type = ModelRegistry.getType(for: identifier) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorModelNotMapped: \(identifier)") + throw ModelRegistry.Error.decoderErrorModelNotMapped + } + //now get the decoder to use for the type + let decoder = try self.superDecoder() + let model = try type.init(from: decoder) + models.append(model) + } + } + return models + } + + /// Convenience function for decoding the container into a list of lists of Models. + public mutating func decodeModels2DIfPresent(typeCodingKey: TypeKey) throws -> [[Model]]? { + var modelLists = [[Model]]() + var containerCopy = self + while !containerCopy.isAtEnd { + var arraycontainerCopy = try containerCopy.nestedUnkeyedContainer() + guard let models = try arraycontainerCopy.decodeModelsIfPresent(typeCodingKey: typeCodingKey) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorModelNotMapped: \(typeCodingKey)") + throw ModelRegistry.Error.decoderErrorModelNotMapped + } + modelLists.append(models) + } + return modelLists + } +} diff --git a/MVMCore/MVMCore/Models/ModelMapping.swift b/MVMCore/MVMCore/Models/ModelMapping.swift new file mode 100644 index 0000000..383e98e --- /dev/null +++ b/MVMCore/MVMCore/Models/ModelMapping.swift @@ -0,0 +1,21 @@ +// +// ModelMapping.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ModelMapping: NSObject { + public static func registerObjects() { + ModelRegistry.register(ActionOpenPageModel.self) + ModelRegistry.register(ActionOpenUrlModel.self) + ModelRegistry.register(ActionOpenAppModel.self) + ModelRegistry.register(ActionCallModel.self) + ModelRegistry.register(ActionPopupModel.self) + ModelRegistry.register(ActionTopAlertModel.self) + ModelRegistry.register(ActionBackModel.self) + } +} diff --git a/MVMCore/MVMCore/Session/MVMCoreSessionObject.m b/MVMCore/MVMCore/Session/MVMCoreSessionObject.m index d094b0b..52a8355 100644 --- a/MVMCore/MVMCore/Session/MVMCoreSessionObject.m +++ b/MVMCore/MVMCore/Session/MVMCoreSessionObject.m @@ -9,12 +9,14 @@ #import "MVMCoreSessionObject.h" #import "MVMCoreObject.h" #import "MVMCoreActionUtility.h" +#import @implementation MVMCoreSessionObject - (instancetype)init { if (self = [super init]) { self.session = [self createNSURLSession]; + [ModelMapping registerObjects]; } return self; } diff --git a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m index 9b28934..2f16308 100644 --- a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m +++ b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m @@ -104,7 +104,7 @@ + (nullable instancetype)createErrorObjectForNSError:(nonnull NSError *)error location:(nullable NSString *)location { - MVMCoreErrorObject *errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[error localizedDescription] code:[error code] domain:ErrorDomainSystem location:location]; + MVMCoreErrorObject *errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[error localizedDescription] messageToLog:[error description] code:[error code] domain:ErrorDomainSystem location:location]; if ([error.domain isEqualToString:NSURLErrorDomain]) { errorObject.systemDomain = error.domain; if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getNativeScreenForRequestError:requestObject:)]) { diff --git a/MVMCore/MVMCore/Utility/PropertyWrappers/Clamping.swift b/MVMCore/MVMCore/Utility/PropertyWrappers/Clamping.swift new file mode 100644 index 0000000..b8bed45 --- /dev/null +++ b/MVMCore/MVMCore/Utility/PropertyWrappers/Clamping.swift @@ -0,0 +1,26 @@ +// +// Clamping.swift +// MVMCore +// +// Created by Scott Pfeil on 1/8/20. +// Copyright © 2020 myverizon. All rights reserved. +// +// Clamps the value between a given range. + +import Foundation + +@propertyWrapper +public struct Clamping { + private var value: Value + private let range: ClosedRange + + public init(range: ClosedRange) { + self.value = range.lowerBound + self.range = range + } + + public var wrappedValue: Value { + get { value } + set { value = min(max(range.lowerBound, newValue), range.upperBound) } + } +} diff --git a/MVMCore/MVMCore/Utility/PropertyWrappers/Percent.swift b/MVMCore/MVMCore/Utility/PropertyWrappers/Percent.swift new file mode 100644 index 0000000..2116306 --- /dev/null +++ b/MVMCore/MVMCore/Utility/PropertyWrappers/Percent.swift @@ -0,0 +1,31 @@ +// +// Progress.swift +// MVMCore +// +// Created by Scott Pfeil on 1/8/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import Foundation + +@propertyWrapper +public struct Percent { + @Clamping(range: 0...100) + public var wrappedValue: CGFloat + + public init(wrappedValue value: CGFloat) { + self.wrappedValue = value + } +} + +extension Percent: Codable { + public init(from decoder: Decoder) throws { + let typeContainer = try decoder.singleValueContainer() + self.wrappedValue = try typeContainer.decode(CGFloat.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(wrappedValue) + } +} diff --git a/MVMCore/MVMCore/Utility/PropertyWrappers/UnitInterval.swift b/MVMCore/MVMCore/Utility/PropertyWrappers/UnitInterval.swift new file mode 100644 index 0000000..cf25308 --- /dev/null +++ b/MVMCore/MVMCore/Utility/PropertyWrappers/UnitInterval.swift @@ -0,0 +1,20 @@ +// +// UnitInterval.swift +// MVMCore +// +// Created by Scott Pfeil on 1/8/20. +// Copyright © 2020 myverizon. All rights reserved. +// +// Clamps the value between 0 and 1 + +import Foundation + +@propertyWrapper +public struct UnitInterval { + @Clamping(range: 0...1) + public var wrappedValue: Value + + public init(wrappedValue value: Value) { + self.wrappedValue = value + } +}