Compare commits

..

No commits in common. "develop" and "vds" have entirely different histories.
develop ... vds

126 changed files with 5734 additions and 5256 deletions

24
.gitignore vendored
View File

@ -10,21 +10,19 @@ mobilefirst_ios
mvm_core mvm_core
mfprepayshop_ios mfprepayshop_ios
mvm_core_ui mvm_core_ui
chatbot_ios
mvmreactnative mvmreactnative
mvm_5g_ios
mvm_dhc_ios
vds_ios
# Exclude all frameworks # frameworks
SharedFrameworks/* contentTransferFramework.framework
ActivationFramework.framework
# Exception to the rule above (Keeps the folder around) RemoteView.framework
!SharedFrameworks/.gitkeep RemoteViewCore.framework
RemoteViewReplayKit.framework
VDSTypographyTokens.framework MVMAnimationFramework.framework
VDSFormControlsTokens.framework VZAnalytics.framework
VDSColorTokens.framework VZWAuthentication.framework
CardinalMobile.framework
MVDRetailFramework.framework
__MACOSX __MACOSX

View File

@ -2,7 +2,10 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:vds_ios/VDS.xcodeproj"> location = "group:VDSSample/VDSSample.xcodeproj">
</FileRef>
<FileRef
location = "group:vds/VDS.xcodeproj">
</FileRef> </FileRef>
<FileRef <FileRef
location = "group:mvm_core/MVMCore/MVMCore.xcodeproj"> location = "group:mvm_core/MVMCore/MVMCore.xcodeproj">

View File

@ -18,20 +18,16 @@
name = UpdateDependency; name = UpdateDependency;
productName = UpdateDependency; productName = UpdateDependency;
}; };
EA985CBC298AE8CB00F2FF2E /* Artifactory */ = {
isa = PBXAggregateTarget;
buildConfigurationList = EA985CBF298AE8CC00F2FF2E /* Build configuration list for PBXAggregateTarget "Artifactory" */;
buildPhases = (
EA985CC0298AE8D000F2FF2E /* ShellScript */,
);
dependencies = (
);
name = Artifactory;
productName = Artifactory;
};
/* End PBXAggregateTarget section */ /* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
D21B3A27259B93ED001483DC /* SelfSizingCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B3A25259B93ED001483DC /* SelfSizingCollectionView.swift */; };
D2431DEB25E93A4F001C7AAC /* buttimag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2431DEA25E93A4F001C7AAC /* buttimag.swift */; };
D27564B62590FADB003CA713 /* ListDeviceRightVariableCaretModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27564B42590FADB003CA713 /* ListDeviceRightVariableCaretModel.swift */; };
D27564B72590FADB003CA713 /* ListDeviceRightVariableCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27564B52590FADB003CA713 /* ListDeviceRightVariableCaret.swift */; };
D27564C825939E91003CA713 /* LinkCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27564C525939E91003CA713 /* LinkCollectionViewCell.swift */; };
D27564C925939E91003CA713 /* Links.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27564C625939E91003CA713 /* Links.swift */; };
D27564CA25939E91003CA713 /* LinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27564C725939E91003CA713 /* LinksModel.swift */; };
D29C557825BF1F340082E7D6 /* JSONCreatorActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */; }; D29C557825BF1F340082E7D6 /* JSONCreatorActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */; };
D2B1E3F322F4A68F0065F95C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */; }; D2B1E3F322F4A68F0065F95C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */; };
D2B1E3F522F4A68F0065F95C /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3F422F4A68F0065F95C /* MasterViewController.swift */; }; D2B1E3F522F4A68F0065F95C /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3F422F4A68F0065F95C /* MasterViewController.swift */; };
@ -40,15 +36,53 @@
D2B1E3FC22F4A6930065F95C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E3FB22F4A6930065F95C /* Assets.xcassets */; }; D2B1E3FC22F4A6930065F95C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E3FB22F4A6930065F95C /* Assets.xcassets */; };
D2B1E3FF22F4A6930065F95C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E3FD22F4A6930065F95C /* LaunchScreen.storyboard */; }; D2B1E3FF22F4A6930065F95C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E3FD22F4A6930065F95C /* LaunchScreen.storyboard */; };
D2B1E40A22F4C9F00065F95C /* JSON in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E40922F4C9F00065F95C /* JSON */; }; D2B1E40A22F4C9F00065F95C /* JSON in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E40922F4C9F00065F95C /* JSON */; };
D2FC4FAD25897ACB00061EA4 /* StepModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FC4FA925897ACB00061EA4 /* StepModel.swift */; };
D2FC4FAE25897ACB00061EA4 /* OrderTrackerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FC4FAA25897ACB00061EA4 /* OrderTrackerModel.swift */; };
D2FC4FAF25897ACB00061EA4 /* Step.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FC4FAB25897ACB00061EA4 /* Step.swift */; };
D2FC4FB025897ACB00061EA4 /* OrderTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FC4FAC25897ACB00061EA4 /* OrderTracker.swift */; };
EA09CDBD282C3FD800A7835F /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA09CDBC282C3FD800A7835F /* CoreBluetooth.framework */; }; EA09CDBD282C3FD800A7835F /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA09CDBC282C3FD800A7835F /* CoreBluetooth.framework */; };
EA09CDD1282C40CC00A7835F /* MFFGHSBluetoothPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDBE282C40CB00A7835F /* MFFGHSBluetoothPair.swift */; };
EA09CDD2282C40CC00A7835F /* GMFGBluetoothPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDC0282C40CB00A7835F /* GMFGBluetoothPair.swift */; };
EA09CDD6282C40CC00A7835F /* GMFGConstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDC4282C40CB00A7835F /* GMFGConstant.swift */; };
EA09CDD8282C40CC00A7835F /* GMFGBLEHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDC7282C40CC00A7835F /* GMFGBLEHandlerProtocol.swift */; };
EA09CDD9282C40CC00A7835F /* GMFG5GCBandSignalHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDC9282C40CC00A7835F /* GMFG5GCBandSignalHandler.swift */; };
EA09CDDA282C40CC00A7835F /* GMFGOperationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDCA282C40CC00A7835F /* GMFGOperationHandler.swift */; };
EA09CDDB282C40CC00A7835F /* GMFGPublicInternetAccessHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDCB282C40CC00A7835F /* GMFGPublicInternetAccessHandler.swift */; };
EA09CDDC282C40CC00A7835F /* GMFGFotaHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDCC282C40CC00A7835F /* GMFGFotaHandler.swift */; };
EA09CDDD282C40CC00A7835F /* GMFGSpeedTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDCD282C40CC00A7835F /* GMFGSpeedTestHandler.swift */; };
EA09CDDE282C40CC00A7835F /* GMFG5GSignalHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDCE282C40CC00A7835F /* GMFG5GSignalHandler.swift */; };
EA09CDDF282C40CC00A7835F /* GMFGRouterWifiHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDCF282C40CC00A7835F /* GMFGRouterWifiHandler.swift */; };
EA09CDE6282C416C00A7835F /* BluetoothDebuggableProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDE2282C416C00A7835F /* BluetoothDebuggableProtocol.swift */; };
EA09CDE7282C416C00A7835F /* MulticastDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDE3282C416C00A7835F /* MulticastDelegate.swift */; };
EA09CDE8282C416C00A7835F /* BluetoothDebugger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDE4282C416C00A7835F /* BluetoothDebugger.swift */; };
EA09CDE9282C416C00A7835F /* BluetoothDebuggerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDE5282C416C00A7835F /* BluetoothDebuggerView.swift */; };
EA09CDEB282C422900A7835F /* GMFGStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDEA282C422900A7835F /* GMFGStorageManager.swift */; };
EA09CDED282C423F00A7835F /* GMFGLocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDEC282C423E00A7835F /* GMFGLocationManager.swift */; };
EA09CDEF282C429800A7835F /* GMFGTestScreenData.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDEE282C429800A7835F /* GMFGTestScreenData.swift */; };
EA09CDF8282C430400A7835F /* BluetoothPairingProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDF1282C430400A7835F /* BluetoothPairingProtocol.swift */; };
EA09CDF9282C430400A7835F /* BluetoothPairableProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDF2282C430400A7835F /* BluetoothPairableProtocol.swift */; };
EA09CDFA282C430400A7835F /* BluetoothConfigModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDF4282C430400A7835F /* BluetoothConfigModel.swift */; };
EA09CDFB282C430400A7835F /* PeripheralModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDF5282C430400A7835F /* PeripheralModel.swift */; };
EA09CDFC282C430400A7835F /* CharacteristicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDF6282C430400A7835F /* CharacteristicModel.swift */; };
EA09CDFD282C430400A7835F /* ServiceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDF7282C430400A7835F /* ServiceModel.swift */; };
EA09CDFF282C437C00A7835F /* MFFGHSAnalyticsProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CDFE282C437C00A7835F /* MFFGHSAnalyticsProtocol.swift */; };
EA09CE01282C43E800A7835F /* KeyedDecodingContainer+Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CE00282C43E800A7835F /* KeyedDecodingContainer+Decode.swift */; };
EA09CE03282C44A100A7835F /* MFFGHSUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CE02282C44A100A7835F /* MFFGHSUtility.swift */; };
EA09CE05282C45C200A7835F /* BluetoothPairBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CE04282C45C200A7835F /* BluetoothPairBehavior.swift */; };
EA1B7BBD2893459E006AF0BC /* DecodableDefaults+VDS.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1B7BBC2893459E006AF0BC /* DecodableDefaults+VDS.swift */; };
EA33618B288B1B630071C351 /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA33618A288B1B630071C351 /* VDS.framework */; }; EA33618B288B1B630071C351 /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA33618A288B1B630071C351 /* VDS.framework */; };
EA33618C288B1B630071C351 /* VDS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA33618A288B1B630071C351 /* VDS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EA33618C288B1B630071C351 /* VDS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA33618A288B1B630071C351 /* VDS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EA3361C1288B37FB0071C351 /* TestToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3361C0288B37FB0071C351 /* TestToggle.swift */; };
EA3361FB2891D54A0071C351 /* VDSTypographyTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */; }; EA3361FB2891D54A0071C351 /* VDSTypographyTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */; };
EA3361FC2891D54A0071C351 /* VDSTypographyTokens.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EA3361FC2891D54A0071C351 /* VDSTypographyTokens.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EA3362342891F5AB0071C351 /* TestToggleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3362332891F5AB0071C351 /* TestToggleModel.swift */; };
EA3E48A62860BB4D00B524AB /* WifiWidgetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3E48A52860BB4D00B524AB /* WifiWidgetModel.swift */; };
EA3E48A82860BB9800B524AB /* WifiWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3E48A72860BB9800B524AB /* WifiWidget.swift */; };
EA5B696E2866BC1000B17D2E /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696C2866BC1000B17D2E /* MVMCore.framework */; }; EA5B696E2866BC1000B17D2E /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696C2866BC1000B17D2E /* MVMCore.framework */; };
EA5B696F2866BC1000B17D2E /* MVMCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696C2866BC1000B17D2E /* MVMCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EA5B696F2866BC1000B17D2E /* MVMCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696C2866BC1000B17D2E /* MVMCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EA5B69702866BC1000B17D2E /* MVMCoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */; }; EA5B69702866BC1000B17D2E /* MVMCoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */; };
EA5B69712866BC1000B17D2E /* MVMCoreUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EA5B69712866BC1000B17D2E /* MVMCoreUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EAA54A92286A47ED00B9136B /* WifiViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA54A91286A47ED00B9136B /* WifiViewController.swift */; };
EAA658152875FA5E00484A7D /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */; }; EAA658152875FA5E00484A7D /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */; };
EAA658162875FA5E00484A7D /* VDSFormControlsTokens.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EAA658162875FA5E00484A7D /* VDSFormControlsTokens.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EACA5E5E2853DBC900CBA65B /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EACA5E5D2853DBC900CBA65B /* VDSColorTokens.xcframework */; }; EACA5E5E2853DBC900CBA65B /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EACA5E5D2853DBC900CBA65B /* VDSColorTokens.xcframework */; };
@ -75,6 +109,13 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
D21B3A25259B93ED001483DC /* SelfSizingCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfSizingCollectionView.swift; sourceTree = "<group>"; };
D2431DEA25E93A4F001C7AAC /* buttimag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = buttimag.swift; sourceTree = "<group>"; };
D27564B42590FADB003CA713 /* ListDeviceRightVariableCaretModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListDeviceRightVariableCaretModel.swift; sourceTree = "<group>"; };
D27564B52590FADB003CA713 /* ListDeviceRightVariableCaret.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListDeviceRightVariableCaret.swift; sourceTree = "<group>"; };
D27564C525939E91003CA713 /* LinkCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkCollectionViewCell.swift; sourceTree = "<group>"; };
D27564C625939E91003CA713 /* Links.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Links.swift; sourceTree = "<group>"; };
D27564C725939E91003CA713 /* LinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinksModel.swift; sourceTree = "<group>"; };
D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCreatorActionHandler.swift; sourceTree = "<group>"; }; D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCreatorActionHandler.swift; sourceTree = "<group>"; };
D2B1E3EF22F4A68F0065F95C /* JSONCreator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSONCreator.app; sourceTree = BUILT_PRODUCTS_DIR; }; D2B1E3EF22F4A68F0065F95C /* JSONCreator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSONCreator.app; sourceTree = BUILT_PRODUCTS_DIR; };
D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -88,17 +129,55 @@
D2B1E51222F9F9590065F95C /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = "<group>"; }; D2B1E51222F9F9590065F95C /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = "<group>"; };
D2B1E51C22FA0DF50065F95C /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2B1E51C22FA0DF50065F95C /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2B1E51E22FA0DF80065F95C /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2B1E51E22FA0DF80065F95C /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2FC4FA925897ACB00061EA4 /* StepModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepModel.swift; sourceTree = "<group>"; };
D2FC4FAA25897ACB00061EA4 /* OrderTrackerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderTrackerModel.swift; sourceTree = "<group>"; };
D2FC4FAB25897ACB00061EA4 /* Step.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Step.swift; sourceTree = "<group>"; };
D2FC4FAC25897ACB00061EA4 /* OrderTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderTracker.swift; sourceTree = "<group>"; };
EA09CDBC282C3FD800A7835F /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; EA09CDBC282C3FD800A7835F /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
EA09CDBE282C40CB00A7835F /* MFFGHSBluetoothPair.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFFGHSBluetoothPair.swift; sourceTree = "<group>"; };
EA09CDC0282C40CB00A7835F /* GMFGBluetoothPair.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGBluetoothPair.swift; sourceTree = "<group>"; };
EA09CDC4282C40CB00A7835F /* GMFGConstant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGConstant.swift; sourceTree = "<group>"; };
EA09CDC7282C40CC00A7835F /* GMFGBLEHandlerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGBLEHandlerProtocol.swift; sourceTree = "<group>"; };
EA09CDC9282C40CC00A7835F /* GMFG5GCBandSignalHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFG5GCBandSignalHandler.swift; sourceTree = "<group>"; };
EA09CDCA282C40CC00A7835F /* GMFGOperationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGOperationHandler.swift; sourceTree = "<group>"; };
EA09CDCB282C40CC00A7835F /* GMFGPublicInternetAccessHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGPublicInternetAccessHandler.swift; sourceTree = "<group>"; };
EA09CDCC282C40CC00A7835F /* GMFGFotaHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGFotaHandler.swift; sourceTree = "<group>"; };
EA09CDCD282C40CC00A7835F /* GMFGSpeedTestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGSpeedTestHandler.swift; sourceTree = "<group>"; };
EA09CDCE282C40CC00A7835F /* GMFG5GSignalHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFG5GSignalHandler.swift; sourceTree = "<group>"; };
EA09CDCF282C40CC00A7835F /* GMFGRouterWifiHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGRouterWifiHandler.swift; sourceTree = "<group>"; };
EA09CDE2282C416C00A7835F /* BluetoothDebuggableProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothDebuggableProtocol.swift; sourceTree = "<group>"; };
EA09CDE3282C416C00A7835F /* MulticastDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MulticastDelegate.swift; sourceTree = "<group>"; };
EA09CDE4282C416C00A7835F /* BluetoothDebugger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothDebugger.swift; sourceTree = "<group>"; };
EA09CDE5282C416C00A7835F /* BluetoothDebuggerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothDebuggerView.swift; sourceTree = "<group>"; };
EA09CDEA282C422900A7835F /* GMFGStorageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGStorageManager.swift; sourceTree = "<group>"; };
EA09CDEC282C423E00A7835F /* GMFGLocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GMFGLocationManager.swift; sourceTree = "<group>"; };
EA09CDEE282C429800A7835F /* GMFGTestScreenData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GMFGTestScreenData.swift; sourceTree = "<group>"; };
EA09CDF1282C430400A7835F /* BluetoothPairingProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPairingProtocol.swift; sourceTree = "<group>"; };
EA09CDF2282C430400A7835F /* BluetoothPairableProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPairableProtocol.swift; sourceTree = "<group>"; };
EA09CDF4282C430400A7835F /* BluetoothConfigModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothConfigModel.swift; sourceTree = "<group>"; };
EA09CDF5282C430400A7835F /* PeripheralModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeripheralModel.swift; sourceTree = "<group>"; };
EA09CDF6282C430400A7835F /* CharacteristicModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacteristicModel.swift; sourceTree = "<group>"; };
EA09CDF7282C430400A7835F /* ServiceModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceModel.swift; sourceTree = "<group>"; };
EA09CDFE282C437C00A7835F /* MFFGHSAnalyticsProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFFGHSAnalyticsProtocol.swift; sourceTree = "<group>"; };
EA09CE00282C43E800A7835F /* KeyedDecodingContainer+Decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "KeyedDecodingContainer+Decode.swift"; sourceTree = "<group>"; };
EA09CE02282C44A100A7835F /* MFFGHSUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFFGHSUtility.swift; sourceTree = "<group>"; };
EA09CE04282C45C200A7835F /* BluetoothPairBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothPairBehavior.swift; sourceTree = "<group>"; };
EA1B7BBC2893459E006AF0BC /* DecodableDefaults+VDS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DecodableDefaults+VDS.swift"; sourceTree = "<group>"; };
EA2ED278285BB3F400781478 /* MVMCoreUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMCoreUI.xcframework; path = ../SharedFrameworks/MVMCoreUI.xcframework; sourceTree = "<group>"; }; EA2ED278285BB3F400781478 /* MVMCoreUI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMCoreUI.xcframework; path = ../SharedFrameworks/MVMCoreUI.xcframework; sourceTree = "<group>"; };
EA2ED279285BB3F400781478 /* MVMCore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMCore.xcframework; path = ../SharedFrameworks/MVMCore.xcframework; sourceTree = "<group>"; }; EA2ED279285BB3F400781478 /* MVMCore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMCore.xcframework; path = ../SharedFrameworks/MVMCore.xcframework; sourceTree = "<group>"; };
EA2ED27E285BD00D00781478 /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA2ED27E285BD00D00781478 /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA2ED27F285BD00D00781478 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA2ED27F285BD00D00781478 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA33618A288B1B630071C351 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA33618A288B1B630071C351 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA3361C0288B37FB0071C351 /* TestToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestToggle.swift; sourceTree = "<group>"; };
EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; }; EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; };
EA3362332891F5AB0071C351 /* TestToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestToggleModel.swift; sourceTree = "<group>"; };
EA3E48A52860BB4D00B524AB /* WifiWidgetModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiWidgetModel.swift; sourceTree = "<group>"; };
EA3E48A72860BB9800B524AB /* WifiWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiWidget.swift; sourceTree = "<group>"; };
EA5B696C2866BC1000B17D2E /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA5B696C2866BC1000B17D2E /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA7E676927582F2200ABF773 /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA7E676927582F2200ABF773 /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA7E676A27582F2200ABF773 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA7E676A27582F2200ABF773 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EAA54A91286A47ED00B9136B /* WifiViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiViewController.swift; sourceTree = "<group>"; };
EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; }; EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
EACA5E5D2853DBC900CBA65B /* VDSColorTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSColorTokens.xcframework; path = ../SharedFrameworks/VDSColorTokens.xcframework; sourceTree = "<group>"; }; EACA5E5D2853DBC900CBA65B /* VDSColorTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSColorTokens.xcframework; path = ../SharedFrameworks/VDSColorTokens.xcframework; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -124,7 +203,9 @@
D288D69B26CAE26900A5C365 /* MF */ = { D288D69B26CAE26900A5C365 /* MF */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D2431DEA25E93A4F001C7AAC /* buttimag.swift */,
D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */, D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */,
D2FC4FA825897ACB00061EA4 /* Order Tracker */,
); );
path = MF; path = MF;
sourceTree = "<group>"; sourceTree = "<group>";
@ -149,6 +230,7 @@
D2B1E3F122F4A68F0065F95C /* JSONCreator */ = { D2B1E3F122F4A68F0065F95C /* JSONCreator */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
EA09CD9A282C3F6B00A7835F /* 5G */,
D288D69B26CAE26900A5C365 /* MF */, D288D69B26CAE26900A5C365 /* MF */,
D2B1E40922F4C9F00065F95C /* JSON */, D2B1E40922F4C9F00065F95C /* JSON */,
D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */, D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */,
@ -158,6 +240,12 @@
D2B1E3FB22F4A6930065F95C /* Assets.xcassets */, D2B1E3FB22F4A6930065F95C /* Assets.xcassets */,
D2B1E3FD22F4A6930065F95C /* LaunchScreen.storyboard */, D2B1E3FD22F4A6930065F95C /* LaunchScreen.storyboard */,
D2B1E40022F4A6930065F95C /* Info.plist */, D2B1E40022F4A6930065F95C /* Info.plist */,
EA3E48A52860BB4D00B524AB /* WifiWidgetModel.swift */,
EA3E48A72860BB9800B524AB /* WifiWidget.swift */,
EAA54A91286A47ED00B9136B /* WifiViewController.swift */,
EA3362332891F5AB0071C351 /* TestToggleModel.swift */,
EA3361C0288B37FB0071C351 /* TestToggle.swift */,
EA1B7BBC2893459E006AF0BC /* DecodableDefaults+VDS.swift */,
); );
path = JSONCreator; path = JSONCreator;
sourceTree = "<group>"; sourceTree = "<group>";
@ -185,6 +273,106 @@
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D2FC4FA825897ACB00061EA4 /* Order Tracker */ = {
isa = PBXGroup;
children = (
D21B3A25259B93ED001483DC /* SelfSizingCollectionView.swift */,
D27564C525939E91003CA713 /* LinkCollectionViewCell.swift */,
D27564C625939E91003CA713 /* Links.swift */,
D27564C725939E91003CA713 /* LinksModel.swift */,
D27564B52590FADB003CA713 /* ListDeviceRightVariableCaret.swift */,
D27564B42590FADB003CA713 /* ListDeviceRightVariableCaretModel.swift */,
D2FC4FA925897ACB00061EA4 /* StepModel.swift */,
D2FC4FAA25897ACB00061EA4 /* OrderTrackerModel.swift */,
D2FC4FAB25897ACB00061EA4 /* Step.swift */,
D2FC4FAC25897ACB00061EA4 /* OrderTracker.swift */,
);
path = "Order Tracker";
sourceTree = "<group>";
};
EA09CD9A282C3F6B00A7835F /* 5G */ = {
isa = PBXGroup;
children = (
EA09CE04282C45C200A7835F /* BluetoothPairBehavior.swift */,
EA09CE02282C44A100A7835F /* MFFGHSUtility.swift */,
EA09CE00282C43E800A7835F /* KeyedDecodingContainer+Decode.swift */,
EA09CDBE282C40CB00A7835F /* MFFGHSBluetoothPair.swift */,
EA09CDFE282C437C00A7835F /* MFFGHSAnalyticsProtocol.swift */,
EA09CDF3282C430400A7835F /* Models */,
EA09CDF0282C430400A7835F /* Protocols */,
EA09CDE1282C416C00A7835F /* Debugger */,
EA09CDBF282C40CB00A7835F /* Utility */,
);
path = 5G;
sourceTree = "<group>";
};
EA09CDBF282C40CB00A7835F /* Utility */ = {
isa = PBXGroup;
children = (
EA09CDEC282C423E00A7835F /* GMFGLocationManager.swift */,
EA09CDEA282C422900A7835F /* GMFGStorageManager.swift */,
EA09CDC0282C40CB00A7835F /* GMFGBluetoothPair.swift */,
EA09CDC4282C40CB00A7835F /* GMFGConstant.swift */,
EA09CDC6282C40CC00A7835F /* Protocols */,
EA09CDC8282C40CC00A7835F /* BLE Handlers */,
EA09CDEE282C429800A7835F /* GMFGTestScreenData.swift */,
);
path = Utility;
sourceTree = "<group>";
};
EA09CDC6282C40CC00A7835F /* Protocols */ = {
isa = PBXGroup;
children = (
EA09CDC7282C40CC00A7835F /* GMFGBLEHandlerProtocol.swift */,
);
path = Protocols;
sourceTree = "<group>";
};
EA09CDC8282C40CC00A7835F /* BLE Handlers */ = {
isa = PBXGroup;
children = (
EA09CDC9282C40CC00A7835F /* GMFG5GCBandSignalHandler.swift */,
EA09CDCA282C40CC00A7835F /* GMFGOperationHandler.swift */,
EA09CDCB282C40CC00A7835F /* GMFGPublicInternetAccessHandler.swift */,
EA09CDCC282C40CC00A7835F /* GMFGFotaHandler.swift */,
EA09CDCD282C40CC00A7835F /* GMFGSpeedTestHandler.swift */,
EA09CDCE282C40CC00A7835F /* GMFG5GSignalHandler.swift */,
EA09CDCF282C40CC00A7835F /* GMFGRouterWifiHandler.swift */,
);
path = "BLE Handlers";
sourceTree = "<group>";
};
EA09CDE1282C416C00A7835F /* Debugger */ = {
isa = PBXGroup;
children = (
EA09CDE2282C416C00A7835F /* BluetoothDebuggableProtocol.swift */,
EA09CDE3282C416C00A7835F /* MulticastDelegate.swift */,
EA09CDE4282C416C00A7835F /* BluetoothDebugger.swift */,
EA09CDE5282C416C00A7835F /* BluetoothDebuggerView.swift */,
);
path = Debugger;
sourceTree = "<group>";
};
EA09CDF0282C430400A7835F /* Protocols */ = {
isa = PBXGroup;
children = (
EA09CDF1282C430400A7835F /* BluetoothPairingProtocol.swift */,
EA09CDF2282C430400A7835F /* BluetoothPairableProtocol.swift */,
);
path = Protocols;
sourceTree = "<group>";
};
EA09CDF3282C430400A7835F /* Models */ = {
isa = PBXGroup;
children = (
EA09CDF4282C430400A7835F /* BluetoothConfigModel.swift */,
EA09CDF5282C430400A7835F /* PeripheralModel.swift */,
EA09CDF6282C430400A7835F /* CharacteristicModel.swift */,
EA09CDF7282C430400A7835F /* ServiceModel.swift */,
);
path = Models;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -222,9 +410,6 @@
D2B1E43722F9F84E0065F95C = { D2B1E43722F9F84E0065F95C = {
CreatedOnToolsVersion = 10.3; CreatedOnToolsVersion = 10.3;
}; };
EA985CBC298AE8CB00F2FF2E = {
CreatedOnToolsVersion = 14.2;
};
}; };
}; };
buildConfigurationList = D2B1E3EA22F4A68F0065F95C /* Build configuration list for PBXProject "JSONCreator" */; buildConfigurationList = D2B1E3EA22F4A68F0065F95C /* Build configuration list for PBXProject "JSONCreator" */;
@ -244,7 +429,6 @@
targets = ( targets = (
D2B1E3EE22F4A68F0065F95C /* JSONCreator */, D2B1E3EE22F4A68F0065F95C /* JSONCreator */,
D2B1E43722F9F84E0065F95C /* UpdateDependency */, D2B1E43722F9F84E0065F95C /* UpdateDependency */,
EA985CBC298AE8CB00F2FF2E /* Artifactory */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -281,23 +465,6 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "#!/bin/bash\n\ncd ../\nsh update.sh\n"; shellScript = "#!/bin/bash\n\ncd ../\nsh update.sh\n";
}; };
EA985CC0298AE8D000F2FF2E /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n# Type a script or drag a script file from your workspace to insert its path.\ncd \"${PROJECT_DIR}\"\ncd ../\ncd \"Supporting Files/Artifactory\"\nmkdir -p \"../../SharedFrameworks\"\nsh DownloadArtifactoryItems.sh\n";
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@ -305,10 +472,55 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
EA09CDFC282C430400A7835F /* CharacteristicModel.swift in Sources */,
EA3E48A82860BB9800B524AB /* WifiWidget.swift in Sources */,
D2B1E3F722F4A68F0065F95C /* DetailViewController.swift in Sources */, D2B1E3F722F4A68F0065F95C /* DetailViewController.swift in Sources */,
EA09CDDD282C40CC00A7835F /* GMFGSpeedTestHandler.swift in Sources */,
EA09CDDF282C40CC00A7835F /* GMFGRouterWifiHandler.swift in Sources */,
EA09CDFD282C430400A7835F /* ServiceModel.swift in Sources */,
EA09CE01282C43E800A7835F /* KeyedDecodingContainer+Decode.swift in Sources */,
EA09CDDE282C40CC00A7835F /* GMFG5GSignalHandler.swift in Sources */,
EA09CDD1282C40CC00A7835F /* MFFGHSBluetoothPair.swift in Sources */,
EA09CDEB282C422900A7835F /* GMFGStorageManager.swift in Sources */,
EA1B7BBD2893459E006AF0BC /* DecodableDefaults+VDS.swift in Sources */,
EA09CE05282C45C200A7835F /* BluetoothPairBehavior.swift in Sources */,
EAA54A92286A47ED00B9136B /* WifiViewController.swift in Sources */,
EA09CDFA282C430400A7835F /* BluetoothConfigModel.swift in Sources */,
D27564CA25939E91003CA713 /* LinksModel.swift in Sources */,
D2B1E3F522F4A68F0065F95C /* MasterViewController.swift in Sources */, D2B1E3F522F4A68F0065F95C /* MasterViewController.swift in Sources */,
D27564B62590FADB003CA713 /* ListDeviceRightVariableCaretModel.swift in Sources */,
EA09CDEF282C429800A7835F /* GMFGTestScreenData.swift in Sources */,
EA09CDED282C423F00A7835F /* GMFGLocationManager.swift in Sources */,
EA09CE03282C44A100A7835F /* MFFGHSUtility.swift in Sources */,
EA09CDF9282C430400A7835F /* BluetoothPairableProtocol.swift in Sources */,
D27564B72590FADB003CA713 /* ListDeviceRightVariableCaret.swift in Sources */,
D2431DEB25E93A4F001C7AAC /* buttimag.swift in Sources */,
EA3361C1288B37FB0071C351 /* TestToggle.swift in Sources */,
D27564C825939E91003CA713 /* LinkCollectionViewCell.swift in Sources */,
EA09CDFB282C430400A7835F /* PeripheralModel.swift in Sources */,
D2FC4FB025897ACB00061EA4 /* OrderTracker.swift in Sources */,
EA09CDD8282C40CC00A7835F /* GMFGBLEHandlerProtocol.swift in Sources */,
EA09CDDC282C40CC00A7835F /* GMFGFotaHandler.swift in Sources */,
EA09CDD6282C40CC00A7835F /* GMFGConstant.swift in Sources */,
D27564C925939E91003CA713 /* Links.swift in Sources */,
EA09CDE6282C416C00A7835F /* BluetoothDebuggableProtocol.swift in Sources */,
EA3E48A62860BB4D00B524AB /* WifiWidgetModel.swift in Sources */,
EA09CDD2282C40CC00A7835F /* GMFGBluetoothPair.swift in Sources */,
EA09CDE9282C416C00A7835F /* BluetoothDebuggerView.swift in Sources */,
D2FC4FAE25897ACB00061EA4 /* OrderTrackerModel.swift in Sources */,
EA3362342891F5AB0071C351 /* TestToggleModel.swift in Sources */,
D21B3A27259B93ED001483DC /* SelfSizingCollectionView.swift in Sources */,
EA09CDD9282C40CC00A7835F /* GMFG5GCBandSignalHandler.swift in Sources */,
EA09CDF8282C430400A7835F /* BluetoothPairingProtocol.swift in Sources */,
D2B1E3F322F4A68F0065F95C /* AppDelegate.swift in Sources */, D2B1E3F322F4A68F0065F95C /* AppDelegate.swift in Sources */,
EA09CDDA282C40CC00A7835F /* GMFGOperationHandler.swift in Sources */,
EA09CDE7282C416C00A7835F /* MulticastDelegate.swift in Sources */,
D29C557825BF1F340082E7D6 /* JSONCreatorActionHandler.swift in Sources */, D29C557825BF1F340082E7D6 /* JSONCreatorActionHandler.swift in Sources */,
EA09CDDB282C40CC00A7835F /* GMFGPublicInternetAccessHandler.swift in Sources */,
D2FC4FAD25897ACB00061EA4 /* StepModel.swift in Sources */,
EA09CDFF282C437C00A7835F /* MFFGHSAnalyticsProtocol.swift in Sources */,
EA09CDE8282C416C00A7835F /* BluetoothDebugger.swift in Sources */,
D2FC4FAF25897ACB00061EA4 /* Step.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -455,7 +667,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 59V5935DHZ; DEVELOPMENT_TEAM = FCMA4QKS77;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/../SharedFrameworks", "$(PROJECT_DIR)/../SharedFrameworks",
@ -479,7 +691,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 59V5935DHZ; DEVELOPMENT_TEAM = FCMA4QKS77;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/../SharedFrameworks", "$(PROJECT_DIR)/../SharedFrameworks",
@ -516,24 +728,6 @@
}; };
name = Release; name = Release;
}; };
EA985CBD298AE8CC00F2FF2E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = FCMA4QKS77;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
EA985CBE298AE8CC00F2FF2E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = FCMA4QKS77;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@ -564,15 +758,6 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
EA985CBF298AE8CC00F2FF2E /* Build configuration list for PBXAggregateTarget "Artifactory" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EA985CBD298AE8CC00F2FF2E /* Debug */,
EA985CBE298AE8CC00F2FF2E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = D2B1E3E722F4A68F0065F95C /* Project object */; rootObject = D2B1E3E722F4A68F0065F95C /* Project object */;

View File

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "EA985CBC298AE8CB00F2FF2E"
BuildableName = "Artifactory"
BlueprintName = "Artifactory"
ReferencedContainer = "container:JSONCreator.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "EA985CBC298AE8CB00F2FF2E"
BuildableName = "Artifactory"
BlueprintName = "Artifactory"
ReferencedContainer = "container:JSONCreator.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1400"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D2B1E3EE22F4A68F0065F95C"
BuildableName = "JSONCreator.app"
BlueprintName = "JSONCreator"
ReferencedContainer = "container:JSONCreator.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D2B1E3EE22F4A68F0065F95C"
BuildableName = "JSONCreator.app"
BlueprintName = "JSONCreator"
ReferencedContainer = "container:JSONCreator.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D2B1E3EE22F4A68F0065F95C"
BuildableName = "JSONCreator.app"
BlueprintName = "JSONCreator"
ReferencedContainer = "container:JSONCreator.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,9 @@
//
// BluetoothPairBehavior.swift
// JSONCreator
//
// Created by Matt Bruce on 5/11/22.
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import Foundation

View File

@ -0,0 +1,43 @@
//
// BluetoothDebuggableProtocol.swift
// MVM5G
//
// Created by Matt Bruce on 3/18/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import UIKit
//This is implemented on ViewControllers
protocol BluetoothDebuggableProtocol: BluetoothDebuggerDelegate {
associatedtype BluetoothPairType: MFFGHSBluetoothPair
var view: UIView! { get set }
var bluetoothPair: BluetoothPairType? { get set }
var bluetoothDebugger: BluetoothDebugger? { get }
var debuggerView: BluetoothDebuggerView? { get set}
func addDebuggerView()
}
extension BluetoothDebuggableProtocol {
var bluetoothDebugger: BluetoothDebugger? {
return self.bluetoothPair?.bluetoothDebugger
}
func addDebuggerView(){
guard GMFGTestScreenData.shared.visualDebugger else { return }
debuggerView = BluetoothDebuggerView()
if let debuggerView = debuggerView {
debuggerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(debuggerView)
debuggerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
debuggerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
debuggerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
debuggerView.heightAnchor.constraint(equalToConstant: 400).isActive = true
}
}
func bluetoothDebuggerUpdate(message: String){
self.debuggerView?.text = message
}
}

View File

@ -0,0 +1,327 @@
//
// GMFGBluetoothDebugger.swift
// MVM5G
//
// Created by Matt Bruce on 3/16/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import CoreBluetooth
//Delegate used to receive updates from the debugger
//during a onChange() debugger event
protocol BluetoothDebuggerDelegate: AnyObject {
func bluetoothDebuggerUpdate(message: String)
}
class BluetoothDebugger: NSObject {
weak var delegate: BluetoothDebuggerDelegate?
var deviceId: String
var config: BluetoothConfigModel
var bluetoothState: CBManagerState = .unknown { didSet { onChange() } }
var bluetoothStatus: Bool = false { didSet { onChange() } }
var isDevicePaired: Bool = false { didSet{ onChange() } }
var isDeviceActivated: Bool = false{ didSet{ onChange() } }
var isBluetoothPermissionDenied: Bool = false { didSet{ onChange() } }
var deviceDiscovered: String? { didSet{ onChange() } }
var deviceDiscoveredNameFailed: Set<String> = [] { didSet{ onChange() } }
var deviceMismatch: Set<String> = [] { didSet{ onChange() } }
var signalStatus: String? { didSet{ onChange() } }
var otherErrors: Set<String> = [] { didSet{ onChange() } }
var logs: Set<String> = [] { didSet { onChange() } }
//computed properties
var deviceInfo: String{
let value = """
deviceId: \(deviceId)\r
bluetoothState: \(bluetoothState.description)\r
bluetoothStatus: \(bluetoothStatus)\r
bluetoothPermissionDenied: \(isBluetoothPermissionDenied)\r
devicePaired: \(isDevicePaired)\r
deviceActivated: \(isDeviceActivated)\r
"""
return value
}
var discoveryInfo: String? {
var value: [String] = []
if let deviceDiscovered = deviceDiscovered {
value.append("deviceDiscovered: \(deviceDiscovered)\r")
}
if deviceDiscoveredNameFailed.isNotEmpty {
value.append("deviceDiscoveredNameFailed: \r\(deviceDiscoveredNameFailed.toString())")
}
if deviceMismatch.isNotEmpty {
value.append("deviceMismatch: \(deviceMismatch.toString())")
}
return value.isNotEmpty ? value.joined(separator: "") : nil
}
var otherErrorsInfo: String? {
guard otherErrors.isNotEmpty else { return nil }
return "\rErrors Occurred:\r\(otherErrors.toString())"
}
var logsInfo: String {
return "\rlogs:\r\(logs.toString())"
}
var configInfo: String {
guard let string = config.toJSONString() else {
return "\rConfig:\rdecodeError"
}
return "\rConfig:\r\(string)"
}
override var description: String {
var descriptions: [String] = [deviceInfo]
//optional messages
if let discoveryInfo = discoveryInfo {
descriptions.append(discoveryInfo)
}
if let firmwareInfo = firmwareInfo {
descriptions.append(firmwareInfo)
}
if let signalStatus = signalStatus {
descriptions.append(signalStatus)
}
if let publicInternetAccessStatusInfo = publicInternetAccessStatusInfo {
descriptions.append(publicInternetAccessStatusInfo)
}
if let speedTestStatusInfo = speedTestStatusInfo {
descriptions.append(speedTestStatusInfo)
}
if let routerWifiInfo = routerWifiInfo {
descriptions.append(routerWifiInfo)
}
if let signalUpdateInfo = signalUpdateInfo {
descriptions.append(signalUpdateInfo)
}
if let signalUpdateInfo = signalUpdateCBandInfo {
descriptions.append(signalUpdateInfo)
}
if let otherErrorsInfo = otherErrorsInfo {
descriptions.append(otherErrorsInfo)
}
descriptions.append(contentsOf: [logsInfo, configInfo])
return descriptions.joined(separator: "")
}
required init(config: BluetoothConfigModel, delegate: BluetoothDebuggerDelegate?){
self.deviceId = config.advertisedData
self.config = config
self.delegate = delegate
super.init()
self.onChange()
}
//methods
func onChange(){
delegate?.bluetoothDebuggerUpdate(message: description)
}
func addLog(message: String){
logs.insert(message)
}
func addOtherError(error: String){
otherErrors.insert(error)
}
func addDiscoveredNameFailures(foundNames: [String]) {
foundNames.forEach { name in
deviceDiscoveredNameFailed.insert(name)
}
}
func addDeviceIMEIMismatch(found: String) {
deviceMismatch.insert(found)
}
func updateCurrentSignalStatus(_ status: MFFGHSSignalStatus, strengthCheckStatus: MFFGHSSignalStrengthCheckStatus, rssi: Double?) {
var rssiValue = "none"
if let rssi = rssi {
rssiValue = "\(rssi)"
}
signalStatus = "signalStatus: status: \(status) strengthCheck: \(strengthCheckStatus) rssi: \(rssiValue)\r"
}
//Handler Delegates Properties
//GMFGSpeedTestDelegate
var speedTestStatus: GMFGSpeedTestUpdate? { didSet { onChange() } }
var speedTestStatusInfo: String? {
guard let status = speedTestStatus else { return nil }
return "speedTestStatusInfo: \(status)\r"
}
//GMFGRouterWifiDelegate
var routerWifiCredentials: GMFGRouterWifiInfo? { didSet { onChange() } }
var routerWifiStatus: GMFGRouterWifiStatus? { didSet { onChange() } }
var routerWifiInfo: String? {
var value = ""
if let routerWifiCredentials = routerWifiCredentials {
value = """
routerWifiCredentials:\r
- ssid: \(routerWifiCredentials.ssid)\r
- password: \(routerWifiCredentials.password)\r
"""
}
if let routerWifiStatus = routerWifiStatus {
value = value + """
routerWifiStatus: \(routerWifiStatus)\r
"""
}
return value
}
//GMFGPublicInternetAccessDelegate
var publicInternetAccessStatus: GMPublicInternetAccessStatus? { didSet { onChange() } }
var publicInternetAccessStatusInfo: String? {
guard let status = publicInternetAccessStatus else { return nil }
return "publicInternetAccessStatus: \(status)\r"
}
//GMFGFotaDelegate
var firmwareResponse: GMFotaResponse? { didSet { onChange() } }
var isCheckingFirmware: Bool? { didSet { onChange() } }
var firmwareInfo: String? {
var value: [String] = []
if let isCheckingFirmware = isCheckingFirmware {
value.append("checkingFirmware: \(isCheckingFirmware)\r")
}
if let fota = firmwareResponse {
value.append("""
firmwareStatus: \(fota.status)\r
firmwareVersion: \(fota.version)\r
firmwareError: \(fota.errorMsg ?? "none")\r
""")
}
return value.isNotEmpty ? value.joined(separator: "") : nil
}
//GMFG5GSignalDelegate
var signalUpdate: GMFG5GSignalUpdate? { didSet { onChange() } }
var signalUpdateInfo: String? {
guard let signalUpdate = signalUpdate else { return nil }
return "\r5G Signal Update: \r\(signalUpdate)\r"
}
//GMFG5GSignalDelegate
var signalUpdateCBand: GMFG5GCBandSignalUpdate? { didSet { onChange() } }
var signalUpdateCBandInfo: String? {
guard let signalUpdate = signalUpdateCBand, let results = signalUpdate.rawResults else { return nil }
return "\r5G C-Band Signal Update: \r\(results)\r"
}
}
//Handler Delegate Implementations
extension BluetoothDebugger: GMFGSpeedTestDelegate {
func didStartSpeedTest() {
//BLELog has this
}
func didStopSpeedTest() {
//BLELog has this
}
func speedTestStatus(status: GMFGSpeedTestUpdate) {
speedTestStatus = status
}
}
extension BluetoothDebugger: GMFGRouterWifiDelegate {
func routerWifi(credentials: GMFGRouterWifiInfo) {
routerWifiCredentials = credentials
}
func routerWifiStatus(status: GMFGRouterWifiStatus) {
routerWifiStatus = status
}
}
extension BluetoothDebugger: GMFGPublicInternetAccessDelegate {
func publicInternetAccessStatus(status: GMPublicInternetAccessStatus) {
publicInternetAccessStatus = status
}
}
extension BluetoothDebugger: GMFGFotaDelegate {
func fotaStatus(statusResponse: GMFotaResponse) {
firmwareResponse = statusResponse
}
func unknownResponse(rawResponse: [String : Any]?) {
let response: String = rawResponse == nil ? "none" : "\(rawResponse!)"
addLog(message: "unknown response: \(response)")
}
}
extension BluetoothDebugger: GMFG5GSignalDelegate {
func updated5GSignal(_ update: GMFG5GSignalUpdate){
signalUpdate = update
}
func signalNotReady() {
signalUpdate = nil
addLog(message: "5G Signal Not Ready")
}
}
extension BluetoothDebugger: GMFG5GCBandSignalDelegate {
func updated5GCBandSignal(_ update: GMFG5GCBandSignalUpdate){
signalUpdateCBand = update
}
func signal5GCBandNotReady() {
signalUpdateCBand = nil
addLog(message: "5G C-Band Signal Not Ready")
}
}
extension CBManagerState: CustomStringConvertible {
public var description: String {
switch self {
case .unknown:
return "unknown"
case .resetting:
return "resetting"
case .unsupported:
return "unsupported"
case .unauthorized:
return "unauthorized"
case .poweredOff:
return "poweredOff"
case .poweredOn:
return "poweredOn"
@unknown default:
return "unknown"
}
}
}
extension Collection {
fileprivate func toString() -> String {
return self.map{" - \($0)\r"}.joined(separator: "")
}
}

View File

@ -0,0 +1,96 @@
//
// BluetoothDebuggerView.swift
// MVM5G
//
// Created by Matt Bruce on 3/19/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import UIKit
/// View Used to show on Pairing screens to act as a Console Log
class BluetoothDebuggerView: UIView {
//console log view
var textView = UITextView()
//text show in textView
var text: String = "Initial Page Load" {
didSet{
textView.text = text
}
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
init() {
super.init(frame: .zero)
setupView()
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
private func setupView() {
translatesAutoresizingMaskIntoConstraints = false
let doneButton = UIButton()
doneButton.setTitle("Done", for: .normal)
doneButton.addTarget(self, action: #selector(close), for: .touchUpInside)
doneButton.translatesAutoresizingMaskIntoConstraints = false
let headerView = UIView()
headerView.translatesAutoresizingMaskIntoConstraints = false
headerView.backgroundColor = .mvmCoolGray6
headerView.addSubview(doneButton)
doneButton.rightAnchor.constraint(equalTo: headerView.rightAnchor).isActive = true
doneButton.topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true
doneButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
doneButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
textView.setContentCompressionResistancePriority(.required, for: .vertical)
textView.isUserInteractionEnabled = true
textView.showsVerticalScrollIndicator = true
textView.isEditable = false
textView.isScrollEnabled = true
textView.scrollRangeToVisible(NSMakeRange(0, 0))
textView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.backgroundColor = .white
textView.text = text
addSubview(headerView)
addSubview(textView)
headerView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
headerView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
headerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
headerView.bottomAnchor.constraint(equalTo: textView.topAnchor).isActive = true
headerView.heightAnchor.constraint(equalToConstant: 40).isActive = true
textView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
textView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
textView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
textView.heightAnchor.constraint(equalToConstant: 400).isActive = true
}
//removes self from View
@objc func close(sender: UIButton){
removeFromSuperview()
}
}

View File

@ -0,0 +1,56 @@
//
// MulticastDelegate.swift
// MVM5G
//
// Created by Matt Bruce on 3/23/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
public class MulticastDelegate<T> {
// MARK: - Properties
private class Wrapper {
weak var delegate: AnyObject?
init(_ delegate: AnyObject) {
self.delegate = delegate
}
}
private var wrappers: [Wrapper] = []
public var delegates: [T] {
return wrappers
.compactMap{ $0.delegate } as! [T]
}
// MARK: - Actions
public func add(delegate: T) {
let wrapper = Wrapper(delegate as AnyObject)
wrappers.append(wrapper)
}
public func add(delegates: [T?]){
for case let delegate? in delegates {
add(delegate: delegate)
}
}
public func remove(delegate: T) {
guard let index = wrappers.firstIndex(where: {
$0.delegate === (delegate as AnyObject)
}) else {
return
}
wrappers.remove(at: index)
}
public func removeAll(){
wrappers.removeAll()
}
public func invokeForEachDelegate(_ handler: (T) -> ()) {
delegates.forEach { handler($0) }
}
}

View File

@ -0,0 +1,59 @@
//
// KeyedDecodingContainer+Decode.swift
// MVM5G
//
// Created by Matt Bruce on 4/15/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import MVMCore
public enum KeyedDecodingContainerError: Error {
case decode(objectType: String, key: String, message: String)
}
extension KeyedDecodingContainerError: LocalizedError, CustomStringConvertible {
public var description: String {
switch self {
case .decode(let objectType, let key, let message):
return "Decoding Error for object: \(objectType) on coding key: \(key) with error: \(message)"
}
}
public var errorDescription: String? {
return self.description
}
}
extension KeyedDecodingContainer {
public func decode<T: Decodable, K: Decodable>(_ type: T.Type,
forKey key: Self.Key,
objectType: K.Type) throws -> T {
do {
return try self.decode(type, forKey: key)
} catch {
throw KeyedDecodingContainerError.decode(objectType: "\(objectType)", key: key.stringValue, message: error.localizedDescription)
}
}
}
extension JSONError: LocalizedError, CustomStringConvertible {
public var description: String {
switch self {
case .pathNotFound:
return "JSON path not found"
case .data(path: let path):
return "JSON data in \(path) is corrupt"
case .other(error: let error):
return error.localizedDescription
case .error(message: let message):
return message
}
}
public var errorDescription: String? {
return description
}
}

View File

@ -0,0 +1,217 @@
//
// MFFGHSAnalyticsProtocol.swift
// MVM5G
//
// Created by Gujuluva Santharam, Ajai Prabhu on 20/05/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import Foundation
import UIKit
import MVMCore
import MVMCoreUI
protocol MFFGHSAnalyticsProtocol {
func trackPage(data: [String: Any]?, additionalData: [String:Any]?)
func trackAction(action: [String: Any]?, pageData:[String: Any]?, additionalData: [String: Any]?)
func trackPageAppear(with pageJSON: [String: Any]?)
func trackPageDisappear(with pageJSON: [String: Any]?)
/** true means it will stop sending data to server when view appear to reduce data load. Temporary bool, will remove next release */
func stopInitialEvent() -> Bool
}
enum AnalyticsLogType: String {
case UI = "UI"
case BLE = "BLE"
}
struct AnalyticsPageInfo {
var pageType: String?
}
extension MFFGHSAnalyticsProtocol {
/** this boolean enable entire analytics feature. enable = false means nothing will send to server */
private var enable: Bool {
let initialParams:[String: Any] = [:]
return !initialParams.boolForKey("isFGAnalyticsDisabled")
}
/** enable time tracking feature. TODO - we are reducing call not sending data on start event. */
private var enableTimeTracker: Bool { return true }
/** true means it will stop sending data to server when view appear to reduce data load. Temporary bool, will remove next release */
func stopInitialEvent() -> Bool { return false }
func trackPage(data: [String: Any]?, additionalData:[String:Any]?) {
let params: [String: Any] = [
"eventType" : additionalData?["eventType"] ?? "pageDisplay",
"pageType" : data?["pageType"] ?? "NA",
"template" : data?["template"] ?? "NA",
"eventName" : additionalData?["eventName"] ?? "start",
"pageClass" : additionalData?["pageClass"] ?? String(describing: Self.self),
"epochSec" : Int(Date().timeIntervalSince1970),
"tdn" : getVendorId(),
"os" : "iOS"
]
let mergedParams = params.merging(additionalData ?? [:]) { $1 }
performRequest(params: ["data": mergedParams])
}
func trackAction(action: [String: Any]?, pageData:[String: Any]?, additionalData: [String: Any]?) {
/*
let params: [String: Any] = [
"eventType" : "action",
"actionPageType": action?["pageType"] ?? "NA",
"actionTitle" : action?["title"] ?? "NA",
"pageType" : pageData?.stringForkey("pageType") ?? "NA",
"template" : pageData?.stringForkey("template") ?? "NA",
"epochSec" : Int(Date().timeIntervalSince1970)
]
performRequest(params: params)
*/
}
func trackGemini(value: [String: Any], logType: AnalyticsLogType, pageInfo: AnalyticsPageInfo? = nil) {
var result: [String: Any] = [
"os" : "iOS",
"LogType" : logType.rawValue,
"tdn" : getVendorId()
]
if let pageInfo = pageInfo {
result["pageType"] = pageInfo.pageType
}
let payload = result.merging(value) { $1 }
performRequest(params: ["data": payload])
}
func trackPKI(processStep: String, attributeList: GMFGAnalyticsAttributeList?) {
var payload: [String: Any] = [
"processStep" : processStep,
"os" : "iOS",
"tdn" : getVendorId()
]
if let attributeList = attributeList {
payload["attributeList"] = attributeList.getList()
//GlassboxManager.glassboxCustomEvent(forKey: GMFGConstant.Glassbox.fivegSetup, withParameters: ["gen3Data": attributeList.getList()])
}
performRequest(params: payload, forPageType: "gen3Data")
}
func trackGen3Data(processStep: String, attributeList: GMFGAnalyticsAttributeList?) {
var payload: [String: Any] = [
"processStep" : processStep,
"os" : "iOS",
"tdn" : getVendorId()
]
if let attributeList = attributeList {
payload["attributeList"] = attributeList.getList()
}
performRequest(params: payload, forPageType: "gen3Data", priority: .high)
}
func resetGMAnalytics() {
LogRequestSerialiser.shared.resetTimer()
}
// MARK:- Get the Device UUID
func getVendorId() -> String {
let uuid = UIDevice.current.identifierForVendor?.uuidString
return uuid ?? GMFGConstant.empty
}
private func performRequest(params: [String: Any], forPageType: String = "logUIData", priority: LogPriority = .normal) {
if enable {
LogRequestSerialiser.shared.queueLogRequest(params: params, forPageType: forPageType, priority: priority)
}
}
// MARK:- Public API - Time Tracker
func trackPageAppear(with pageJSON: [String: Any]?) {
if !enableTimeTracker { return }
//GMFGSelfInstallTimeTracker.shared.trackPageAppear(with: pageJSON)
}
func trackPageDisappear(with pageJSON: [String: Any]?) {
if !enableTimeTracker { return }
//GMFGSelfInstallTimeTracker.shared.trackPageDisappear(with: pageJSON)
}
}
final class LogRequestSerialiser {
static let shared: LogRequestSerialiser = LogRequestSerialiser()
private lazy var requestQueue: [RequestItem] = []
private lazy var timer: Timer? = nil
private init() { /* this avoid creating new instance */ }
private var index = 0
fileprivate func queueLogRequest(params: [String: Any], forPageType: String, priority: LogPriority) {
let requestItem = RequestItem(priority: priority, endpoint: forPageType, parameters: params)
requestQueue.append(requestItem)
startTimer()
}
@objc fileprivate func performRequestIfAvailable() {
if requestQueue.count > index {
let objectToBePerformed = requestQueue[index]
if let reqParams = MVMCoreRequestParameters(pageType: objectToBePerformed.endpoint, extraParameters: nil) {
index = index + 1
reqParams.add(objectToBePerformed.parameters)
MVMCoreLoadHandler.sharedGlobal()?.loadBackgroundRequest(reqParams, dataForPage: nil, delegateObject: nil)
}
}
if requestQueue.count <= index { resetTimer() }
}
fileprivate func resetTimer() {
timer?.invalidate()
timer = nil
index = 0
requestQueue.removeAll()
}
fileprivate func startTimer() {
if timer == nil {
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.performRequestIfAvailable), userInfo: nil, repeats: true)
self.timer?.tolerance = 0.5
}
}
}
}
fileprivate struct RequestItem {
var priority: LogPriority
var endpoint: String
var parameters: [String: Any]
}
fileprivate enum LogPriority {
case high
case normal
}
struct GMFGAnalyticsAttributeList {
private var attrList: [[String: Any]] = []
@available(*, deprecated, message: "use add(name:, value:)")
mutating func addAttribute(name: String, value: Any) {
attrList.append([
"attributeName": name,
"attributeValue": value
])
}
mutating func add(_ name: String, _ value: Any) {
attrList.append([
"attributeName": name,
"attributeValue": value
])
}
func getList() -> [[String: Any]] {
return attrList
}
}

View File

@ -0,0 +1,547 @@
//
// MFFGHSBluetoothPair.swift
// MobileFirstFramework
//
// Created by Chowdhury, Shohrab on 3/29/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import CoreBluetooth
public enum MFFGHSSignalStatus: NSNumber {
case noBluetoothConnection = -1, noSignal = 1, poor, good, confirmedGood, confirmedPoor
}
public enum MFFGHSSignalStrengthCheckStatus: NSNumber {
case idle = 0, processing, complete
}
public protocol MFFGHSBluetoothTestingProtocol {
var continueTesting: Bool { get set }
}
public protocol MFFGHSBluetoothPairDelegate : NSObjectProtocol {
/// Receive ble status ON/OFF
func bluetoothStatus(isOn: Bool)
/// New status that's more reliable as a callback if BLE is off
func bluetoothOff()
/// Bluetooth does not have access from the user
func bluetoothPermissionsDenied()
/// BLE found a device that doesn't match what it expects to find.
func deviceIMEIMismatch(expected: String, found: String)
/// An attempted pairing failed due to a broadcast naming mismatch.
func onBluetoothDiscoveredNameFailed(expectedName: String, foundNames: [String])
/// The bluetooth service was discovered.
func onBluetoothDiscovered(expectedName: String, foundName: String)
/// Check device is paired with phone
func pairUpdate(isPaired: Bool)
/// Check device is activated or not
func updateActivatedStatus(isActivated: Bool)
/// Receive current RSSI
func updateCurrentSignalStatus(_ status: MFFGHSSignalStatus, strengthCheckStatus: MFFGHSSignalStrengthCheckStatus, rssi: Double?)
}
extension MFFGHSBluetoothPairDelegate {
public func bluetoothStatus(isOn: Bool) {}
public func bluetoothOff() {}
public func bluetoothPermissionsDenied() {}
public func deviceIMEIMismatch(expected: String, found: String) {}
public func onBluetoothDiscoveredNameFailed(expectedName: String, foundNames: [String]) {}
public func onBluetoothDiscovered(expectedName: String, foundName: String) {}
public func pairUpdate(isPaired: Bool) {}
public func updateActivatedStatus(isActivated:Bool) {}
public func updateCurrentSignalStatus(_ status: MFFGHSSignalStatus, strengthCheckStatus: MFFGHSSignalStrengthCheckStatus, rssi: Double?) {}
}
class MFFGHSBluetoothPair: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, BluetoothParingProtocol {
// !!Major change!! Some controllers are relying on bluetooth object being passed.
static weak var instance:MFFGHSBluetoothPair?
/// Weak instance returned. Controller that uses it should hold onto strong reference. When all controllers deallocate, this will also.
static var sharedInstance: MFFGHSBluetoothPair {
get {
if let instance = instance {
return instance
} else {
let newInstance = MFFGHSBluetoothPair()
instance = newInstance
return newInstance
}
}
}
// Bluetooth control objects.
var centralManager: CBCentralManager?
var peripheral: CBPeripheral?
// Event delegate.
weak var delegate: MFFGHSBluetoothPairDelegate?
//debugger for event delegate
var bluetoothDebugger: BluetoothDebugger?
// Data from bluetooth connection
var isPaired = false
var isCPEActivated = false
var currentSignalStatus: MFFGHSSignalStatus = .noBluetoothConnection
var currentRSSIValue: Double?
// Configured properties.
var bluetoothConfig: BluetoothConfigModel? {
didSet {
if (oldValue != bluetoothConfig) { // TODO: Needs deep check for config changes.
setupBluetoothScanner()
}
}
}
var signalStrengthObserveDuration: TimeInterval = 30
var signalPassingPercentage: Double = 100
var signalStrengthCheckStatus: MFFGHSSignalStrengthCheckStatus = .idle
var signalStrengthObserverTimer: Timer?
var lastSignalStatusTimeStamp: Date?
var signalStrengthGoodTotalTime: Double = 0
var signalStrengthFailTotalTime: Double = 0
override init() {
super.init()
setupBluetoothScanner()
}
#if DEBUG
deinit {
print("bluetooth destroy")
}
#endif
var bluetoothEnabled:Bool {
#if targetEnvironment(simulator)
return true
#else
return self.centralManager?.state == CBManagerState.poweredOn
#endif
}
func scanForPeripherals(central:CBCentralManager) {
let advertiseIds = getBleAdvertiseUUIDs()
if advertiseIds.count > 0 {
central.scanForPeripherals(withServices: advertiseIds, options: nil)
} else {
central.stopScan()
}
}
func setupBluetoothScanner(showPowerAlert:Bool = false) {
// Reset connection on new config.
if let peripheral = self.peripheral {
centralManager?.cancelPeripheralConnection(peripheral)
self.peripheral = nil
self.isPaired = false
self.currentSignalStatus = .noBluetoothConnection
}
if self.centralManager == nil || showPowerAlert {
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main, options: [CBCentralManagerOptionShowPowerAlertKey: showPowerAlert])
} else if (bluetoothEnabled) {
scanForPeripherals(central: centralManager!)
} // else wait for powered on status
if GMFGTestScreenData.shared.isCPESimulated {
#if DEBUG
simulateBluetoothMessaging()
#endif
} else {
#if DEBUG && targetEnvironment(simulator)
simulateBluetoothMessaging()
#endif
}
}
#if DEBUG
// For simulating RSSI changes.
var timer: Timer?
private func simulateBluetoothMessaging() {
// If we don't get advertisement data, technically nothing will come.
if getBleAdvertiseUUIDs().count == 0 { return }
if timer != nil { return }
var signalRotate = 0
_ = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { (timer) in
self.delegate?.bluetoothStatus(isOn: true)
self.isCPEActivated = true
self.delegate?.updateActivatedStatus(isActivated: self.isCPEActivated)
self.isPaired = true
self.delegate?.pairUpdate(isPaired: self.isPaired)
signalRotate = (signalRotate + 1) % 5
self.currentRSSIValue = Double(signalRotate)
if (signalRotate >= 3) {
self.currentRSSIValue = -76
self.currentSignalStatus = .confirmedGood
} else if (signalRotate >= 2) {
self.currentRSSIValue = -86
self.currentSignalStatus = .good
} else if (signalRotate >= 1) {
self.currentRSSIValue = -101
self.currentSignalStatus = .poor
} else {
self.currentRSSIValue = -999
self.currentSignalStatus = .noSignal
}
self.delegate?.updateCurrentSignalStatus(self.currentSignalStatus, strengthCheckStatus:self.signalStrengthCheckStatus, rssi: self.currentRSSIValue)
self.bluetoothDebugger?.bluetoothStatus = true
self.bluetoothDebugger?.isDeviceActivated = true
self.bluetoothDebugger?.isDevicePaired = self.isPaired
self.bluetoothDebugger?.updateCurrentSignalStatus(self.currentSignalStatus, strengthCheckStatus:self.signalStrengthCheckStatus, rssi: self.currentRSSIValue)
}
}
#endif
// Should be used when we detect scanning is no longer required.
private func stopScanning() {
if let peripheral = self.peripheral {
centralManager?.cancelPeripheralConnection(peripheral)
self.peripheral = nil;
}
centralManager?.stopScan()
centralManager = nil
}
open func shutdown() {
stopScanning()
MFFGHSBluetoothPair.instance = nil
}
public func stopNotify5G(controller: MFFGHSBluetoothPairDelegate) {
if let del = delegate, del === controller {
delegate = nil
}
resetSignalStrengthCheckValue()
}
public func setup(config: BluetoothConfigModel, delegate: BluetoothDebuggerDelegate) {
bluetoothDebugger = BluetoothDebugger(config: config, delegate: delegate)
bluetoothConfig = config
}
public func startNotify5G(controller: MFFGHSBluetoothPairDelegate) {
delegate = controller
// Initialize
delegate?.pairUpdate(isPaired: isPaired)
delegate?.updateActivatedStatus(isActivated: isCPEActivated)
delegate?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
if let state = centralManager?.state {
bluetoothDebugger?.bluetoothState = state
}
bluetoothDebugger?.bluetoothStatus = bluetoothEnabled
bluetoothDebugger?.isDevicePaired = isPaired
bluetoothDebugger?.isDeviceActivated = isCPEActivated
bluetoothDebugger?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus:signalStrengthCheckStatus, rssi: currentRSSIValue)
}
// MARK:- Bluetooth delegate
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
bluetoothDebugger?.bluetoothState = central.state
switch (central.state) {
case .poweredOn:
delegate?.bluetoothStatus(isOn: true)
bluetoothDebugger?.bluetoothStatus = true
scanForPeripherals(central: central)
case .poweredOff, .unsupported, .unauthorized, .unknown:
delegate?.bluetoothStatus(isOn: false)
bluetoothDebugger?.bluetoothStatus = false
default:
print("bluetooth not powered on")
}
}
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if findPeripheralName(getBleAdvertiseName(), in: advertisementData) {
self.peripheral = peripheral
peripheral.delegate = self
central.connect(peripheral, options: nil)
central.stopScan()
} else {
if let foundName = advertisementData[CBAdvertisementDataLocalNameKey] as? String, foundName.hasPrefix(GMFGConstant.BLE.advertisePrefix) {
delegate?.deviceIMEIMismatch(expected: getBleAdvertiseName(), found: foundName)
bluetoothDebugger?.addDeviceIMEIMismatch(found: foundName)
}
}
}
private func findPeripheralName(_ name: String, in advertisementData: [String : Any]) -> Bool {
var found = false
var foundAdvertisedNames: [String] = []
// Check the local data name. (Where it should be. Used for testing app.)
if let localServiceName = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
if localServiceName == name {
found = true
} else {
foundAdvertisedNames.append(localServiceName)
}
}
// Check the service data. (Where it is actually implemented by CPE.)
if !found, let avdService = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID:Data] {
for key in avdService.keys {
if let rawName = avdService[key],
let advertisedName = String(bytes: rawName, encoding: .utf8) {
if (advertisedName == name) {
found = true
break
} else {
foundAdvertisedNames.append(advertisedName)
}
}
}
}
if found {
// Currently exact equality passes. Later can adjust to be actual advertised name if the requirement relaxes.
delegate?.onBluetoothDiscovered(expectedName: name, foundName: name)
bluetoothDebugger?.deviceDiscovered = name
let value: [String : Any] = [
"blePairStatus": "discovered",
"expectedBroadcastName": name,
"foundBroadcastName": name
]
track(value)
return true;
} else {
delegate?.onBluetoothDiscoveredNameFailed(expectedName: name, foundNames: foundAdvertisedNames)
bluetoothDebugger?.addDiscoveredNameFailures(foundNames: foundAdvertisedNames)
let value: [String : Any] = [
"blePairStatus": "mismatch",
"expectedBroadcastName": name,
"foundBroadcastName": foundAdvertisedNames.joined(separator: " / ").prefix(500)
]
track(value)
return false
}
}
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
isPaired = true
delegate?.pairUpdate(isPaired: true)
bluetoothDebugger?.isDevicePaired = true
peripheral.discoverServices(getBleAdvertiseUUIDs()) // For testing app which can only advertise on 1 service.
peripheral.discoverServices(getSeviceUUIDs())
}
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services ?? [] {
peripheral.discoverCharacteristics(getCharacteristicUUIDs(serviceId: service.uuid), for: service)
}
}
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics ?? [] {
peripheral.setNotifyValue(true, for: characteristic)
}
}
public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
let cpeResponse = formatCharacteristicData(characteristic)
handleActivated(response: cpeResponse)
handleFiveGSignal(response: cpeResponse)
}
public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { }
public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
// We only connect to 1 peripheral. Using that assumption below.
isPaired = false
currentSignalStatus = .noBluetoothConnection
currentRSSIValue = nil
delegate?.pairUpdate(isPaired: false)
delegate?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
bluetoothDebugger?.isDevicePaired = false
bluetoothDebugger?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
self.peripheral = nil
scanForPeripherals(central: central)
}
func formatCharacteristicData(_ characteristic: CBCharacteristic) -> [String: Any] {
guard
let advertiseData = characteristic.value, !advertiseData.isEmpty,
let advertiseDict = try? JSONSerialization.jsonObject(with: advertiseData, options: []) as? [String: Any]
else {
return [:]
}
return advertiseDict
}
// MARK: Handle Activation
func handleActivated(response: [String: Any]) {
if let activation = response["Activation"] as? [String: Any] {
isCPEActivated = activation.stringForkey("Status") == "Activated"
delegate?.updateActivatedStatus(isActivated: isCPEActivated)
bluetoothDebugger?.isDeviceActivated = isCPEActivated
}
}
// MARK: Handle FiveGSignal
func handleFiveGSignal(response: [String: Any]) {
if let fivegSignal = response["5GSignal"] as? [String: Any] {
if let rssiValue = parseRSRPFromJSON(fiveGData: fivegSignal) {
currentRSSIValue = rssiValue
// This need to call before currentSignalStatus set with new status. This is to gather the amount of time on the previous signal status before the update.
if signalStrengthCheckStatus == .processing {
//lastSignalStatusTimeStamp = lastSignalStatusTimeStamp != nil ? lastSignalStatusTimeStamp : Date()
checkSignalStrengthContinueRequired()
}
if GMFGTestScreenData.shared.isEnable5GSignal {
currentSignalStatus = currentSignalStatus == .confirmedGood ? .confirmedGood : .good
} else {
if rssiValue >= higherThreshold || rssiValue <= lowerThreshold {
// Future reference: -999 means no signal from CPE. Need to make sure it will always be included in check.
// Invalid value. We should not be above the upper limits or beneath the lower limits.
currentSignalStatus = .noSignal
} else if rssiValue >= rssiThreshold {
currentSignalStatus = currentSignalStatus == .confirmedGood ? .confirmedGood : .good
} else {
currentSignalStatus = .poor
}
}
} else {
currentSignalStatus = .noSignal // Invalid value or doesn't exist.
}
delegate?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
bluetoothDebugger?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
}
}
// MARK:- Handle Signal History
private func resetSignalStrengthCheckValue() {
signalStrengthCheckStatus = .idle
signalStrengthObserverTimer?.invalidate()
signalStrengthObserverTimer = nil
lastSignalStatusTimeStamp = nil
signalStrengthGoodTotalTime = 0
signalStrengthFailTotalTime = 0
}
func checkSignalStrengthContinueRequired() {
let lastTrackDate = lastSignalStatusTimeStamp ?? Date()
if [.good, .confirmedGood].contains(currentSignalStatus) {
signalStrengthGoodTotalTime += Date().timeIntervalSince(lastTrackDate)
} else {
signalStrengthFailTotalTime += Date().timeIntervalSince(lastTrackDate)
}
lastSignalStatusTimeStamp = Date()
evaluateSignalStrength()
}
private func evaluateSignalStrength() {
let maxFailPercentage = 100 - signalPassingPercentage
let maxFailTime = (maxFailPercentage / 100) * signalStrengthObserveDuration
let maxPassTime = (signalPassingPercentage / 100) * signalStrengthObserveDuration
#if DEBUG
print("[ MFFGHSBluetoothPair ] Good Signal Time >>>> \(signalStrengthGoodTotalTime)")
print("[ MFFGHSBluetoothPair ] Bad Signal Time >>>> \(signalStrengthFailTotalTime)")
#endif
if signalStrengthFailTotalTime > maxFailTime {
// already Fail, stop testing
resetSignalStrengthCheckValue()
signalStrengthCheckStatus = .complete
currentSignalStatus = .confirmedPoor
delegate?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
bluetoothDebugger?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
} else if signalStrengthGoodTotalTime >= maxPassTime || signalStrengthCheckStatus == .complete {
// already PASS. stop testing and handle
resetSignalStrengthCheckValue()
signalStrengthCheckStatus = .complete
currentSignalStatus = .confirmedGood
delegate?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
bluetoothDebugger?.updateCurrentSignalStatus(currentSignalStatus, strengthCheckStatus: signalStrengthCheckStatus, rssi: currentRSSIValue)
} else {
//contiue
}
}
public func startSignalStrengthCheckValue(duration: TimeInterval, percentage: Double){
if signalStrengthCheckStatus != .processing {
resetSignalStrengthCheckValue()
signalStrengthObserveDuration = duration
signalPassingPercentage = percentage
if currentSignalStatus == .confirmedGood {
currentSignalStatus = .good
}
signalStrengthCheckStatus = .processing
lastSignalStatusTimeStamp = Date()
signalStrengthObserverTimer = Timer(timeInterval: (signalStrengthObserveDuration + 0.3), repeats: false) { (timer) in
#if DEBUG
print("[ MFFGHSBluetoothPair ] Signal Test Timeout")
#endif
self.signalStrengthCheckStatus = .complete
self.checkSignalStrengthContinueRequired()
}
RunLoop.main.add(signalStrengthObserverTimer!, forMode: .common)
}
}
// MARK:- Utility Functions
func parseRSRPFromJSON(fiveGData: [String: Any]) -> Double? {
return fiveGData["SS-RSRP"] as? Double ?? nil
}
// MARK:- Analytics
func track(_ data: [String: Any]) {
if let _delegate = delegate {
trackGemini(value: data.merging(["delegateName": String(describing: _delegate)]) { $1 }, logType: .BLE)
}
}
// MARK: BluetoothConfigModel methods
var rssiThreshold: Double {
return bluetoothConfig?.bleSignalThreshold ?? 0
}
var lowerThreshold: Double {
return bluetoothConfig?.bleSignalLowerBound ?? 0
}
var higherThreshold: Double {
return bluetoothConfig?.bleSignalUpperBound ?? 0
}
func getBleAdvertiseUUIDs() -> [CBUUID] {
return bluetoothConfig?.peripherals.map{ $0.uuid } ?? []
}
open func getBleAdvertiseName() -> String {
return bluetoothConfig?.advertisedData ?? ""
}
func getSeviceUUIDs() -> [CBUUID] {
return bluetoothConfig?.services.map { $0.uuid } ?? []
}
func getCharacteristicUUIDs(serviceId: CBUUID) -> [CBUUID] {
return bluetoothConfig?.services.first?.characteristics.map { $0.uuid } ?? []
}
}

View File

@ -0,0 +1,17 @@
import MVMCore
import MVMCoreUI
extension ViewController {
public func fivegBLEConfig() throws -> BluetoothConfigModel {
guard let json = loadObject?.modulesJSON?.dictionaryWithChainOfKeysOrIndexes(["fivegBleUuid", "fivegBleUuid"]) else {
throw BluetoothConfigError.noJSONFound
}
return try BluetoothConfigModel.decode(jsonDict: json, delegateObject: nil)
}
}
extension Collection {
var isNotEmpty: Bool {
return !isEmpty
}
}

View File

@ -0,0 +1,103 @@
//
// BluetoothConfig.swift
// MVM5G
//
// Created by Matt Bruce on 4/13/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import CoreBluetooth
import MVMCore
public enum BluetoothConfigError: Error, LocalizedError, CustomStringConvertible {
case decode(key: String)
case noJSONFound
public var description: String {
switch self {
case .decode:
return GMFGConstant.BLE.LogMsg.bleDecodeError
case .noJSONFound:
return GMFGConstant.BLE.LogMsg.bleModuleMissing
}
}
public var errorDescription: String? {
return description
}
}
public struct BluetoothConfigModel: Codable, Equatable {
var advertisedData: String
var pin: String
var bleAPIVersion: Double
var bleSignalThreshold: Double
var bleSignalLowerBound: Double
var bleSignalUpperBound: Double
var peripherals: [PeripheralModel]
var services: [ServiceModel]
var logger: ((String, String, [String: Any])-> Void)?
enum CodingKeys: String, CodingKey {
case bleAPIVersion
case pin
case bleSignalThreshold
case bleSignalLowerBound
case bleSignalUpperBound
case advertisedData
case bleAdv
case service
}
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
let _bleAPIVersion = try typeContainer.decode(String.self, forKey: .bleAPIVersion, objectType: BluetoothConfigModel.self)
let _bleSignalThreshold = try typeContainer.decode(String.self, forKey: .bleSignalThreshold, objectType: BluetoothConfigModel.self)
let _bleSignalLowerBound = try typeContainer.decode(String.self, forKey: .bleSignalLowerBound, objectType: BluetoothConfigModel.self)
let _bleSignalUpperBound = try typeContainer.decode(String.self, forKey: .bleSignalUpperBound, objectType: BluetoothConfigModel.self)
guard let double = Double(_bleAPIVersion) else {
throw BluetoothConfigError.decode(key: "bleAPIVersion: \(_bleAPIVersion)")
}
bleAPIVersion = double
guard let double = Double(_bleSignalThreshold) else {
throw BluetoothConfigError.decode(key: "bleSignalThreshold: \(_bleSignalThreshold)")
}
bleSignalThreshold = double
guard let double = Double(_bleSignalLowerBound) else {
throw BluetoothConfigError.decode(key: "bleSignalLowerBound: \(_bleSignalLowerBound)")
}
bleSignalLowerBound = double
guard let double = Double(_bleSignalUpperBound) else {
throw BluetoothConfigError.decode(key: "bleSignalUpperBound: \(_bleSignalUpperBound)")
}
bleSignalUpperBound = double
pin = try typeContainer.decode(String.self, forKey: .pin, objectType: BluetoothConfigModel.self)
advertisedData = try typeContainer.decode(String.self, forKey: .advertisedData, objectType: BluetoothConfigModel.self)
peripherals = try typeContainer.decode([PeripheralModel].self, forKey: .bleAdv, objectType: BluetoothConfigModel.self)
services = try typeContainer.decode([ServiceModel].self, forKey: .service, objectType: BluetoothConfigModel.self)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(bleAPIVersion, forKey: .bleAPIVersion)
try container.encode(pin, forKey: .pin)
try container.encode(bleSignalThreshold, forKey: .bleSignalThreshold)
try container.encode(bleSignalLowerBound, forKey: .bleSignalLowerBound)
try container.encode(bleSignalUpperBound, forKey: .bleSignalUpperBound)
try container.encode(advertisedData, forKey: .advertisedData)
try container.encode(peripherals, forKey: .bleAdv)
try container.encode(services, forKey: .service)
}
public static func == (lhs: BluetoothConfigModel, rhs: BluetoothConfigModel) -> Bool {
return lhs.advertisedData == rhs.advertisedData &&
lhs.pin == rhs.pin &&
lhs.peripherals == rhs.peripherals &&
lhs.services == rhs.services
}
}

View File

@ -0,0 +1,44 @@
//
// Characteristic.swift
// MVM5G
//
// Created by Matt Bruce on 4/13/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import CoreBluetooth
protocol CBUUIDIdentifiable {
var uuid: CBUUID { get set}
}
public enum CharacteristicType: String {
case speedTest = "RouterSpeedTest"
case speedTestResults = "RouterSpeedTestResults"
case internetAccess = "RouterPublicInternetAccess"
case operationMode = "ReceiverMode"
case fotaCheck = "FOTACheck"
case fotaStatus = "FOTAStatus"
case fourGSignal = "Fourg"
case fiveGSignal = "Fiveg"
case fiveGCBandSignal = "FivegCBand"
case routerWiFi = "RouterWifi"
case routerMode = "RouterMode"
case repeaterOperations = "RepeaterOperations"
case repeaterPairStatus = "RepeaterPairStatus"
case repeaterMode = "RepeaterMode"
case repeaterPair = "RepeaterPair"
case radiocontrol = "Radiocontrol"
case activation = "Activation"
case unknown = "unknown"
}
public struct CharacteristicModel: CBUUIDIdentifiable, Equatable{
var uuid: CBUUID
var name: CharacteristicType
public static func == (lhs: CharacteristicModel, rhs: CharacteristicModel) -> Bool {
return lhs.uuid == rhs.uuid && lhs.name == rhs.name
}
}

View File

@ -0,0 +1,34 @@
//
// Peripheral.swift
// MVM5G
//
// Created by Matt Bruce on 4/13/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import CoreBluetooth
public struct PeripheralModel: CBUUIDIdentifiable, Codable, Equatable {
var uuid: CBUUID
enum CodingKeys: String, CodingKey {
case uuid
}
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
let _uuid = try typeContainer.decode(String.self, forKey: .uuid)
uuid = CBUUID(string: _uuid)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(uuid.uuidString, forKey: .uuid)
}
public static func == (lhs: PeripheralModel, rhs: PeripheralModel) -> Bool {
return lhs.uuid == rhs.uuid
}
}

View File

@ -0,0 +1,44 @@
//
// Service.swift
// MVM5G
//
// Created by Matt Bruce on 4/13/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import CoreBluetooth
public struct ServiceModel: CBUUIDIdentifiable, Codable, Equatable {
var uuid: CBUUID
var characteristics: [CharacteristicModel]
enum CodingKeys: String, CodingKey {
case uuid
case characteristicUUID
}
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
let _uuid = try typeContainer.decode(String.self, forKey: .uuid)
uuid = CBUUID(string: _uuid)
let _characteristics = try typeContainer.decode([String: String].self, forKey: .characteristicUUID)
characteristics = _characteristics.map { key, value in
return CharacteristicModel(uuid: CBUUID(string: value), name: CharacteristicType(rawValue: key) ?? .unknown)
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(uuid.uuidString, forKey: .uuid)
var _characteristics: [String: String] = [:]
characteristics.forEach { c in
_characteristics[c.name.rawValue] = c.uuid.uuidString
}
try container.encode(_characteristics, forKey: .characteristicUUID)
}
public static func == (lhs: ServiceModel, rhs: ServiceModel) -> Bool {
return lhs.uuid == rhs.uuid && lhs.characteristics == rhs.characteristics
}
}

View File

@ -0,0 +1,65 @@
//
// BluetoothPairableProtocol.swift
// MVM5G
//
// Created by Matt Bruce on 4/15/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
import MVMCore
import MVMCoreUI
/// This Protocol will be implemented by UI
protocol BluetoothPairableProtocol: AnyObject {
associatedtype BluetoothPairingType: BluetoothParingProtocol
var bluetoothPair: BluetoothPairingType? { get set }
func setBluetoothConfig() -> Bool
func track(_ message: Any, logType: AnalyticsLogType)
}
extension BluetoothPairableProtocol where Self: ViewController, Self: MFFGHSAnalyticsProtocol {
@discardableResult
func setBluetoothConfig() -> Bool {
do {
let config = try fivegBLEConfig()
bluetoothPair?.bluetoothConfig = config
return true
} catch {
track(error.localizedDescription)
return false
}
}
func track(_ message: Any, logType: AnalyticsLogType = .UI) {
if let message = message as? String {
trackGemini(value: [KeyMessage: message], logType: logType, pageInfo: AnalyticsPageInfo(pageType: loadObject?.pageType))
} else if let dict = message as? [String: Any] {
trackGemini(value: dict, logType: logType, pageInfo: AnalyticsPageInfo(pageType: loadObject?.pageType))
}
}
}
extension BluetoothPairableProtocol where Self: ViewController, Self: MFFGHSAnalyticsProtocol, Self: BluetoothDebuggableProtocol {
@discardableResult
func setBluetoothConfig() -> Bool {
do {
let config = try fivegBLEConfig()
bluetoothPair?.setup(config: config, delegate: self)
return true
} catch {
track(error.localizedDescription)
return false
}
}
func track(_ message: Any, logType: AnalyticsLogType = .UI) {
if let message = message as? String {
bluetoothDebugger?.addLog(message: message)
trackGemini(value: [KeyMessage: message], logType: logType, pageInfo: AnalyticsPageInfo(pageType: loadObject?.pageType))
} else if let dict = message as? [String: Any] {
bluetoothDebugger?.addLog(message: dict.description)
trackGemini(value: dict, logType: logType, pageInfo: AnalyticsPageInfo(pageType: loadObject?.pageType))
}
}
}

View File

@ -0,0 +1,32 @@
//
// BluetoothPairingProtocol.swift
// MVM5G
//
// Created by Matt Bruce on 4/15/22.
// Copyright © 2022 Kyle. All rights reserved.
//
import Foundation
/// This Protocol will be implemented by a variation of BluetoothPairing Classes
protocol BluetoothParingProtocol: AnyObject, MFFGHSAnalyticsProtocol {
var bluetoothConfig: BluetoothConfigModel? { get set }
var bluetoothDebugger: BluetoothDebugger? { get set }
func getBleAdvertiseName() -> String
func track(_ data: [String: Any])
func track(_ message: String, function: String, additionalData: [String: Any])
}
extension BluetoothParingProtocol {
func track(_ message: String, function: String = #function, additionalData: [String: Any] = [:]) {
guard bluetoothConfig != nil else { return }
let data = additionalData.values.isEmpty ? "" : "\r \(additionalData)"
bluetoothDebugger?.addLog(message: "\(message)\(data)")
trackGemini(value: ([GMFGConstant.functionName: function,
GMFGConstant.BLE.advertisedData: getBleAdvertiseName(),
"message": message
]).merging(additionalData, uniquingKeysWith: { $1 }), logType: .BLE)
}
}

View File

@ -0,0 +1,105 @@
//
// GMFG5GSignalHandler.swift
// MVM5G
//
// Created by Jason Beck on 5/11/21.
// Copyright © 2021 Kyle. All rights reserved.
//
import CoreBluetooth
protocol GMFG5GCBandSignalDelegate: AnyObject {
func updated5GCBandSignal(_ update: GMFG5GCBandSignalUpdate)
func signal5GCBandNotReady()
}
private enum ResultKeys: String {
case signalNoiseRatio = "SINR"
case referencePower = "RSRP"
case pci = "PCI"
case ssbIndex = "SSBI"
case referenceSignalQuality = "RSRQ"
case modulationOrder = "MO"
case mcsIndex = "MCS " //This is on purpose. The firmware has a trailing space in the key name.
case arfcn5G = "5GARFCN"
case ledColor = "LED"
}
struct GMFG5GCBandSignalUpdate {
var signalToNoiseRatio: Int = 0
var referencePower: Int = 0
var pci: Int = 0
var ssbIndex: Int = 0
var referenceSignalQuality: Int = 0
var modulationOrder: String = "NA"
var mcsIndex: Int = 0
var arfcn5G: Int = 0
var ledColor: GMFGCPELEDColor?
var rawResults: [String: Any]?
}
class GMFG5GCBandSignalHandler: GMFGBLEHandlerProtocol {
private let multicast = MulticastDelegate<GMFG5GCBandSignalDelegate>()
public func setDelegate(delegates: [GMFG5GCBandSignalDelegate?]) {
multicast.add(delegates: delegates)
}
public func reset() {
multicast.removeAll()
}
//MARK:- Helper
private func rawKey(_ type: ResultKeys) -> String { return type.rawValue }
private func rawStatus(_ type: GMFGCPELEDColor) -> String { return type.rawValue }
public func get5GSignal(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
peripheral.readValue(for: characteristic)
}
//It is possible to try and call the device before it's done loading
public func deviceNotReady() {
multicast.invokeForEachDelegate{ $0.signal5GCBandNotReady() }
}
public func response(response: [String : Any]) {
if let validResponse = responseFormat(response: response) {
multicast.invokeForEachDelegate{ $0.updated5GCBandSignal(validResponse) }
}
}
func responseFormat(response: [String: Any]) -> GMFG5GCBandSignalUpdate? {
guard let fiveGData = response["5GSignal"] as? [String: Any] else {
return nil
}
var returnSignal = GMFG5GCBandSignalUpdate()
if let signalToNoise = (fiveGData[rawKey(.signalNoiseRatio)] as? String), let snrInt = Int(signalToNoise) {
returnSignal.signalToNoiseRatio = snrInt
}
if let referenceSignalPower = (fiveGData[rawKey(.referencePower)] as? String), let refPowerInt = Int(referenceSignalPower) {
returnSignal.referencePower = refPowerInt
}
if let fiveGARFCN = (fiveGData[rawKey(.arfcn5G)] as? String), let arfcnInt = Int(fiveGARFCN) {
returnSignal.arfcn5G = arfcnInt
}
if let referenceQuality = (fiveGData[rawKey(.referenceSignalQuality)] as? String), let sqInt = Int(referenceQuality) {
returnSignal.referenceSignalQuality = sqInt
}
if let ssbi = (fiveGData[rawKey(.ssbIndex)] as? String), let ssbInt = Int(ssbi) {
returnSignal.ssbIndex = ssbInt
}
if let ledColorRaw = (fiveGData[rawKey(.ledColor)] as? String), let ledColor = GMFGCPELEDColor(rawValue: ledColorRaw) {
returnSignal.ledColor = ledColor
}
if let mcs = (fiveGData[rawKey(.mcsIndex)] as? String), let mcsInt = Int(mcs) {
returnSignal.mcsIndex = mcsInt
}
if let pci = (fiveGData[rawKey(.pci)] as? String), let pciInt = Int(pci) {
returnSignal.pci = pciInt
}
if let mo = (fiveGData[rawKey(.modulationOrder)] as? String) {
returnSignal.modulationOrder = mo
}
returnSignal.rawResults = fiveGData
return returnSignal
}
}

View File

@ -0,0 +1,111 @@
//
// GMFG5GSignalHandler.swift
// MVM5G
//
// Created by Jason Beck on 5/11/21.
// Copyright © 2021 Kyle. All rights reserved.
//
import CoreBluetooth
protocol GMFG5GSignalDelegate: AnyObject {
func updated5GSignal(_ update: GMFG5GSignalUpdate)
func signalNotReady()
}
private enum ResultKeys: String {
case signalNoiseRatio = "SINR"
case referencePower = "RSRP"
case pci = "PCI"
case ssbIndex = "SSBI"
case referenceSignalQuality = "RSRQ"
case modulationOrder = "MO"
case mcsIndex = "MCS " //This is on purpose. The firmware has a trailing space in the key name.
case arfcn5G = "5GARFCN"
case ledColor = "LED"
}
enum GMFGCPELEDColor: String {
case red = "R"
case yellow = "Y"
case green = "G"
}
struct GMFG5GSignalUpdate {
var signalToNoiseRatio: Int = 0
var referencePower: Int = 0
var pci: Int = 0
var ssbIndex: Int = 0
var referenceSignalQuality: Int = 0
var modulationOrder: String = "NA"
var mcsIndex: Int = 0
var arfcn5G: Int = 0
var ledColor: GMFGCPELEDColor?
var rawResults: [String: Any]?
}
class GMFG5GSignalHandler: GMFGBLEHandlerProtocol {
private let multicast = MulticastDelegate<GMFG5GSignalDelegate>()
public func setDelegate(delegates: [GMFG5GSignalDelegate?]) {
multicast.add(delegates: delegates)
}
public func reset() {
multicast.removeAll()
}
//MARK:- Helper
private func rawKey(_ type: ResultKeys) -> String { return type.rawValue }
private func rawStatus(_ type: GMFGCPELEDColor) -> String { return type.rawValue }
public func get5GSignal(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
peripheral.readValue(for: characteristic)
}
//It is possible to try and call the device before it's done loading
public func deviceNotReady() {
multicast.invokeForEachDelegate{ $0.signalNotReady() }
}
public func response(response: [String : Any]) {
if let validResponse = responseFormat(response: response) {
multicast.invokeForEachDelegate{ $0.updated5GSignal(validResponse) }
}
}
func responseFormat(response: [String: Any]) -> GMFG5GSignalUpdate? {
guard let fiveGData = response["5GSignal"] as? [String: Any] else {
return nil
}
var returnSignal = GMFG5GSignalUpdate()
if let signalToNoise = (fiveGData[rawKey(.signalNoiseRatio)] as? String), let snrInt = Int(signalToNoise) {
returnSignal.signalToNoiseRatio = snrInt
}
if let referenceSignalPower = (fiveGData[rawKey(.referencePower)] as? String), let refPowerInt = Int(referenceSignalPower) {
returnSignal.referencePower = refPowerInt
}
if let fiveGARFCN = (fiveGData[rawKey(.arfcn5G)] as? String), let arfcnInt = Int(fiveGARFCN) {
returnSignal.arfcn5G = arfcnInt
}
if let referenceQuality = (fiveGData[rawKey(.referenceSignalQuality)] as? String), let sqInt = Int(referenceQuality) {
returnSignal.referenceSignalQuality = sqInt
}
if let ssbi = (fiveGData[rawKey(.ssbIndex)] as? String), let ssbInt = Int(ssbi) {
returnSignal.ssbIndex = ssbInt
}
if let ledColorRaw = (fiveGData[rawKey(.ledColor)] as? String), let ledColor = GMFGCPELEDColor(rawValue: ledColorRaw) {
returnSignal.ledColor = ledColor
}
if let mcs = (fiveGData[rawKey(.mcsIndex)] as? String), let mcsInt = Int(mcs) {
returnSignal.mcsIndex = mcsInt
}
if let pci = (fiveGData[rawKey(.pci)] as? String), let pciInt = Int(pci) {
returnSignal.pci = pciInt
}
if let mo = (fiveGData[rawKey(.modulationOrder)] as? String) {
returnSignal.modulationOrder = mo
}
returnSignal.rawResults = fiveGData
return returnSignal
}
}

View File

@ -0,0 +1,132 @@
//
// GMFGFotaHandler.swift
// MVM5G
//
// Created by Jason Beck on 4/20/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import CoreBluetooth
private enum GMFotaKey: String {
case status = "FOTAStatus"
case error = "ErrorMessage"
case version = "FirmwareVersion"
case check = "Check"
case fotaOp = "FOTAOperation"
}
public enum GMFotaStatus: String {
case notReady = "NotReady"
case latest = "Latest"
case available = "NewAvailable"
case success = "SuccessfulUpgrade"
case fail = "FailedUpgrade"
case failDownload = "FailedDownload"
case progress = "DownloadProgress"
case upgrading = "Upgrading"
}
protocol GMFGFotaDelegate: AnyObject {
func didStartUpdate()
func fotaStatus(statusResponse: GMFotaResponse)
func unknownResponse(rawResponse: [String: Any]?)
}
extension GMFGFotaDelegate {
func didStartUpdate() {}
}
final class GMFotaResponse: CustomStringConvertible {
var status: GMFotaStatus
var errorMsg: String?
private var _version = ""
var version: String {
set {
if (newValue.isEmpty) || (newValue == "XXX.YYY.ZZZZ") || (newValue == "Unknown") {
_version = "0.0.0.0"
} else {
_version = newValue
}
}
get {
return _version
}
}
var rawResponse: [String: Any]
init(status: GMFotaStatus, version: String, rawResponse: [String: Any]) {
self.status = status
self.rawResponse = rawResponse
self.version = version
}
var description: String {
return """
Status: \(self.status.rawValue)
Error Message: \(self.errorMsg ?? GMFGConstant.empty)
Version: \(self.version)
Raw Response:\n\(self.rawResponse)
"""
}
}
final class GMFGFotaHandler: GMFGBLEHandlerProtocol {
private let multicast = MulticastDelegate<GMFGFotaDelegate>()
public func setDelegate(delegates: [GMFGFotaDelegate?]) {
self.multicast.add(delegates: delegates)
}
public func reset() {
self.multicast.removeAll()
}
//MARK:- Helper
private func rawKey(_ type: GMFotaKey) -> String { return type.rawValue }
private func rawStatus(_ type: GMFotaStatus) -> String { return type.rawValue }
//MARK:- Fota Functions
public func requestVersion(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
peripheral.readValue(for: characteristic)
}
public func startUpdate(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
let requestValue = [rawKey(.fotaOp): rawKey(.check)]
guard let data = convertToData(requestValue) else { return }
let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
peripheral.writeValue(data, for: characteristic, type: writeType)
multicast.invokeForEachDelegate { $0.didStartUpdate() }
}
public func response(response: [String : Any]) {
let status: GMFotaStatus!
var version = "0.0.0.0"
guard let statusString = response[rawKey(.status)] as? String else {
multicast.invokeForEachDelegate{ $0.unknownResponse(rawResponse: response) }
return
}
if statusString.contains("DownloadProgress") {
status = .progress
} else if let _status = GMFotaStatus(rawValue: statusString),
let _version = response[rawKey(.version)] as? String {
status = _status
version = _version
} else {
multicast.invokeForEachDelegate{ $0.unknownResponse(rawResponse: response) }
return
}
let responseObj = GMFotaResponse(status: status, version: version, rawResponse: response)
responseObj.errorMsg = response[rawKey(.error)] as? String
multicast.invokeForEachDelegate{ $0.fotaStatus(statusResponse: responseObj) }
}
public func deviceNotReady() {
let responseObj = GMFotaResponse(status: .notReady, version: "Unknown", rawResponse: [:])
multicast.invokeForEachDelegate{ $0.fotaStatus(statusResponse: responseObj) }
}
}

View File

@ -0,0 +1,34 @@
//
// GMFGOperationHandler.swift
// MVM5G
//
// Created by Jason Beck on 7/28/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import CoreBluetooth
enum GMFGOperationMode: String {
case installation = "Installation"
case operational = "Operational"
}
class GMFGOperationHandler: GMFGBLEHandlerProtocol {
public func setOpMode(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, mode: GMFGOperationMode, disableBLE: Bool = false) -> Bool {
var requestValue: [String: Any] = ["ReceiverMode": mode.rawValue]
if disableBLE {
requestValue["DisableBLE"] = disableBLE
}
guard let data = convertToData(requestValue) else { return false }
let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
peripheral.writeValue(data, for: characteristic, type: writeType)
return true
}
func response(response: [String : Any]) {
//This class does not currently respond to the VC, so this function is here only to satisfy protocol conformance
}
func deviceNotReady() {
//This class does not currently respond to the VC, so this function is here only to satisfy protocol conformance
}
}

View File

@ -0,0 +1,47 @@
//
// GMFGPublicInternetAccessHandler.swift
// MVM5G
//
// Created by Jason Beck on 5/27/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import CoreBluetooth
protocol GMFGPublicInternetAccessDelegate: AnyObject {
func publicInternetAccessStatus(status: GMPublicInternetAccessStatus)
}
enum GMPublicInternetAccessStatus: String {
case enabled = "Enabled"
case disabled = "Disabled"
case notReady = "NotReady"
}
class GMFGPublicInternetAccessHandler: GMFGBLEHandlerProtocol {
private let multicast = MulticastDelegate<GMFGPublicInternetAccessDelegate>()
public func setDelegate(delegates: [GMFGPublicInternetAccessDelegate?]) {
self.multicast.add(delegates: delegates)
}
public func reset() {
self.multicast.removeAll()
}
public func getPublicInternetAccess(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
peripheral.readValue(for: characteristic)
}
public func response(response: [String : Any]) {
guard let statusString = response["PublicInternetAccess"] as? String, let statusEnum = GMPublicInternetAccessStatus.init(rawValue: statusString) else {
return
}
multicast.invokeForEachDelegate{ $0.publicInternetAccessStatus(status: statusEnum) }
reset()
}
public func deviceNotReady() {
multicast.invokeForEachDelegate{ $0.publicInternetAccessStatus(status: .notReady) }
}
}

View File

@ -0,0 +1,51 @@
//
// GMFGRouterWifiHandler.swift
// MVM5G
//
// Created by Rajesh on 12/9/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import Foundation
import CoreBluetooth
protocol GMFGRouterWifiDelegate: AnyObject {
func routerWifi(credentials: GMFGRouterWifiInfo)
func routerWifiStatus(status: GMFGRouterWifiStatus)
}
struct GMFGRouterWifiInfo {
var ssid: String
var password: String
}
enum GMFGRouterWifiStatus: String {
case disabled = "Disabled"
case notReady = "NotReady"
}
class GMFGRouterWifiHandler: GMFGBLEHandlerProtocol {
private let multicast = MulticastDelegate<GMFGRouterWifiDelegate>()
public func setDelegate(delegates: [GMFGRouterWifiDelegate?]) {
self.multicast.add(delegates: delegates)
}
public func reset() {
self.multicast.removeAll()
}
public func fetchRouterWifiCredentials(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
peripheral.readValue(for: characteristic)
}
public func response(response: [String : Any]) {
guard let wifiSSID = response["SSID"] as? String, let wifiPwd = response["Password"] as? String else { return }
multicast.invokeForEachDelegate{ $0.routerWifi(credentials: GMFGRouterWifiInfo.init(ssid: wifiSSID, password: wifiPwd)) }
reset()
}
public func deviceNotReady() {
multicast.invokeForEachDelegate{ $0.routerWifiStatus(status: .notReady) }
}
}

View File

@ -0,0 +1,141 @@
//
// GMFGSpeedTestHandler.swift
// MVM5G
//
// Created by Jason Beck on 5/26/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import CoreBluetooth
protocol GMFGSpeedTestDelegate: AnyObject {
func didStartSpeedTest()
func didStopSpeedTest()
func speedTestStatus(status: GMFGSpeedTestUpdate)
}
extension GMFGSpeedTestDelegate {
func didStartSpeedTest(){}
func didStopSpeedTest(){}
}
private enum ResultKeys: String {
case result = "Result"
case speedTestServer = "SIP"
case speedTestServerID = "SID"
case routerIP = "RIP"
case downlink = "DL"
case uplink = "UL"
case latency = "Lat"
case jitter = "Jitt"
case progress = "Prog"
case errorMessage = "Error"
}
enum Status: String {
case ready = "Ready"
case running = "Running"
case failed = "Failed"
case done = "Done"
case notReady = "NotReady"
}
struct GMFGSpeedTestUpdate {
var result: Status
var speedTestServerIP: String?
var speedTestServerID: Int?
var routerIP: String?
var downlink: String?
var uplink: String?
var latency: String?
var jitter: Int?
var progress: Double?
var errorMessage: String?
var rawResults: [String: Any]?
func getDictFromSelf() -> [String: Any]? {
let dataDict: [String: Any] = [
ResultKeys.result.rawValue : result.rawValue,
ResultKeys.speedTestServer.rawValue : speedTestServerIP ?? GMFGConstant.empty,
ResultKeys.speedTestServerID.rawValue: speedTestServerID ?? -1,
ResultKeys.routerIP.rawValue : routerIP ?? GMFGConstant.empty,
ResultKeys.downlink.rawValue : downlink ?? GMFGConstant.empty,
ResultKeys.uplink.rawValue : uplink ?? GMFGConstant.empty,
ResultKeys.latency.rawValue : latency ?? GMFGConstant.empty,
ResultKeys.jitter.rawValue : jitter ?? -1,
ResultKeys.progress.rawValue : progress ?? 0.0,
ResultKeys.errorMessage.rawValue : errorMessage ?? GMFGConstant.empty
]
return dataDict
}
}
class GMFGSpeedTestHandler: GMFGBLEHandlerProtocol {
private let multicast = MulticastDelegate<GMFGSpeedTestDelegate>()
public func setDelegate(delegates: [GMFGSpeedTestDelegate?]) {
self.multicast.add(delegates: delegates)
}
public func reset() {
multicast.removeAll()
}
//MARK:- Helper
private func rawKey(_ type: ResultKeys) -> String { return type.rawValue }
private func rawStatus(_ type: Status) -> String { return type.rawValue }
public func start(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
let requestValue = ["SpeedTest": "Start"]
guard let data = convertToData(requestValue) else { return }
let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
peripheral.writeValue(data, for: characteristic, type: writeType)
multicast.invokeForEachDelegate{ $0.didStartSpeedTest() }
//Notify process started having status = running
let responseObj = GMFGSpeedTestUpdate(result: .running)
multicast.invokeForEachDelegate{ $0.speedTestStatus(status: responseObj) }
}
public func stop(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
let requestValue = ["SpeedTest": "Stop"]
guard let data = convertToData(requestValue) else { return }
let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
peripheral.writeValue(data, for: characteristic, type: writeType)
multicast.invokeForEachDelegate{ $0.didStopSpeedTest() }
}
public func update(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic) {
peripheral.readValue(for: characteristic)
}
//It is possible to try and call the device before it's done loading
public func deviceNotReady() {
let responseObj = GMFGSpeedTestUpdate(result: .notReady)
multicast.invokeForEachDelegate{ $0.speedTestStatus(status: responseObj) }
}
public func response(response: [String : Any]) {
guard let statusString = response[rawKey(.result)] as? String,
let status = Status(rawValue: statusString) else {
return
}
let responseObj = responseFormat(status: status, response: response)
if responseObj.result == .done || responseObj.result == .failed {
multicast.invokeForEachDelegate{ $0.didStopSpeedTest() }
}
multicast.invokeForEachDelegate{ $0.speedTestStatus(status: responseObj) }
}
func responseFormat(status: Status, response: [String: Any]) -> GMFGSpeedTestUpdate {
return GMFGSpeedTestUpdate(result: status, speedTestServerIP: response[rawKey(.speedTestServer)] as? String,
speedTestServerID: response[rawKey(.speedTestServerID)] as? Int,
routerIP: response[rawKey(.routerIP)] as? String,
downlink: response[rawKey(.downlink)] as? String,
uplink: response[rawKey(.uplink)] as? String,
latency: response[rawKey(.latency)] as? String,
jitter: response[rawKey(.jitter)] as? Int,
progress: (response[rawKey(.progress)] as? NSString)?.doubleValue,
errorMessage: response[rawKey(.errorMessage)] as? String, rawResults: response)
}
}

View File

@ -0,0 +1,509 @@
//
// GMFGBluetoothPair.swift
// MobileFirstFramework
//
// Created by Chowdhury, Shohrab on 4/20/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import CoreBluetooth
class GMFGBluetoothPair: MFFGHSBluetoothPair {
private static weak var ginstance: GMFGBluetoothPair?
static var shared: GMFGBluetoothPair {
get {
if let ginstance = ginstance {
return ginstance
} else {
let newInstance = GMFGBluetoothPair()
ginstance = newInstance
return newInstance
}
}
}
override var bluetoothConfig: BluetoothConfigModel? {
didSet {
if (oldValue != bluetoothConfig) { // TODO: Needs deep check for config changes.
setupBluetoothScanner(showPowerAlert: true)
}
}
}
override func shutdown() {
super.shutdown()
GMFGBluetoothPair.ginstance = nil
}
typealias ResponseHandler = ([String : Any]) -> Void
private var speedTestHandler = GMFGSpeedTestHandler()
private var internetAccessHandler = GMFGPublicInternetAccessHandler()
private var routerWifiHandler = GMFGRouterWifiHandler()
private var operationModeHandler = GMFGOperationHandler()
private var fotaHandler = GMFGFotaHandler()
private var fiveGSignalHandler = GMFG5GSignalHandler()
private var fiveGCBandSignalHandler = GMFG5GCBandSignalHandler()
private var responseHandlers: [CBUUID: ResponseHandler] = [:]
private var max5GSignal: Double?
var max5GSignalSeen: Double? {
set {
if (max5GSignal == nil && newValue != nil) || (max5GSignal != nil && newValue == nil) {
max5GSignal = newValue
return
}
guard let value = newValue, let maxSignal = max5GSignal else { return }
if value > maxSignal { max5GSignal = newValue }
}
get { return max5GSignal }
}
private var min5GSignal: Double?
var min5GSignalSeen: Double? {
set {
if (min5GSignal == nil && newValue != nil) || (min5GSignal != nil && newValue == nil) {
min5GSignal = newValue
return
}
guard let value = newValue, let minSignal = min5GSignal else { return }
if value < minSignal { min5GSignal = newValue }
}
get { return min5GSignal }
}
var samples5GSignalSeen = 0
public class func isValidAdvertisedData(_ testData: String) -> Bool {
return testData.contains(GMFGConstant.BLE.advertisePrefix) && testData.count == 20
}
// MARK:- Notification Functions
func updateAllNotifyValue(_ shouldNotify: Bool) {
if let _peripheral = peripheral, let services = _peripheral.services {
for service in services {
if let characteristics = service.characteristics {
for characteristic in characteristics {
if characteristic.isNotifying {
_peripheral.setNotifyValue(shouldNotify, for: characteristic)
}
}
}
}
}
}
@discardableResult func sendNotifications(for characteristic: CharacteristicType, shouldNotify: Bool) -> Bool {
if let _peripheral = peripheral, let _characteristic = getCharacteristic(peripheral: _peripheral, fromType: characteristic) {
_peripheral.setNotifyValue(shouldNotify, for: _characteristic)
return true
}
return false
}
/// This will ensure that the handlers are registered only once
/// All this logic was originally happening in a case statement
/// therefore each comparison / lookup was happening everytime
/// the callback occurred. This is registering a characteric to a handler
/// which happens 1 time and used then with a dictionary lookup for the handler.
/// - Parameter peripheral: comes in from delegate callback
func ensureResponseHandlers(peripheral: CBPeripheral) {
//compare local peripheral vs one passed in
//make sure bluetoothConfig is set
//make sure there are no responseHandlers registered
guard let localPeripheral = self.peripheral,
peripheral.identifier == localPeripheral.identifier,
responseHandlers.isEmpty,
bluetoothConfig != nil else { return }
// activation
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .activation)?.uuid {
responseHandlers[uuid] = handleActivated(response:)
}
// speedTest
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .speedTest)?.uuid {
responseHandlers[uuid] = speedTestHandler.response(response:)
}
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .speedTestResults)?.uuid {
responseHandlers[uuid] = speedTestHandler.response(response:)
}
//internetAccess
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .internetAccess)?.uuid {
responseHandlers[uuid] = internetAccessHandler.response(response:)
}
//fota
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .fotaCheck)?.uuid {
responseHandlers[uuid] = fotaHandler.response(response:)
}
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .fotaStatus)?.uuid {
responseHandlers[uuid] = fotaHandler.response(response:)
}
//routerWifi
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .routerWiFi)?.uuid {
responseHandlers[uuid] = routerWifiHandler.response(response:)
}
//fiveGCBandSignal
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .fiveGCBandSignal)?.uuid {
responseHandlers[uuid] = fiveGCBandSignalHandler.response(response:)
}
//fiveGSignal
if let uuid = getCharacteristic(peripheral: peripheral, fromType: .fiveGSignal)?.uuid {
func fiveGResponse(response: [String: Any]){
updateFiveGStatistics(cpeResponse: response)
handleFiveGSignal(response: response)
fiveGSignalHandler.response(response: response)
}
responseHandlers[uuid] = fiveGResponse(response:)
}
}
// MARK:- CBPeripheralDelegate
override public func centralManagerDidUpdateState(_ central: CBCentralManager) {
bluetoothDebugger?.bluetoothState = central.state
if central.state == .unauthorized {
delegate?.bluetoothPermissionsDenied() //User denied BLE
bluetoothDebugger?.isBluetoothPermissionDenied = true
} else if central.state == .poweredOff {
delegate?.bluetoothOff() //User turned off BLE
}
super.centralManagerDidUpdateState(central)
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
let cpeResponse = formatCharacteristicData(characteristic)
track("Message From CPE", additionalData: cpeResponse.merging(["CBUUID":characteristic.uuid.uuidString], uniquingKeysWith: { $1 }))
//make sure responseHandlers are registered
ensureResponseHandlers(peripheral: peripheral)
if let responseHandler = responseHandlers[characteristic.uuid] {
responseHandler(cpeResponse)
}
}
override public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? String, peripheralName.hasPrefix(GMFGConstant.BLE.advertisePrefix) {
track("Scanning found peripheral \(peripheralName) with RSSI \(RSSI).")
} else {
track("Scanning found peripheral, but not a VZ5G device")
}
super.centralManager(central, didDiscover: peripheral, advertisementData: advertisementData, rssi: RSSI)
}
override public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
track("Connected to \(String(describing: peripheral.name))")
super.centralManager(central, didConnect: peripheral)
}
override public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
track("Disconnected from \(String(describing: peripheral.name))")
fiveGSignalHandler.deviceNotReady()
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
}
override public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
track("Discover Service Error: \(error.localizedDescription)")
}
super.peripheral(peripheral, didDiscoverServices: error)
}
public func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
if let error = error {
track("Read error: \(error.localizedDescription) with RSSI: \(RSSI)")
}
}
public func peripheral(_ peripheral: CBPeripheral, didOpen channel: CBL2CAPChannel?, error: Error?) {
if let error = error {
track("Error opening channel: \(error.localizedDescription)")
}
}
public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
if let error = error {
track("Error writing to characteristic: \(String(describing: descriptor.characteristic?.uuid.uuidString)) holding value: \(String(describing: descriptor.value)) with error: \(error.localizedDescription)")
}
}
public func peripheral(_ peripheral: CBPeripheral, didDiscoverIncludedServicesFor service: CBService, error: Error?) {
if let error = error {
track("Error in discovered device characteristics: \(error.localizedDescription)")
}
}
override func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
track(error?.localizedDescription ?? "Unknown", function: "Central Manager Failed Connection")
}
override func scanForPeripherals(central: CBCentralManager) {
if !central.isScanning {
track("Starting scan for peripherals")
central.scanForPeripherals(withServices: nil, options: nil)
} else {
track("Already Scanning for peripherals")
}
}
//5GSignal Characteristic
private func updateFiveGStatistics(cpeResponse: [String: Any]) {
if let fivegSignal = cpeResponse["5GSignal"] as? [String: Any] {
if let rssiValue = parseRSRPFromJSON(fiveGData: fivegSignal) {
max5GSignalSeen = rssiValue
min5GSignalSeen = rssiValue
samples5GSignalSeen = samples5GSignalSeen + 1
}
}
}
// MARK:- Speed Test Functions
public func startSpeedTest(_ speedTestDelegate: GMFGSpeedTestDelegate, withNotifications: Bool) {
speedTestHandler.setDelegate(delegates: [speedTestDelegate, bluetoothDebugger])
if let _peripheral = peripheral, let _cTriggerSpeedTest = getCharacteristic(peripheral: _peripheral, fromType: .speedTest) {
if withNotifications {
updateAllNotifyValue(false) //Turn them all off to reduce traffic.
_ = sendNotifications(for: .speedTestResults, shouldNotify: true)
}
track("Starting Speed Test")
speedTestHandler.start(_peripheral, _cTriggerSpeedTest)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
speedTestHandler.deviceNotReady()
}
}
public func stopSpeedTest() {
speedTestHandler.reset()
if let _peripheral = peripheral, let _cTriggerSpeedTest = getCharacteristic(peripheral: _peripheral, fromType: .speedTest) {
_ = sendNotifications(for: .speedTestResults, shouldNotify: false)
track("Speed Test Stopping")
speedTestHandler.stop(_peripheral, _cTriggerSpeedTest)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
speedTestHandler.deviceNotReady()
}
}
//MARK:- Router WIFI Info
public func fetchRouterWifi(delegate: GMFGRouterWifiDelegate) {
routerWifiHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _cRouterWifi = getCharacteristic(peripheral: _peripheral, fromType: .routerWiFi) {
track("Started fetching Wifi info")
routerWifiHandler.fetchRouterWifiCredentials(_peripheral, _cRouterWifi)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
routerWifiHandler.deviceNotReady()
}
}
// MARK:- Public Internet Functions
public func checkInternetStatus(delegate: GMFGPublicInternetAccessDelegate) {
internetAccessHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _cPublicInternetAccess = getCharacteristic(peripheral: _peripheral, fromType: .internetAccess) {
track("Getting Internet Access")
internetAccessHandler.getPublicInternetAccess(_peripheral, _cPublicInternetAccess)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
internetAccessHandler.deviceNotReady()
}
}
// MARK:- Operational Mode Functions
@discardableResult
public func setOpMode(mode: GMFGOperationMode, disableBLE: Bool = false) -> Bool {
let additionalLogData: [String: Any] = ["Mode": mode.rawValue, "DisableBLE": disableBLE]
if let _peripheral = peripheral, let _cOperationMode = getCharacteristic(peripheral: _peripheral, fromType: .operationMode) {
track("Disabling BLE", additionalData: additionalLogData)
return operationModeHandler.setOpMode(_peripheral, _cOperationMode, mode: mode, disableBLE: disableBLE)
}
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage, additionalData: additionalLogData)
return false
}
// MARK:- FOTA Functions
public func startGetFirmwareVersion(delegate: GMFGFotaDelegate) {
bluetoothDebugger?.isCheckingFirmware = true
fotaHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _cFota = getCharacteristic(peripheral: _peripheral, fromType: .fotaStatus) {
track("Started getting firmware version from device")
fotaHandler.requestVersion(_peripheral, _cFota)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
fotaHandler.deviceNotReady()
}
}
public func stopGetFirmwareVersion() {
bluetoothDebugger?.isCheckingFirmware = false
fotaHandler.reset()
track("Stopped getting firmware version")
}
public func startFirmwareUpgrade(delegate: GMFGFotaDelegate, useNotifications: Bool) {
fotaHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _cFota = getCharacteristic(peripheral: _peripheral, fromType: .fotaCheck), getCharacteristic(peripheral: _peripheral,fromType: .fotaStatus) != nil {
track("Starting firmware update")
updateAllNotifyValue(false)
_ = self.sendNotifications(for: .fotaStatus, shouldNotify: useNotifications)
fotaHandler.startUpdate(_peripheral, _cFota)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
fotaHandler.deviceNotReady()
}
}
public func readFOTAStatus(delegate: GMFGFotaDelegate) {
fotaHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _cFota = getCharacteristic(peripheral: _peripheral, fromType: .fotaStatus) {
track("Checking FOTA status")
fotaHandler.requestVersion(_peripheral, _cFota)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
fotaHandler.deviceNotReady()
}
}
public func stopFirmwareUpgrade() {
fotaHandler.reset()
track("Stopped firmware update")
}
public func isFotaInProgress() -> Bool {
if let params = GMFGStorageManager.retrieve(key: GMFGConstant.fiveGParams), let inProgress = params[GMFGConstant.BLE.fotaInProgress] as? Bool {
return inProgress
}
return false
}
public func setFotaInProgress(_ inProgress: Bool) {
GMFGStorageManager.addEntries(dictionary: [GMFGConstant.BLE.fotaInProgress: inProgress])
}
public func getOldFirmwareVersion() -> String? {
if let params = GMFGStorageManager.retrieve(key: GMFGConstant.fiveGParams), let oldFirmware = params[GMFGConstant.BLE.firmwareVersion] as? String {
return oldFirmware
}
return nil
}
public func isFirmwareNewer(_ newFirmware: String) -> Bool {
if getOldFirmwareVersion() == newFirmware {
return false
}
return true
}
// MARK:- 5G Signal Handler
public func start5GSignalUpdates(_ delegate: GMFG5GSignalDelegate, useNotifications: Bool) {
fiveGSignalHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _c5GSignal = getCharacteristic(peripheral: _peripheral, fromType: .fiveGSignal) {
track("Getting 5G Signal")
sendNotifications(for: .fiveGSignal, shouldNotify: useNotifications)
fiveGSignalHandler.get5GSignal(_peripheral, _c5GSignal)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
fiveGSignalHandler.deviceNotReady()
}
}
public func stop5GSignalUpdates() {
fiveGSignalHandler.reset()
track("Stop getting 5G Signal")
updateAllNotifyValue(false)
}
// MARK:- 5G CBand Signal Handler
public func start5GCBandSignalUpdates(_ delegate: GMFG5GCBandSignalDelegate, useNotifications: Bool) {
fiveGCBandSignalHandler.setDelegate(delegates: [delegate, bluetoothDebugger])
if let _peripheral = peripheral, let _c5GSignal = getCharacteristic(peripheral: _peripheral, fromType: .fiveGCBandSignal) {
track("Getting 5G C-Band Signal")
sendNotifications(for: .fiveGCBandSignal, shouldNotify: useNotifications)
fiveGCBandSignalHandler.get5GSignal(_peripheral, _c5GSignal)
} else {
let errorMessage = peripheral == nil ? GMFGConstant.BLE.LogMsg.peripheralError : GMFGConstant.BLE.LogMsg.characteristicError
track(errorMessage)
fiveGCBandSignalHandler.deviceNotReady()
}
}
public func stop5GCBandSignalUpdates() {
fiveGCBandSignalHandler.reset()
track("Stop getting 5G C-Band Signal")
updateAllNotifyValue(false)
}
// MARK:- Utility Functions
override func parseRSRPFromJSON(fiveGData: [String: Any]) -> Double? {
return (fiveGData["RSRP"] as? NSString)?.doubleValue ?? nil
}
// MARK:- BluetoothConfigModel Functions
override func getBleAdvertiseName() -> String {
let remoteAdvData = bluetoothConfig?.advertisedData ?? ""
if GMFGBluetoothPair.isValidAdvertisedData(remoteAdvData) {
GMFGStorageManager.addEntries(dictionary: [GMFGConstant.BLE.advertisedData: remoteAdvData])
return remoteAdvData
} else if let localData = GMFGStorageManager.retrieve(key: GMFGConstant.fiveGParams), let localAdvData = localData[GMFGConstant.BLE.advertisedData] as? String {
track(GMFGConstant.BLE.LogMsg.cachedAdvertised)
return localAdvData
}
return remoteAdvData
}
func getCharacteristic(peripheral: CBPeripheral, fromType: CharacteristicType) -> CBCharacteristic? {
guard let service = bluetoothConfig?.services.first else {
track("SERVICE was empty in the BLE Module JSON")
return nil
}
guard let expectedCharacteristicUUID = service.characteristics.first(where: {$0.name == fromType})?.uuid else {
track("No characteristic found for key \(fromType.rawValue) in the BLE Module JSON")
return nil
}
guard let expectedServiceUUID = getSeviceUUIDs().first else {
track("No services found in the BLE Module JSON")
return nil
}
guard peripheral.state == .connected else {
track("Tried to get a characteristic from the peripheral, but it is still in state: \(peripheral.state.rawValue)")
return nil
}
guard let services = peripheral.services else {
return nil
}
if services.count != 1 {
track("Found \(services.count) services!")
}
guard let service = services.first(where: {$0.uuid == expectedServiceUUID}) else {
track("Could not find service: \(expectedServiceUUID) on device.")
return nil
}
guard let characteristic = service.characteristics?.first(where: {$0.uuid == expectedCharacteristicUUID}) else {
track("Could not find characteristic: \(expectedCharacteristicUUID) on device.")
return nil
}
return characteristic
}
}

View File

@ -0,0 +1,87 @@
//
// GMFGConstant.swift
// MVM5G
//
// Created by Shohrab Chowdhury on 6/23/20.
// Copyright © 2020 Kyle. All rights reserved.
//
struct GMFGConstant {
struct BLE {
static let pin = "pin"
static let advertisedData = "advertisedData"
static let fiveGCurrentSignal = "currentSignal"
static let fiveGHighSignal = "highSignal"
static let fiveGLowSignal = "lowSignal"
static let firmwareVersion = "firmwareVersion"
static let fotaInProgress = "fotaInProgress"
static let fotaStatus = "FOTAStatus"
static let cpeBLEOperation = "CPEBLEOperation"
static let advertisePrefix = "VZ5G_RECEIVER_"
static let routerWifiSSID = "routerWifiSSID"
static let routerWifiPwd = "routerWifiPwd"
struct LogMsg {
static let startingBLE = "Starting BLE Connection"
static let leavingPage = "Disconnecting BT because user is leaving page"
static let noAdvertisedName = "No Advertised Name"
static let attemptInstallationMode = "Attempting to switch to Installation mode"
static let attemptOperationalMode = "Attempting to switch to Operational mode"
static let internetNotEnabled = "CPE Internet Not Enabled. Starting speed test anyway..."
static let attemptDisableBleOpMode = "Attempting to disable BLE and set Operational mode"
static let fotaGotVersion = "Got version from CPE"
static let fotaUnexpectedCPEStatus = "Unexpected FOTA status returned from CPE"
static let cachedAdvertised = "Using local cached advertising name"
static let peripheralError = "Peripheral not found"
static let characteristicError = "Characteristic not found"
static let unknownCPEResponse = "Unknown response from CPE"
static let bleModuleMissing = "Ble Module missing"
static let bleDecodeError = "Ble Module decocde error"
}
}
struct AR {
static let capable = "arCapable"
static let capableStatusReq = "arCapableStatusRequired"
static let deviceLocation = "deviceLocation"
static let overlayShown = "AROverlayShown"
static let infoAccessibilityLabel = "Information icon button"
}
struct Map {
static let fivegSignalExposures = "fivegSignalExposures"
static let antennaList = "antennasList"
static let antennaLocation = "antennaLocation"
static let selectedAntennaIndex = "selectedAntennaIndex"
static let maxZoomLevel: Float = 18.0
}
struct Test {
static let hardcodeToggle = "isHardcode"
static let CPEToggle = "isCPESupported"
static let fiveGSignalToggle = "is5GSignalEnabled"
static let forceBCS = "isBCSForce"
static let visualDebugger = "isVisualDebugger"
}
struct LogMsg {
static let invalidTimer = "Timer is invalid"
}
struct TimeTracker {
static let details = "GMFGTimeTrackingDetails"
}
struct Glassbox {
static let fivegSetup = "5GSetup"
}
static let empty = ""
static let index = "index"
static let imei = "imei"
static let extenderMacId = "extenderMacId"
static let overlayShown = "OverlayShown"
static let fiveGParams = "fivegParams"
static let orderNumber = "orderNumber"
static let functionName = "functionName"
static let birthCertificate = "BirthCertificate"
static let feedbackShown = "isFeedbackShown"
static let feedback = "feedback"
static let clearCache = "clearCache"
static let blinkingColor = "blinkingColor"
static let blinkSec = "blinkSec"
}

View File

@ -0,0 +1,99 @@
//
// GMFGLocationManager.swift
// MVM5G
//
// Created by Muthulingam, Muthuraj on 03/06/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import Foundation
import CoreLocation
protocol GMFGLocationManagerDelegate: AnyObject {
func locationManager(_ manager: GMFGLocationManager, didUpdateLocations locations: [CLLocation])
func locationManager(_ manager: GMFGLocationManager, didHeadUpdate newHeading: CLHeading)
func locationManager(_ manager: GMFGLocationManager, didUpdateLocationPermissions isAuthorized: Bool)
}
final class GMFGLocationManager: NSObject {
// MARK: - Public Properties
weak var delegate: GMFGLocationManagerDelegate?
static let shared = GMFGLocationManager()
var locationServicesEnabled: Bool {
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
case .notDetermined, .restricted, .denied:
return false
case .authorizedAlways, .authorizedWhenInUse:
return true
@unknown default:
return false
}
} else {
return false
}
}
/// Fetches Current Location if available
private(set) var currentLocation: CLLocation?
// MARK: - Private Properties
private lazy var locationManager = CLLocationManager()
/// to avoid called to create instance
private override init() {
super.init()
}
// MARK: - Public Helpers
func prepareLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.headingFilter = kCLHeadingFilterNone
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
}
func startLocationMonitoring() {
locationManager.startUpdatingHeading()
locationManager.startUpdatingLocation()
}
func stopLocationMonitoring() {
locationManager.stopUpdatingHeading()
locationManager.stopUpdatingLocation()
}
}
extension GMFGLocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways, .authorizedWhenInUse:
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
case .denied, .notDetermined, .restricted:
delegate?.locationManager(self, didUpdateLocationPermissions: false)
/// Resets the location
currentLocation = nil
@unknown default: currentLocation = nil
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let currentLocation = locations.last {
self.currentLocation = currentLocation
}
delegate?.locationManager(self, didUpdateLocations: locations)
}
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
delegate?.locationManager(self, didHeadUpdate: newHeading)
}
}
extension CLLocation {
var array: [Double] { return [coordinate.latitude, coordinate.longitude] }
}

View File

@ -0,0 +1,50 @@
//
// GMFGRequestHandler.swift
// MVM5G
//
// Created by Gujuluva Santharam, Ajai Prabhu on 07/07/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import UIKit
class GMFGStorageManager {
//MARK - user default base methods
class func store(dictionary: [AnyHashable : Any],for key:String) {
// MFUtility.save(dictionary, toUserDefaultsForKey: key)
}
class func retrieve(key: String) -> [String: Any]? {
return UserDefaults.standard.dictionary(forKey: key)
}
//Use this to append entries from dictionary to existing one
class func addEntries(dictionary: [String : Any], key: String = GMFGConstant.fiveGParams) {
let storedDict = GMFGStorageManager.retrieve(key: key) ?? [:]
let appendedDict = storedDict.merging(dictionary) { $1 }
GMFGStorageManager.store(dictionary: appendedDict, for: key)
}
class func extraRequestParams() -> [String: Any] {
var storedDict = GMFGStorageManager.retrieve(key: GMFGConstant.fiveGParams) ?? [:]
if let currentLocation = GMFGLocationManager.shared.currentLocation {
storedDict[GMFGConstant.AR.deviceLocation] = currentLocation.array
}
return GMFGTestScreenData.shared.isHardcodedValues ? GMFGTestScreenData.shared.hardcodeDict : storedDict
}
//MARK: - methods to remove from user defaults
class func remove(key: String) {
if var storedDict = GMFGStorageManager.retrieve(key: GMFGConstant.fiveGParams) {
storedDict.removeValue(forKey: key)
GMFGStorageManager.store(dictionary: storedDict, for: GMFGConstant.fiveGParams)
}
}
class func removeAll() {
UserDefaults.standard.removeObject(forKey: GMFGConstant.fiveGParams)
UserDefaults.standard.removeObject(forKey: "selfInstallNextStep")
}
}

View File

@ -0,0 +1,30 @@
//
// GMFGTestScreenData.swift
// JSONCreator
//
// Created by Matt Bruce on 5/11/22.
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import Foundation
import UIKit
class GMFGTestScreenData: NSObject {
var geminiHardCode = false
var isCPESimulated = true
var isHardcodedValues = false
var isARCapable = true
var cpeVersionNumber = GMFGConstant.empty
var isEnable5GSignal = true
var forceBCS = false
var visualDebugger = false
var deviceLocation: [String] = []
var hardcodeDict: [String: Any] = [:]
var toggleDict: [String : Bool] = [:]
static let shared = GMFGTestScreenData()
/// to avoid called to create instance
private override init() {
super.init()
}
}

View File

@ -0,0 +1,21 @@
//
// GMFGBLEHandlerProtocol.swift
// MVM5G
//
// Created by Jason Beck on 7/10/20.
// Copyright © 2020 Kyle. All rights reserved.
//
import Foundation
protocol GMFGBLEHandlerProtocol {
func convertToData(_ dictionary: [String: Any]) -> Data?
func response(response: [String : Any])
func deviceNotReady()
}
extension GMFGBLEHandlerProtocol {
func convertToData(_ dictionary: [String: Any]) -> Data? {
do { return try JSONSerialization.data(withJSONObject: dictionary, options: []) }
catch { return nil }
}
}

View File

@ -14,7 +14,6 @@ import VDS
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
var window: UIWindow? var window: UIWindow?
var splitViewController: UISplitViewController?
var mvcNav: UINavigationController? var mvcNav: UINavigationController?
var dvcNav: UINavigationController? var dvcNav: UINavigationController?
var mvc: UIViewController? var mvc: UIViewController?
@ -23,26 +22,34 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Setup our core object with the default implementation // Setup our core object with the default implementation
CoreUIObject.sharedInstance()?.defaultInitialSetup() CoreUIObject.sharedInstance()?.defaultInitialSetup()
CoreUIObject.sharedInstance()?.globalTopAlertDelegate = self
// MVMCoreCache.shared()?.addPage(toCache: [KeyPageType:"videotest","template":"stack","header":[KeyMoleculeName:"header","molecule":["moleculeName":"twoButtonView","primaryButton":["moleculeName":"button","title":"back","action":[KeyActionType:KeyActionTypeBack]],"secondaryButton":["moleculeName":"button","title":"open","action":[KeyActionType:KeyActionTypeOpen,KeyPageType:"planSelectionPageType"]]]],"stack":[KeyMoleculeName:"stack","molecules":[]]], pageType: "videotest")
//
// let path = Bundle.main.path(forResource: "Testing3", ofType: "json")!
// let string = try! String(contentsOfFile: path, encoding: .utf8)
// let dict: [AnyHashable: Any] = try! JSONSerialization.jsonObject(with: string.data(using: .utf8)!, options: .fragmentsAllowed) as! [AnyHashable: Any]
// let page: [AnyHashable: Any] = dict[KeyPage] as! [AnyHashable: Any]
// MVMCoreCache.shared()?.addPage(toCache: page, pageType: page[KeyPageType]! as! String)
return true return true
} }
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch. // Override point for customization after application launch.
splitViewController = window!.rootViewController as? UISplitViewController let splitViewController = window!.rootViewController as! UISplitViewController
NavigationHandler.shared().viewControllerToPresentOn = splitViewController mvcNav = splitViewController.viewControllers[0] as? UINavigationController
mvcNav = splitViewController?.viewControllers[0] as? UINavigationController
mvcNav?.delegate = self mvcNav?.delegate = self
mvc = mvcNav?.topViewController mvc = mvcNav?.topViewController
dvcNav = splitViewController?.viewControllers[splitViewController!.viewControllers.count-1] as? UINavigationController dvcNav = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as? UINavigationController
dvc = dvcNav?.topViewController dvc = dvcNav?.topViewController
dvc?.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem dvc?.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
dvc?.navigationItem.leftItemsSupplementBackButton = true dvc?.navigationItem.leftItemsSupplementBackButton = true
splitViewController?.delegate = self splitViewController.delegate = self
splitViewController?.preferredDisplayMode = .allVisible splitViewController.preferredDisplayMode = .allVisible
let gr = UILongPressGestureRecognizer(target: self, action: #selector(jsonPasteAndGo)) let gr = UILongPressGestureRecognizer(target: self, action: #selector(jsonPasteAndGo))
splitViewController?.view.addGestureRecognizer(gr) splitViewController.view.addGestureRecognizer(gr)
NotificationCenter.default.addObserver(forName: UIViewController.showDetailTargetDidChangeNotification, object: splitViewController, queue: nil) { [weak self] (notification) in NotificationCenter.default.addObserver(forName: UIViewController.showDetailTargetDidChangeNotification, object: splitViewController, queue: nil) { [weak self] (notification) in
if let strongSelf = self, let svc = notification.object as? UISplitViewController { if let strongSelf = self, let svc = notification.object as? UISplitViewController {
@ -54,6 +61,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
} }
} }
} }
self.register()
return true return true
} }
@ -88,7 +96,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
// MARK: - Split view // MARK: - Split view
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewControlller:UIViewController, onto primaryViewController:UIViewController) -> Bool { func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
//guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } //guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
//guard let _ = secondaryAsNavController.topViewController as? DetailViewController else { return false } //guard let _ = secondaryAsNavController.topViewController as? DetailViewController else { return false }
return true return true
@ -106,3 +114,179 @@ extension AppDelegate: UINavigationControllerDelegate {
} }
} }
} }
extension AppDelegate: MVMCoreGlobalTopAlertDelegateProtocol {
func getTopAlertView() -> UIView & MVMCoreTopAlertViewProtocol {
guard let topAlertView = MVMCoreUISplitViewController.main()?.topAlertView else {
return MVMCoreUITopAlertView()
}
return topAlertView;
}
func priorityForTopAlert(by object: MVMCoreTopAlertObject) -> Operation.QueuePriority {
return object.queuePriority
}
}
extension AppDelegate {
func register(){
ModelRegistry.register(handler: TestLabelToggle.self, for: TestLabelToggleModel.self)
ModelRegistry.register(handler: TestToggle.self, for: TestToggleModel.self)
ModelRegistry.register(handler: TextEntryField.self, for: TextEntryField64Model.self)
ModelRegistry.register(handler: EmailVerifyField.self, for: EmailVerifyModel.self)
ModelRegistry.register(handler: WifiWidget.self, for: WifiWidgetModel.self)
ModelRegistry.register(handler: ToggleWifiActionHandler.self, for: ToggleWifiActionModel.self)
}
}
@objcMembers open class EmailVerifyModel: MoleculeModelProtocol {
public static var identifier: String = "emailVerifyField"
public var moleculeName: String = EmailVerifyModel.identifier
public var emailField: TextEntryFieldModel
public var bottomMolecule: MoleculeModelProtocol
public var email: String
public var backgroundColor: MVMCoreUI.Color?
public init(emailField: TextEntryFieldModel, email: String, bottomMolecule: MoleculeModelProtocol) {
self.emailField = emailField
self.email = email
self.bottomMolecule = bottomMolecule
}
public required init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
emailField = try typeContainer.decode(TextEntryFieldModel.self, forKey: .emailField)
email = try typeContainer.decode(String.self, forKey: .email)
bottomMolecule = try typeContainer.decodeModel(codingKey: .bottomMolecule)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(emailField, forKey: .emailField)
try container.encode(email, forKey: .email)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeModel(bottomMolecule, forKey: .bottomMolecule)
}
private enum CodingKeys: String, CodingKey {
case moleculeName
case emailField
case bottomMolecule
case backgroundColor
case email
}
}
@objcMembers open class EmailVerifyField: View {
private let emailField = TextEntryField()
private var bottomView: MoleculeViewProtocol?
private var emailVerifyFieldModel: EmailVerifyModel? {
return model as? EmailVerifyModel
}
private var isBottomViewHidden: Bool {
guard let emailVerifyFieldModel = emailVerifyFieldModel, let text = emailField.text else { return true }
return !(emailVerifyFieldModel.email.caseInsensitiveCompare(text) == .orderedSame)
}
private let containerView = MVMCoreUICommonViewsUtility.commonView()
open override func setupView() {
super.setupView()
backgroundColor = .clear
clipsToBounds = true
addSubview(containerView)
NSLayoutConstraint.constraintPinSubview(toSuperview: containerView)
containerView.addSubview(emailField)
NSLayoutConstraint.constraintPinSubview(emailField, pinTop: true, pinBottom: false, pinLeft: true, pinRight: true)
addEmailFieldObserver()
}
private func addEmailFieldObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(onEmailValueChange), name: UITextField.textDidChangeNotification, object: emailField.textField)
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? EmailVerifyModel else { return }
emailField.set(with: model.emailField, delegateObject, additionalData)
if let bottomView = self.bottomView ?? ModelRegistry.createMolecule(model.bottomMolecule, delegateObject: delegateObject, additionalData: additionalData) {
bottomView.set(with: model.bottomMolecule, delegateObject, additionalData)
self.bottomView = bottomView
addBottomView(bottomView: bottomView)
}
}
public func onEmailValueChange() {
bottomView?.isHidden = isBottomViewHidden
}
private func addBottomView(bottomView: MoleculeViewProtocol) {
containerView.addSubview(bottomView)
bottomView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: bottomView.trailingAnchor).isActive = true
bottomView.topAnchor.constraint(equalTo: emailField.bottomAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true
bottomView.isHidden = isBottomViewHidden
}
}
class ToggleWifiActionModel: ActionModelProtocol {
static var identifier: String = "toggleWifi"
var extraParameters: JSONValueDictionary?
var analyticsData: JSONValueDictionary?
var wifiId: String
var actionType: String = ToggleWifiActionModel.identifier
init(wifiId: String) {
self.wifiId = wifiId
}
}
class ToggleWifiActionHandler: MVMCoreActionHandlerProtocol {
required public init() {}
func handleAction(_ model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) {
guard let action = model as? ToggleWifiActionModel else { return }
print("Wi-Fi Id: \(action.wifiId)")
}
}
class TextEntryField64Model: TextEntryFieldModel {
open override class var identifier: String { "textFieldBase64" }
open override func formFieldServerValue() -> AnyHashable? {
guard let value = super.formFieldServerValue() as? String else { return nil }
return value.base64Encoded()
}
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
text = text?.base64Decoded()
}
}
extension String {
func base64Encoded() -> String? {
data(using: .utf8)?.base64EncodedString()
}
func base64Decoded() -> String? {
guard let data = Data(base64Encoded: self) else { return nil }
return String(data: data, encoding: .utf8)
}
}

View File

@ -0,0 +1,117 @@
//
// DecodableDefaults+VDS.swift
// JSONCreator
//
// Created by Matt Bruce on 7/28/22.
// Copyright © 2022 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
import MVMCore
//MARK: - Decodable Defaults
extension VDSFontCategory {
public enum DefaultFeature: DecodableDefault.Source {
public static var defaultValue: VDSFontCategory { .feature }
}
public enum DefaultTitle: DecodableDefault.Source {
public static var defaultValue: VDSFontCategory { .title }
}
public enum DefaultBody: DecodableDefault.Source {
public static var defaultValue: VDSFontCategory { .body }
}
public enum DefaultMicro: DecodableDefault.Source {
public static var defaultValue: VDSFontCategory { .micro }
}
}
extension VDSFontSize {
public enum Default2XLarge: DecodableDefault.Source {
public static var defaultValue: VDSFontSize { .xxlarge }
}
public enum DefaultXLarge: DecodableDefault.Source {
public static var defaultValue: VDSFontSize { .xlarge }
}
public enum DefaultLarge: DecodableDefault.Source {
public static var defaultValue: VDSFontSize { .large }
}
public enum DefaultMedium: DecodableDefault.Source {
public static var defaultValue: VDSFontSize { .medium }
}
public enum DefaultSmall: DecodableDefault.Source {
public static var defaultValue: VDSFontSize { .small }
}
public enum DefaultXSmall: DecodableDefault.Source {
public static var defaultValue: VDSFontSize { .xsmall }
}
}
extension VDSTextPosition {
public enum DefaultLeft: DecodableDefault.Source {
public static var defaultValue: VDSTextPosition { .left }
}
public enum DefaultRight: DecodableDefault.Source {
public static var defaultValue: VDSTextPosition { .right }
}
public enum DefaultCenter: DecodableDefault.Source {
public static var defaultValue: VDSTextPosition { .center }
}
}
extension VDSFontWeight {
public enum DefaultBold: DecodableDefault.Source {
public static var defaultValue: VDSFontWeight { .bold }
}
public enum DefaultRegular: DecodableDefault.Source {
public static var defaultValue: VDSFontWeight { .regular }
}
}
extension VDSToggle {
public enum DefaultOffText: DecodableDefault.Source {
public static var defaultValue: String { "Off" }
}
public enum DefaultOnText: DecodableDefault.Source {
public static var defaultValue: String { "On" }
}
}
extension Surface {
public enum DefaultLight: DecodableDefault.Source {
public static var defaultValue: Surface { .light }
}
public enum DefaultDark: DecodableDefault.Source {
public static var defaultValue: Surface { .dark }
}
}
extension DecodableDefault {
public struct Surface {
public typealias Light = DecodableDefault.Wrapper<VDS.Surface.DefaultLight>
public typealias Dark = DecodableDefault.Wrapper<VDS.Surface.DefaultDark>
}
public struct VDSTypography {
public typealias FontCategoryFeature = DecodableDefault.Wrapper<VDSFontCategory.DefaultFeature>
public typealias FontCategoryTitle = DecodableDefault.Wrapper<VDSFontCategory.DefaultTitle>
public typealias FontCategoryBody = DecodableDefault.Wrapper<VDSFontCategory.DefaultBody>
public typealias FontCategoryMicro = DecodableDefault.Wrapper<VDSFontCategory.DefaultMicro>
public typealias FontWeightBold = DecodableDefault.Wrapper<VDSFontWeight.DefaultBold>
public typealias FontWeightRegular = DecodableDefault.Wrapper<VDSFontWeight.DefaultRegular>
public typealias FontSize2XLarge = DecodableDefault.Wrapper<VDSFontSize.Default2XLarge>
public typealias FontSizeXLarge = DecodableDefault.Wrapper<VDSFontSize.DefaultXLarge>
public typealias FontSizeLarge = DecodableDefault.Wrapper<VDSFontSize.DefaultLarge>
public typealias FontSizeMedium = DecodableDefault.Wrapper<VDSFontSize.DefaultMedium>
public typealias FontSizeSmall = DecodableDefault.Wrapper<VDSFontSize.DefaultSmall>
public typealias FontSizeXSmall = DecodableDefault.Wrapper<VDSFontSize.DefaultXSmall>
public typealias TextPositionLeft = DecodableDefault.Wrapper<VDSTextPosition.DefaultLeft>
public typealias TextPositionRight = DecodableDefault.Wrapper<VDSTextPosition.DefaultRight>
public typealias TextPositionCenter = DecodableDefault.Wrapper<VDSTextPosition.DefaultCenter>
}
// public struct VDSToggle {
// public typealias OffText = DecodableDefault.Wrapper<VDS.VDSToggle.DefaultOffText>
// public typealias OnText = DecodableDefault.Wrapper<VDS.VDSToggle.DefaultOnText>
// }
}

View File

@ -19,8 +19,6 @@ class DetailViewController: UIViewController {
guard textView.superview == nil else { guard textView.superview == nil else {
return return
} }
modalPresentationStyle = .fullScreen
view.addSubview(textView) view.addSubview(textView)
if UIDevice.current.userInterfaceIdiom == .pad { if UIDevice.current.userInterfaceIdiom == .pad {
textView.font = UIFont.systemFont(ofSize: 40) textView.font = UIFont.systemFont(ofSize: 40)
@ -68,45 +66,40 @@ class DetailViewController: UIViewController {
@objc func play() { @objc func play() {
do { do {
if let data = textView.text.data(using: .utf8), let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable: Any] { if let data = textView.text.data(using: .utf8), let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable: Any] {
guard let page = jsonObject.optionalDictionaryForKey(KeyPage) else { let page = jsonObject.optionalDictionaryForKey(KeyPage)
let error = NSError(domain: ErrorDomainNative, code: ErrorCode.parsingJSON.rawValue, userInfo: [NSLocalizedDescriptionKey: "Needs a Page to show."]) let pageType = page?.optionalStringForKey(KeyPageType)
showError(error) let template = page?.optionalStringForKey("template")
return
}
guard let pageType = page.optionalStringForKey(KeyPageType) else {
let error = NSError(domain: ErrorDomainNative, code: ErrorCode.parsingJSON.rawValue, userInfo: [NSLocalizedDescriptionKey: "Needs a pageType."])
showError(error)
return
}
let template = page.optionalStringForKey("template")
let moduleMap = jsonObject.optionalDictionaryForKey(KeyModuleMap)
var errorObject: MVMCoreErrorObject? = MVMCoreErrorObject(title: nil, message: "No Template Found", code: ErrorCode.initViewController.rawValue, domain: ErrorDomainNative, location: nil) var errorObject: MVMCoreErrorObject? = MVMCoreErrorObject(title: nil, message: "No Template Found", code: ErrorCode.initViewController.rawValue, domain: ErrorDomainNative, location: nil)
if let viewController = MVMCoreUIViewControllerMappingObject.shared()?.createMFViewController(ofTemplate: template, pageType: pageType), if let viewController = MVMCoreUIViewControllerMappingObject.shared()?.createMFViewController(ofTemplate: template, pageType: pageType),
let loadObject = MVMCoreLoadObject(pageJSON: page, modulesJSON: moduleMap, requestParameters: nil, dataForPage: nil, delegateObject: nil), let loadObject = MVMCoreLoadObject(pageJSON: page, modulesJSON: jsonObject.optionalDictionaryForKey(KeyModuleMap), requestParameters: nil, dataForPage: nil, delegateObject: nil),
viewController.shouldFinishProcessingLoad(loadObject, error: &errorObject) { viewController.shouldFinishProcessingLoad(loadObject, error: &errorObject) {
Task(priority: .userInitiated) { @MainActor in //let split = MVMCoreUISplitViewController.setup(asMainController: nil, rightPanel: nil)!
let gr = UILongPressGestureRecognizer(target: self, action: #selector(DetailViewController.close)) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
viewController.view.addGestureRecognizer(gr) viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.close))
let topAlert = NotificationContainerView()
CoreUIObject.sharedInstance()?.topNotificationHandler = NotificationHandler(with: topAlert)
let split = MVMCoreUISplitViewController.setup(asMainController: nil, rightPanel: nil, topAlert: topAlert)!
_ = split.view // Force loadView
let done = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.close))
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
split.navigationController?.isToolbarHidden = false
viewController.setToolbarItems([spacer, done], animated: false)
split.navigationController?.setToolbarItems([spacer, done], animated: false)
NavigationHandler.shared().viewControllerToPresentOn = split
UIApplication.shared.delegate?.window??.rootViewController = split
await MVMCoreLoadRequestOperation.processJSON(fromServer: jsonObject, loadObject: loadObject)
await NavigationHandler.shared().push(viewController: viewController, animated: false)
} }
let gr = UILongPressGestureRecognizer(target: self, action: #selector(DetailViewController.close))
viewController.view.addGestureRecognizer(gr)
/*split.modalPresentationStyle = .fullScreen
present(split, animated: true) {
split.navigationController?.setViewControllers([viewController], animated: false)
// Notify of json change
let systemParameters = jsonObject.optionalDictionaryForKey(KeySystemParameters)
loadObject.responseJSON = jsonObject
loadObject.systemParametersJSON = systemParameters
loadObject.responseInfoMap = jsonObject.optionalDictionaryForKey(KeyResponseInfo)
var pages = jsonObject.dictionaryForKey(KeyPageMap)
pages.updateValue(page, forKey: pageType!)
MVMCoreLoadRequestOperation.notifyListeners(ofNewResponse: pages, modules: jsonObject.optionalDictionaryForKey(KeyModuleMap), systemParameters: systemParameters, loadObject: loadObject)
}*/
//let navigation = UINavigationController(rootViewController: viewController)
let navigation = NavigationController.setupNavigationControllerAsMainController()!
navigation.pushViewController(viewController, animated: false)
MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = splitViewController
MVMCoreNavigationHandler.shared()?.present(navigation, animated: true)
} else if let errorObject = errorObject { } else if let errorObject = errorObject {
let error = NSError(domain: ErrorDomainNative, code: ErrorCode.initViewController.rawValue, userInfo: [NSLocalizedDescriptionKey: errorObject.messageToLog ?? errorObject.messageToDisplay!]) let error = NSError(domain: ErrorDomainNative, code: ErrorCode.initViewController.rawValue, userInfo: [NSLocalizedDescriptionKey: errorObject.messageToLog ?? errorObject.messageToDisplay!])
showError(error) showError(error)
@ -118,9 +111,7 @@ class DetailViewController: UIViewController {
} }
@objc func close() { @objc func close() {
guard let splitViewController = (UIApplication.shared.delegate as? AppDelegate)?.splitViewController else { return } MVMCoreNavigationHandler.shared()?.dismissTopViewController(animated: true)
NavigationHandler.shared().viewControllerToPresentOn = splitViewController
UIApplication.shared.delegate?.window??.rootViewController = splitViewController
} }
} }

View File

@ -1,11 +0,0 @@
"moleculeName":"headerH1",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "headline"
},
"body":{
"moleculeName": "label",
"text": "body"
}
}

View File

@ -1,28 +0,0 @@
"moleculeName":"headerH1Btn",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "headline"
},
"body":{
"moleculeName": "label",
"text": "body"
}
},
"buttons": {
"moleculeName": "twoButtonView",
"primaryButton": {
"moleculeName": "button",
"title": "primary",
"action": {
"actionType": "noop"
}
},
"secondaryButton": {
"moleculeName": "button",
"title": "secondary",
"action": {
"actionType": "noop"
}
}
}

View File

@ -1,23 +1,23 @@
"moleculeName":"headerH1Landing", "moleculeName":"headerH1Landing",
"headline":{ "headline":{
"moleculeName": "label", "moleculeName": "label",
"text":"headline" "text":"x"
}, },
"headline2":{ "headline2":{
"moleculeName": "label", "moleculeName": "label",
"text":"headline2" "text":"x"
}, },
"subHeadline":{ "subHeadline":{
"moleculeName": "label", "moleculeName": "label",
"text":"subHeadline" "text":"y"
}, },
"body":{ "body":{
"moleculeName": "label", "moleculeName": "label",
"text":"body" "text":"y"
}, },
"link":{ "link":{
"moleculeName": "link", "moleculeName": "link",
"title":"link", "title":"y",
"action": { "action": {
"actionType": "back" "actionType": "back"
} }
@ -26,16 +26,17 @@
"moleculeName":"twoButtonView", "moleculeName":"twoButtonView",
"primaryButton":{ "primaryButton":{
"moleculeName": "button", "moleculeName": "button",
"title":"primary", "title":"x",
"action": { "action": {
"actionType": "noop" "actionType": "openPage",
"pageType": "verifyZip"
} }
}, },
"secondaryButton":{ "secondaryButton":{
"moleculeName": "button", "moleculeName": "button",
"title":"secondary", "title":"x",
"action": { "action": {
"actionType": "noop" "actionType": "back"
} }
} }
} }

View File

@ -3,10 +3,10 @@
"moleculeName": "headlineBody", "moleculeName": "headlineBody",
"headline":{ "headline":{
"moleculeName": "label", "moleculeName": "label",
"text":"headline" "text":"x"
}, },
"body":{ "body":{
"moleculeName": "label", "moleculeName": "label",
"text":"body" "text":"y"
} }
} }

View File

@ -1,29 +0,0 @@
"moleculeName":"headerH2Btns",
"headlineBody": {
"moleculeName": "headlineBody",
"headline":{
"moleculeName": "label",
"text":"headline"
},
"body":{
"moleculeName": "label",
"text":"body"
}
},
"buttons": {
"moleculeName": "twoButtonView",
"primaryButton": {
"moleculeName": "button",
"title": "primary",
"action": {
"actionType": "noop"
}
},
"secondaryButton": {
"moleculeName": "button",
"title": "secondary",
"action": {
"actionType": "noop"
}
}
}

View File

@ -1,19 +0,0 @@
"moleculeName":"headerH2CrtBtn",
"headlineBody": {
"moleculeName": "headlineBody",
"headline":{
"moleculeName": "label",
"text":"headline"
},
"body":{
"moleculeName": "label",
"text":"body"
}
},
"caretLink": {
"moleculeName": "caretLink",
"title": "link",
"action": {
"actionType": "noop"
}
}

View File

@ -1,19 +0,0 @@
"moleculeName":"headerH2Link",
"headlineBody": {
"moleculeName": "headlineBody",
"headline":{
"moleculeName": "label",
"text":"headline"
},
"body":{
"moleculeName": "label",
"text":"body"
}
},
"link": {
"moleculeName": "link",
"title": "link",
"action": {
"actionType": "noop"
}
}

View File

@ -1,29 +1,29 @@
"moleculeName":"headerH2TwoRows", "moleculeName":"headerH2TwoRows",
"headline":{ "headline":{
"moleculeName": "label", "moleculeName": "label",
"text":"headline" "text":"x"
}, },
"body":{ "body":{
"moleculeName": "label", "moleculeName": "label",
"text":"body" "text":"y"
}, },
"subBody":{ "subBody":{
"moleculeName": "label", "moleculeName": "label",
"text":"subBody" "text":"y"
}, },
"body2":{ "body2":{
"moleculeName": "label", "moleculeName": "label",
"text":"body2" "text":"y"
}, },
"subBody2":{ "subBody2":{
"moleculeName": "label", "moleculeName": "label",
"text":"subBody2" "text":"y"
}, },
"body3":{ "body3":{
"moleculeName": "label", "moleculeName": "label",
"text":"body3" "text":"y"
}, },
"subBody3":{ "subBody3":{
"moleculeName": "label", "moleculeName": "label",
"text":"subBody3" "text":"y"
} }

View File

@ -1,19 +0,0 @@
"moleculeName":"headerH2BtnTny",
"headlineBody": {
"moleculeName": "headlineBody",
"headline":{
"moleculeName": "label",
"text":"headline"
},
"body":{
"moleculeName": "label",
"text":"body"
}
},
"button": {
"moleculeName": "button",
"title": "button",
"action": {
"actionType": "noop"
}
}

View File

@ -1,29 +0,0 @@
"moleculeName" : "listDvcBtnS",
"eyebrow" : {
"moleculeName" : "label",
"text" : "8.0 GB"
},
"headline" : {
"moleculeName" : "label",
"text" : "Verizon L data"
},
"body" : {
"moleculeName" : "label",
"text" : "2.0 GB"
},
"body2" : {
"moleculeName" : "label",
"text" : "Additional data"
},
"button": {
"moleculeName": "button",
"title":"hello",
"action": {
"actionType":"openPage",
"pageType":"hello"
}
},
"image":{
"moleculeName":"image",
"image": "https://mobile.vzw.com/hybridClient/is/image/VerizonWireless/iPhoneXr_Black_PureAngles"
}

View File

@ -1,31 +0,0 @@
"moleculeName" : "listDvcLnkS",
"eyebrow" : {
"moleculeName" : "label",
"text" : "8.0 GB"
},
"headline" : {
"moleculeName" : "label",
"text" : "Verizon L data"
},
"body" : {
"moleculeName" : "label",
"text" : "2.0 GB"
},
"body2" : {
"moleculeName" : "label",
"text" : "Additional data"
},
"twoLinkView": {
"leftLink": {
"moleculeName": "link",
"title":"hello",
"action": {
"actionType":"openPage",
"pageType":"hello"
}
}
},
"image":{
"moleculeName":"image",
"image": "https://mobile.vzw.com/hybridClient/is/image/VerizonWireless/iPhoneXr_Black_PureAngles"
}

View File

@ -6,19 +6,19 @@
"moleculeName" : "eyebrowHeadlineBodyLink", "moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : { "eyebrow" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "eyebrow" "text" : "Hello"
}, },
"headline" : { "headline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "Hello"
}, },
"body" : { "body" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello"
}, },
"link" : { "link" : {
"moleculeName" : "link", "moleculeName" : "link",
"title" : "link", "title" : "Hello",
"action": { "action": {
"actionType":"back" "actionType":"back"
} }

View File

@ -6,10 +6,10 @@
"moleculeName" : "headlineBody", "moleculeName" : "headlineBody",
"headline" : { "headline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "Hello"
}, },
"body" : { "body" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello"
} }
} }

View File

@ -2,15 +2,15 @@
"moleculeName": "listLVImg", "moleculeName": "listLVImg",
"leftLabel": { "leftLabel": {
"moleculeName": "label", "moleculeName": "label",
"text": "left" "text": "Lorem ipsum"
}, },
"rightLabel": { "rightLabel": {
"moleculeName": "label", "moleculeName": "label",
"text": "right" "text": "Label"
}, },
"image": { "image": {
"moleculeName": "image", "moleculeName": "image",
"image": "alert_standard" "image": "imageName_PayPal_logo"
}, },
"action" : { "action" : {
"disabled" : false, "disabled" : false,

View File

@ -1,36 +0,0 @@
"moleculeName": "listLVImgAll",
"eyebrowHeadlineBodyLink" : {
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
},
"link" : {
"moleculeName" : "link",
"title" : "link",
"action": {
"actionType":"back"
}
}
},
"image": {
"moleculeName": "image",
"image": "alert_standard"
},
"action" : {
"disabled" : false,
"analyticsData" : {
},
"title" : "Manage plan",
"actionType" : "openPage",
"pageType" : "planLanding"
}

View File

@ -1,40 +0,0 @@
"moleculeName": "listLVImgRCAll",
"eyebrowHeadlineBodyLink" : {
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
},
"link" : {
"moleculeName" : "link",
"title" : "link",
"action": {
"actionType":"back"
}
}
},
"rightLabel": {
"moleculeName": "label",
"text": "right"
},
"image": {
"moleculeName": "image",
"image": "alert_standard"
},
"action" : {
"disabled" : false,
"analyticsData" : {
},
"title" : "Manage plan",
"actionType" : "openPage",
"pageType" : "planLanding"
}

View File

@ -1,24 +0,0 @@
"number": 1,
"moleculeName" : "listLVNAll",
"eyebrowHeadlineBodyLink" : {
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
},
"link" : {
"moleculeName" : "link",
"title" : "link",
"action": {
"actionType":"back"
}
}
}

View File

@ -1,13 +0,0 @@
"number": 1,
"moleculeName" : "listLVNLBdy",
"headlineBody" : {
"moleculeName" : "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
}

View File

@ -1,26 +0,0 @@
"radioButton" : {
"moleculeName" : "radioButton"
},
"moleculeName" : "listLVRBAll",
"eyebrowHeadlineBodyLink" : {
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
},
"link" : {
"moleculeName" : "link",
"title" : "link",
"action": {
"actionType":"back"
}
}
}

View File

@ -1,15 +0,0 @@
"radioButton" : {
"moleculeName" : "radioButton"
},
"moleculeName" : "listLVRBBdy",
"headlineBody" : {
"moleculeName" : "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
}

View File

@ -1,30 +0,0 @@
"radioButton" : {
"moleculeName" : "radioButton"
},
"moleculeName" : "listLVRBImg",
"image": {
"moleculeName": "image",
"image": "alert_standard"
},
"eyebrowHeadlineBodyLink" : {
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
},
"link" : {
"moleculeName" : "link",
"title" : "Hello",
"action": {
"actionType":"back"
}
}
}

View File

@ -1,23 +0,0 @@
"moleculeName" : "listPrgBarData",
"progressBar" : {
"moleculeName" : "multiProgressBar",
"progressList": [{
"percent" : 40,
"color" : "red"
},{
"percent" : 30,
"color" : "blue"
}]
},
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"action" : {
"actionType" : "back"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "right"
}

View File

@ -1,18 +0,0 @@
"moleculeName": "planLockup",
"planLabel": {
"moleculeName": "label",
"text": "XL"
},
"headline": {
"moleculeName": "label",
"text": "headline"
},
"subHeadline": {
"moleculeName": "label",
"text": "subHeadline"
},
"body": {
"moleculeName": "label",
"text": "body"
}

View File

@ -5,21 +5,18 @@
}, },
"leftHeadline": { "leftHeadline": {
"moleculeName": "label", "moleculeName": "label",
"text": "headline" "text": "Lorem ipsum dolor sit."
}, },
"leftBody": { "leftBody": {
"moleculeName": "label", "moleculeName": "label",
"text": "body" "text": "Lorem ipsum dolor sit."
}, },
"leftSubBody": { "leftSubBody": {
"moleculeName": "label", "moleculeName": "label",
"text": "subBody" "text": "Lorem ipsum dolor sit."
}, },
"rightLabel": { "rightLabel": {
"moleculeName": "label", "moleculeName": "label",
"text": "right" "text": "Label"
}, }
"action": {
"actionType": "noop"
}

View File

@ -1,27 +0,0 @@
"moleculeName" : "list1CTxt",
"eyebrow": {
"moleculeName" : "label",
"text" : "eyebrow"
},
"headline": {
"moleculeName" : "label",
"text" : "headline"
},
"subHeadline": {
"moleculeName" : "label",
"text" : "subHeadline"
},
"body": {
"moleculeName" : "label",
"text" : "body"
},
"link": {
"moleculeName" : "link",
"title" : "link",
"action": {
"actionType": "noop"
}
},
"action": {
"actionType": "back"
}

View File

@ -2,13 +2,13 @@
"headlineBody" : { "headlineBody" : {
"headline": { "headline": {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "Hello"
}, },
"body": { "body": {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello"
} }
}, },
"action": { "action": {
"actionType": "noop" "actionType": "back"
} }

View File

@ -1,14 +1,14 @@
"moleculeName" : "listPrgBarThin", "moleculeName" : "listPrgBarThin",
"leftBody" : { "leftBody" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "x alkdfjaldf kjasdlkfj salkdfj aslkfdj lksafdj aslkdfj slkfd jsalk jasdlk jsadl kjakslfj "
}, },
"action" : { "action" : {
"actionType" : "back" "actionType" : "back"
}, },
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "Hello"
}, },
"rightBar" : { "rightBar" : {
"moleculeName" : "line", "moleculeName" : "line",
@ -21,5 +21,5 @@
}, },
"leftHeadline" : { "leftHeadline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "alkjf dsalkjf kjadfl kja"
} }

View File

@ -1,30 +0,0 @@
"moleculeName" : "listRVBtn",
"button" : {
"moleculeName" : "button",
"title": "button",
"action": {
"actionType": "noop"
}
},
"eyebrowHeadlineBodyLink" : {
"body" : {
"moleculeName" : "label",
"text" : "Body"
},
"link" : {
"moleculeName" : "link",
"title" : "TextButton",
"action" : {
"actionType" : "back"
}
},
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "Eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "Headline"
}
}

View File

@ -1,6 +1,6 @@
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "heeeeyy"
}, },
"moleculeName" : "listRVLine", "moleculeName" : "listRVLine",
"bar" : { "bar" : {
@ -9,7 +9,7 @@
}, },
"leftLabel" : { "leftLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "left" "text" : "Hello"
}, },
"action": { "action": {
"actionType": "back" "actionType": "back"

View File

@ -4,5 +4,5 @@
}, },
"leftLabel" : { "leftLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "left" "text" : "Hello Ryan!!!"
} }

View File

@ -2,19 +2,19 @@
"eyebrowHeadlineBodyLink": { "eyebrowHeadlineBodyLink": {
"eyebrow" : { "eyebrow" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "eyebrow" "text" : "Hello Ryan!!!"
}, },
"headline" : { "headline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "Hello Ryan!!!"
}, },
"body" : { "body" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello Ryan!!!"
}, },
"link" : { "link" : {
"moleculeName" : "link", "moleculeName" : "link",
"title" : "link", "title" : "Hello",
"action": { "action": {
"actionType":"back" "actionType":"back"
} }
@ -22,7 +22,7 @@
}, },
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "Hello Ryan!!!"
}, },
"arrow": { "arrow": {
"moleculeName": "arrow" "moleculeName": "arrow"

View File

@ -3,16 +3,16 @@
"moleculeName":"headlineBody", "moleculeName":"headlineBody",
"headline" : { "headline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "Hello Ryan!!!"
}, },
"body" : { "body" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello Ryan!!!"
} }
}, },
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "Hello Ryan!!!"
}, },
"arrow": { "arrow": {
"moleculeName": "arrow" "moleculeName": "arrow"

View File

@ -1,27 +0,0 @@
"moleculeName" : "listRVCaretAll",
"rightLabel" : {
"moleculeName" : "label",
"text": "right"
},
"eyebrowHeadlineBodyLink" : {
"body" : {
"moleculeName" : "label",
"text" : "Body"
},
"link" : {
"moleculeName" : "link",
"title" : "TextButton",
"action" : {
"actionType" : "back"
}
},
"moleculeName" : "eyebrowHeadlineBodyLink",
"eyebrow" : {
"moleculeName" : "label",
"text" : "Eyebrow"
},
"headline" : {
"moleculeName" : "label",
"text" : "Headline"
}
}

View File

@ -1,6 +1,6 @@
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "heeeeyy"
}, },
"moleculeName" : "listRVWheel", "moleculeName" : "listRVWheel",
"wheel" : { "wheel" : {
@ -8,7 +8,7 @@
}, },
"leftLabel" : { "leftLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "left" "text" : "Hello"
}, },
"action": { "action": {
"actionType": "back" "actionType": "back"

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CBillChg",
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "center"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "right"
}

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CBillHst",
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "center"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "right"
}

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CDataUsg",
"leftLabel" : {
"moleculeName" : "label",
"text" : "8.0 GB"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "Verizon L data"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "2.0 GB"
}

View File

@ -1,18 +0,0 @@
"moleculeName" : "list3CIntData",
"leftLabel" : {
"moleculeName" : "label",
"text" : "8.0 GB"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "Verizon L data"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "2.0 GB"
},
"arrow": {
"moleculeName": "arrow",
"color": "green",
"degrees": 270
}

View File

@ -1,71 +0,0 @@
"moleculeName" : "list3CSpdTst",
"title": {
"moleculeName" : "label",
"text" : "title"
},
"topLeftHeadlineBody" : {
"moleculeName": "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
},
"topCenterHeadlineBody" : {
"moleculeName": "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
},
"topRightHeadlineBody" : {
"moleculeName": "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
},
"bottomLeftHeadlineBody" : {
"moleculeName": "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
},
"bottomCenterHeadlineBody" : {
"moleculeName": "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
},
"bottomRightHeadlineBody" : {
"moleculeName": "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}
}

View File

@ -1,46 +1,46 @@
"moleculeName" : "list2CCmpr1", "moleculeName" : "list2CCmpr1",
"leftHeadline1" : { "leftHeadline1" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline1" "text" : "Hello"
}, },
"leftHeadline2" : { "leftHeadline2" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline2" "text" : "Hello"
}, },
"leftHeadline3" : { "leftHeadline3" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline3" "text" : "Hello"
}, },
"leftBody" : { "leftBody" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello"
}, },
"leftLink" : { "leftLink" : {
"moleculeName" : "label", "moleculeName" : "label",
"title" : "link", "title" : "Hello",
"action": { "action": {
"actionType": "back" "actionType": "back"
} }
}, },
"rightHeadline1" : { "rightHeadline1" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline1" "text" : "Hello"
}, },
"rightHeadline2" : { "rightHeadline2" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline2" "text" : "Hello"
}, },
"rightHeadline3" : { "rightHeadline3" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline3" "text" : "Hello"
}, },
"rightBody" : { "rightBody" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello"
}, },
"rightLink" : { "rightLink" : {
"moleculeName" : "label", "moleculeName" : "label",
"title" : "link", "title" : "Hello",
"action": { "action": {
"actionType": "back" "actionType": "back"
} }

View File

@ -1,9 +0,0 @@
"moleculeName" : "list2CDrpDrp1",
"leftDropDown" : {
"moleculeName": "dropDown",
"options": ["Option1","Option2","Option3"]
},
"rightDropDown" : {
"moleculeName": "dropDown",
"options": ["Option1","Option2","Option3"]
}

View File

@ -1,17 +1,17 @@
"moleculeName" : "list2CTxtPrc1", "moleculeName" : "list2CTxtPrc1",
"leftHeadline" : { "leftHeadline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "Hello"
}, },
"leftBody" : { "leftBody" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Hello"
}, },
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "Hello"
}, },
"rightSubLabel" : { "rightSubLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "rightSub" "text" : "Hello"
} }

View File

@ -1,9 +1,9 @@
"moleculeName" : "list2CTxtPrc2", "moleculeName" : "list2CTxtPrc1",
"leftLabel" : { "leftLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "left" "text" : "Hello"
}, },
"rightLabel" : { "rightLabel" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "right" "text" : "Hello"
} }

View File

@ -1,34 +0,0 @@
"moleculeName" : "doughnutChart",
"title" : {
"moleculeName" : "label",
"text" : "title"
},
"subtitle" : {
"moleculeName" : "label",
"text" : "subtitle"
},
"sections" : [{
"moleculeName": "doughnutChartItem",
"label": {
"moleculeName" : "label",
"text" : "subtitle"
},
"percent": 22,
"color": "green"
},{
"moleculeName": "doughnutChartItem",
"label": {
"moleculeName" : "label",
"text" : "subtitle"
},
"percent": 15,
"color": "blue"
},{
"moleculeName": "doughnutChartItem",
"label": {
"moleculeName" : "label",
"text" : "subtitle"
},
"percent": 35,
"color": "green"
}]

View File

@ -1,13 +0,0 @@
"moleculeName" : "planNamesLockup",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"subHeadline" : {
"moleculeName" : "label",
"text" : "subHeadline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}

View File

@ -1,25 +0,0 @@
"moleculeName" : "listPrgBarThin",
"leftBody" : {
"moleculeName" : "label",
"text" : "body"
},
"action" : {
"actionType" : "back"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "right"
},
"rightBar" : {
"moleculeName" : "line",
"backgroundColor" : "red"
},
"progressBar" : {
"moleculeName" : "progressBar",
"percent" : 40,
"color" : "red"
},
"leftHeadline" : {
"moleculeName" : "label",
"text" : "headline"
}

View File

@ -1,9 +0,0 @@
"moleculeName" : "list1CTxtDiv1",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}

View File

@ -1,9 +0,0 @@
"moleculeName" : "list1CTxtDiv2",
"headline" : {
"moleculeName" : "label",
"text" : "headline"
},
"body" : {
"moleculeName" : "label",
"text" : "body"
}

View File

@ -1,9 +1,9 @@
"moleculeName" : "list1CTxtDiv3", "moleculeName" : "list1CTxtDiv3",
"headline" : { "headline" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "headline" "text" : "8.0 GB"
}, },
"body" : { "body" : {
"moleculeName" : "label", "moleculeName" : "label",
"text" : "body" "text" : "Verizon L data"
} }

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CBillChgDiv",
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "left"
}

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CBillHisDiv",
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "left"
}

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CDataUsgDiv",
"leftLabel" : {
"moleculeName" : "label",
"text" : "8.0 GB"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "Verizon L data"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "2.0 GB"
}

View File

@ -1,13 +0,0 @@
"moleculeName" : "list3CSpdTstDiv",
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"centerLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "left"
}

View File

@ -1,9 +0,0 @@
"moleculeName" : "list2CSbscDiv",
"leftLabel" : {
"moleculeName" : "label",
"text" : "left"
},
"rightLabel" : {
"moleculeName" : "label",
"text" : "right"
}

View File

@ -1,194 +0,0 @@
{
"ResponseInfo": {
"locale": "EN",
"server": "10-74-170-83.ebiz.verizon.com-mf_prepayss01",
"code": "00000",
"hideNotificationLogo": false,
"message": "0",
"buildNumber": "6698",
"type": "Success",
"requestId": "dbb1ee17-69fe-464e-8a82-9563b83422ab",
"topAlertTime": 0
},
"Page": {
"navigationBar": {
"moleculeName": "navigationBar",
"title": "Account security"
},
"pageType": "tbd",
"cache": false,
"screenHeading": "Account security",
"template": "stack",
"header": {
"moleculeName": "header",
"molecule": {
"moleculeName": "headlineBody",
"headline": {
"moleculeName": "label",
"text": "Next up, let's secure this account."
},
"body": {
"moleculeName": "label",
"attributes": [
{
"topPadding": 30,
"length": 19,
"action": {
"actionType": "openPage",
"analyticsData": {
"vzdl.page.pageLinkName": "/mf/Manage Profile|Email Verify",
"vzdl.page.linkName": "Verify"
},
"pageType": "whyWeAskingAEMPR"
},
"location": 113,
"type": "action"
}
],
"text": "We'll use this PIN and security question for verification and help accessing the account. Make sure the PIN meets these requirements."
}
}
},
"stack": {
"moleculeName": "stack",
"molecules": [
{
"moleculeName": "stackItem",
"horizontalAlignment": "leading",
"molecule": {
"moleculeName": "digitTextField",
"editable": true,
"title": "Account security PIN",
"digits": 4,
"fieldKey": "securityPIN"
}
},
{
"moleculeName": "stackItem",
"horizontalAlignment": "leading",
"molecule": {
"moleculeName": "digitTextField",
"editable": true,
"title": "Confirm account security PIN",
"type": "secure",
"digits": 4,
"fieldKey": "confirmSecurityPIN"
}
},
{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "dropDown",
"fieldKey": "securityQuestion",
"title": "Security question",
"options": [
"What was the first live concert you attended?",
"Where did you and your spouse first meet?",
"What was your favorite place to visit as a child?",
"What was the first name of your first roommate?",
"What is the name of a memorable place?",
"What is the first name of your best friend?",
"What was your favorite restaurant in college?"
],
"selectedIndex": 0
}
},
{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "textField",
"title": "Security answer",
"type": "text",
"fieldKey": "securityAnswer"
}
},
{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "label",
"text": "Be sure to remember these details. They'll be needed to access the account later."
}
}
]
},
"footer": {
"moleculeName": "footer",
"molecule": {
"moleculeName": "twoButtonView",
"primaryButton": {
"groupName": "default",
"moleculeName": "button",
"title": "Next",
"action": {
"analyticsData": {
"vzdl.page.linkName": "Legal Disclosure"
},
"fieldKey": "next",
"actionType": "openPage",
"extraParameters": {
"from": "none"
},
"presentationStyle": "push",
"pageType": "legalDisclosurePR"
}
}
}
},
"formRules": [
{
"groupName": "default",
"rules": [
{
"regex": "^(?!.*0123|.*1234|.*2345|.*3456|.*4567|.*5678|.*6789|.*3210|.*4321|.*5432|.*6543|.*7654|.*8765|.*9876|.*0000|.*1111|.*2222|.*3333|.*4444|.*5555|.*6666|.*7777|.*8888|.*9999).*$",
"type": "regex",
"fields": [
"securityPIN"
],
"errorMessage": {
"securityPIN": "Your PIN can't have numbers in order or repeating."
}
},
{
"type": "equals",
"fields": [
"securityPIN",
"confirmSecurityPIN"
],
"errorMessage": {
"confirmSecurityPIN": "Your account PIN entries don't match. Try again."
}
},
{
"type": "regex",
"regex": "^[A-Za-z0-9 ]{3,10}$",
"fields": [
"securityAnswer"
],
"errorMessage": {
"securityAnswer": "Your security answer can only letters, numbers, spaces, and periods."
}
},
{
"type": "regex",
"regex": "^.{3,10}$",
"fields": [
"securityAnswer"
],
"errorMessage": {
"securityAnswer": "Your answer must be between 3-10 characters."
}
},
{
"type": "allRequired",
"ruleId": "requiredRule",
"fields": [
"securityPIN",
"confirmSecurityPIN",
"securityAnswer"
]
}
]
}
]
}
}

View File

@ -1,399 +0,0 @@
{
"ResponseInfo": {},
"Page": {
"pageType": "contactUs",
"screenHeading": "Select an international plan",
"template": "list",
"formRules": [{
"groupName": "default",
"rules": [{
"type": "anyValueChanged",
"fields": [
"c1"
]
}]
}],
"molecules": [{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "default",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "primary",
"style": "primary",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "large",
"size": "large",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "standard",
"size": "standard",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "small",
"size": "small",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "tiny",
"size": "tiny",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary",
"style": "secondary",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary large",
"style": "secondary",
"size": "large",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary standard",
"style": "secondary",
"size": "standard",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary small",
"style": "secondary",
"size": "small",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary tiny",
"style": "secondary",
"size": "tiny",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "primary disabled",
"enabled": false,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "small disabled",
"enabled": false,
"size": "small",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary disabled",
"enabled": false,
"style": "secondary",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"molecule": {
"moleculeName": "button",
"title": "secondary small disabled",
"style": "secondary",
"enabled": false,
"size": "small",
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "default",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "primary",
"style": "primary",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "large",
"size": "large",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "standard",
"size": "standard",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "small",
"size": "small",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "tiny",
"size": "tiny",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary",
"style": "secondary",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary large",
"style": "secondary",
"size": "large",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary standard",
"style": "secondary",
"size": "standard",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary small",
"style": "secondary",
"size": "small",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary tiny",
"style": "secondary",
"size": "tiny",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "primary disabled",
"enabled": false,
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "small disabled",
"enabled": false,
"size": "small",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary disabled",
"enabled": false,
"style": "secondary",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"moleculeName": "listItem",
"backgroundColor": "black",
"molecule": {
"moleculeName": "button",
"title": "secondary small disabled",
"style": "secondary",
"enabled": false,
"size": "small",
"inverted": true,
"action": {
"actionType": "noop"
}
}
},{
"checkbox" : {
"moleculeName" : "checkbox",
"fieldKey": "c1",
"groupName": "default",
},
"moleculeName" : "listLVCB",
"eyebrowHeadlineBodyLink" : {
"moleculeName" : "eyebrowHeadlineBodyLink",
"headline" : {
"moleculeName" : "label",
"text" : "Change to enable the primary footer button."
}
}
}],
"footer": {
"moleculeName": "footer",
"molecule": {
"moleculeName":"twoButtonView",
"primaryButton":{
"moleculeName": "button",
"title":"x",
"groupName": "default",
"action": {
"actionType": "openPage",
"pageType": "rtlVisitUs"
}
},
"secondaryButton":{
"moleculeName": "button",
"title":"y",
"action": {
"actionType": "back"
}
}
}
}
}
}

View File

@ -1,133 +0,0 @@
{
"ResponseInfo": {
"locale": "EN",
"server": "10-74-170-83.ebiz.verizon.com-mf_prepayss01",
"code": "00000",
"hideNotificationLogo": false,
"message": "0",
"buildNumber": "6698",
"type": "Success",
"requestId": "dbb1ee17-69fe-464e-8a82-9563b83422ab",
"topAlertTime": 0
},
"Page": {
"navigationBar": {
"moleculeName": "navigationBar",
"title": "Account security"
},
"pageType": "tbd",
"cache": false,
"screenHeading": "Account security",
"template": "stack",
"stack": {
"moleculeName": "stack",
"molecules": [
{
"moleculeName": "stackItem",
"horizontalAlignment": "leading",
"molecule": {
"moleculeName": "digitTextField",
"editable": true,
"title": "Account security PIN",
"digits": 4,
"fieldKey": "securityPIN"
}
},
{
"moleculeName": "stackItem",
"horizontalAlignment": "leading",
"molecule": {
"moleculeName": "digitTextField",
"editable": true,
"title": "Confirm account security PIN",
"type": "text",
"digits": 4,
"fieldKey": "confirmSecurityPIN"
}
},
{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "textField",
"fieldKey": "preferredFirstName",
"type": "text",
"text": "",
"errorMessage": "Please enter a valid first name.",
"title": "Preferred First Name",
"feedback": "This will replace greeting name if you have one.",
"required": false
}
}
]
},
"footer": {
"moleculeName": "footer",
"molecule": {
"moleculeName": "twoButtonView",
"primaryButton": {
"groupName": "default",
"moleculeName": "button",
"title": "Next",
"action": {
"analyticsData": {
"vzdl.page.linkName": "Legal Disclosure"
},
"fieldKey": "next",
"actionType": "openPage",
"extraParameters": {
"from": "none"
},
"presentationStyle": "push",
"pageType": "legalDisclosurePR"
}
}
}
},
"formRules": [
{
"groupName": "default",
"rules": [
{
"regex": "^[0-6]{0,4}$",
"type": "regex",
"fields": [
"securityPIN"
],
"errorMessage": {
"securityPIN": "Your PIN can't have numbers in order or repeating."
}
},
{
"type": "equals",
"fields": [
"securityPIN",
"confirmSecurityPIN"
],
"errorMessage": {
"confirmSecurityPIN": "Your account PIN entries don't match. Try again."
}
},
{
"regex": "^[0-9a-zA-Z@\\.\\-\\_?]{0,25}$",
"ruleId": "anyAlphaNumeric",
"errorMessage": {
"preferredFirstName": "Only use for First Name"
},
"type": "regex",
"fields": [
"preferredFirstName"
]
},
{
"type": "allRequired",
"ruleId": "requiredRule",
"fields": [
"securityPIN",
"confirmSecurityPIN"
]
}
]
}
]
}
}

View File

@ -19,10 +19,17 @@
"stack": { "stack": {
"moleculeName": "stack", "moleculeName": "stack",
"molecules": [ "molecules": [
{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "testToggle",
"fieldKey": "isActive"
}
},
{ {
"moleculeName": "stackItem", "moleculeName": "stackItem",
"molecule": { "molecule": {
"moleculeName": "textView", "moleculeName": "textField",
"fieldKey": "firstName", "fieldKey": "firstName",
"type": "text", "type": "text",
"errorMessage": "Please enter a valid first name.", "errorMessage": "Please enter a valid first name.",
@ -72,11 +79,12 @@
{ {
"moleculeName": "stackItem", "moleculeName": "stackItem",
"molecule": { "molecule": {
"moleculeName": "textField", "moleculeName": "textFieldBase64",
"fieldKey": "zipcode", "fieldKey": "zipcode",
"type": "number", "type": "number",
"placeholder": "90210", "placeholder": "90210",
"title": "Zip Code", "title": "Zip Code",
"text": "NzUwMzQ=",
"errorMessage": "Please enter a valid zip code." "errorMessage": "Please enter a valid zip code."
} }
} }

View File

@ -1,196 +0,0 @@
{
"ResponseInfo" : {
"locale" : "EN",
"server" : "loghost-mf_postpayss01",
"userMessage" : "0",
"code" : "00000",
"appSessionExtended" : true,
"message" : "0",
"mdn" : "7165723410",
"buildNumber" : "61",
"type" : "Success",
"requestId" : "12321a81-a48b-4023-94d9-7bd42af6d65a",
"topAlertTime" : 0
},
"Page" : {
"pageStatNames" : [
"\/mf\/retail\/appt\/flow",
"\/mf\/retail\/appt\/reasons"
],
"template" : "list",
"footer" : {
"moleculeName" : "footer",
"molecule" : {
"moleculeName" : "twoButtonView",
"primaryButton" : {
"groupName" : "default",
"moleculeName" : "button",
"title" : "Continue",
"action" : {
"analyticsData" : {
"vzdl.page.linkName" : "Continue"
},
"extraParameters" : {
"destPageType" : "rtlApptsStoreLocator",
"FromStoreDetails" : "N"
},
"actionType" : "openPage",
"title" : "Confirm",
"presentationStyle" : "push",
"pageType" : "launchApp"
}
}
}
},
"molecules" : [
{
"dropDown" : {
"moleculeName" : "dropDown",
"action" : {
"actionType" : "noop"
},
"placeholder" : "Select a reason for visit",
"title" : "What can we help you with?",
"fieldKey" : "reason",
"type" : "text",
"options" : [
"Account Support",
"Shop",
"Device Setup\/Troubleshooting",
"Other"
]
},
"line" : {
"moleculeName" : "line",
"type" : "none"
},
"moleculeName" : "dropDownListItem",
"molecules" : [
[
{
"line" : {
"moleculeName" : "line",
"type" : "none"
},
"topPadding" : 0,
"moleculeName" : "listItem",
"molecule" : {
"title" : "Relating to",
"fieldKey" : "subReason",
"moleculeName" : "dropDown",
"options" : [
"Autopay question or issue",
"Billing issue",
"Misleading promise or information inquiry",
"Disconnect line",
"Payment arrangements",
"Promised promotion or offer",
"Other"
],
"type" : "text",
"action" : {
"actionType" : "noop"
}
}
}
],
[
],
[
],
[
]
]
}
],
"cache" : false,
"header" : {
"moleculeName" : "header",
"molecule" : {
"moleculeName" : "headlineBody",
"headline" : {
"moleculeName" : "label",
"text" : "Make an appointment to see a representative."
},
"body" : {
"moleculeName" : "label",
"text" : "We currently have limited staffing. For your safety and the safety of our employees, we are only scheduling appointments to provide one-on-one support for account maintenance or device troubleshooting.",
"fontStyle" : "BoldBodySmall"
}
}
},
"tab" : [
{
"appContext" : "mobileFirstSS",
"title" : "Schedule",
"actionType" : "openPage",
"moleculeName" : "label",
"presentationStyle" : "root",
"pageType" : "rtlReasonAndSubReasons"
},
{
"appContext" : "mobileFirstSS",
"title" : "My Appointments",
"actionType" : "openPage",
"moleculeName" : "label",
"presentationStyle" : "root",
"pageType" : "rtlViewAllScheduledAppts"
}
],
"pageType" : "rtlReasonAndSubReasons",
"suppressPostLaunchRequests" : false,
"formRules" : [
{
"groupName": "default",
"rules": [
{
"type": "allRequired",
"ruleId": "allRequired",
"fields": [
"reason",
"subReason"
]
}
],
"effects": [
{
"type": "dynamicRuleFormFieldEffect",
"fieldKey": "subReason",
"activatedRuleIds": ["allRequired"],
"rules": [
{
"type": "regex",
"regex": "^Account Support$",
"fields": [
"reason"
]
}
]
},
{
"type": "enableFormFieldEffect",
"fieldKey": "subReason",
"rules": [
{
"type": "regex",
"regex": "^Account Support$",
"fields": [
"reason"
]
}
]
}
]
}
],
"navigationBar" : {
"moleculeName" : "navigationBar",
"title" : "Make Appointment"
},
"tabBarHidden" : true,
"isAtomicTabs" : true
}
}

View File

@ -86,7 +86,7 @@
"moleculeName": "button", "moleculeName": "button",
"title": "Learn more", "title": "Learn more",
"style": "secondary", "style": "secondary",
"size": "small", "size": "tiny",
"action": { "action": {
"actionType": "openPage", "actionType": "openPage",
"pageType": "x" "pageType": "x"
@ -147,7 +147,7 @@
"moleculeName": "button", "moleculeName": "button",
"title": "Learn more", "title": "Learn more",
"style": "secondary", "style": "secondary",
"size": "small", "size": "tiny",
"action": { "action": {
"actionType": "openPage", "actionType": "openPage",
"pageType": "x" "pageType": "x"

View File

@ -1,931 +0,0 @@
{
"SystemParams":{
"googleMapsAPIKey":"AIzaSyD9-5Q4fTMYESxmbZhYpA98sy7XFK2d0BE",
"enableGoogleMapsIOS":true
},
"Page":{
"ResponseInfo":{
"type":"Success",
"code":"00000"
},
"pageType":"prospectWelcomeTrial",
"backgroundColor":"coolGray1",
"tabBarIndex":0,
"navigationBar":{
"line":{
"moleculeName":"line",
"type":"none"
},
"moleculeName":"navigationBar",
"additionalLeftButtons":[
{
"accessibilityText":"Verizon logo, tap anytime to scroll to top of page",
"moleculeName":"navigationImageButton",
"image":"nav_vz_mark",
"imageRenderingMode":"alwaysOriginal",
"action":{
"analyticsData":{
"vzdl.page.linkName":"global black bar nav: vz icon"
},
"actionType":"scrollToTop"
}
}
],
"additionalRightButtons":[
{
"moleculeName":"navigationLabelButton",
"title":"Sign in",
"action":{
"hideCloseButton":false,
"appContext":"mobileFirstSS",
"analyticsData":{
"vzdl.page.id":"prospectTrailWelcome",
"vzdl.target.engagement.intent":"customer sign in",
"vzdl.page.displayChannel":"MVA",
"vzdl.page.linkName":"I'm a customer",
"vzdl.page.name":"prospectTrailWelcome"
},
"requestURL":"https:\/\/mobile-exp.vzw.com\/mobile\/nsa\/nos\/gw\/launchapp\/oauthSignIn?",
"extraParameters":{
"oAuthLaunchAppFlow":"Y"
},
"disableNativeAction":false,
"customUserAgent":"MY_VZW_APP;IOS;16.3.1;iPhone15,2;10.5.0;VZW-MFA-IOS",
"openInWebview":true,
"disableOfflineDevice":false,
"hideUrl":false,
"actionType":"openPage",
"pageType":"userSignIn",
"presentationStyle":"root",
"isSelected":false,
"openOauthWebView":false,
"hideWebNavigation":false,
"selected":false
}
}
],
"style":"dark"
},
"line":{
"moleculeName":"line",
"type":"none"
},
"header":{
"moleculeName":"header",
"useVerticalMargins":true,
"backgroundColor":"coolGray1",
"topPadding":32,
"bottomPadding":24,
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"label",
"text":"Join the best mobile\nnetwork.",
"textAlignment":"center",
"fontStyle":"BoldTitleXLarge"
}
},
"template":"list",
"molecules":[
{
"moleculeName":"listItem",
"useVerticalMargins":false,
"backgroundColor":"coolGray1",
"molecule":{
"moleculeName": "stack",
"axis": "vertical",
"backgroundColor":"black",
"cornerRadius":8,
"useVerticalMargins":true,
"topPadding":24,
"bottomPadding":24,
"molecules": [{
"moleculeName":"stackItem",
"spacing": 0,
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"label",
"text":"Bring your own\ndevice",
"fontStyle":"BoldTitleXLarge",
"textColor":"white",
"textAlignment":"center"
}
},{
"moleculeName":"stackItem",
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"label",
"text":"Bring your device and get up to\n$540 on select plans.",
"fontStyle":"RegularBodyLarge",
"textColor":"white",
"textAlignment":"center"
}
},{
"moleculeName":"stackItem",
"horizontalAlignment":"center",
"verticalAlignment":"center",
"molecule":{
"moleculeName":"button",
"size":"small",
"style":"primary",
"inverted":true,
"title":"Get started",
"action":{
"analyticsData":{
"vzdl.page.id":"prospectTrailWelcome",
"vzdl.target.engagement.intent":"prospectJoinVerizon",
"vzdl.page.displayChannel":"MVA",
"vzdl.page.linkName":"Join Verizon",
"vzdl.page.name":"prospectTrailWelcome"
},
"presentationStyle":"root",
"pageType":"joinByodProspect",
"disableOfflineDevice":false,
"showNativeNavigation":true,
"disableAction":false,
"hideCloseButton":true,
"hideWebNavigation":false,
"checkCameraPermission":false,
"enableNativeScroll":true,
"appContext":"mobileFirstSS",
"disableNativeAction":false,
"openInWebview":true,
"isSelected":false,
"requestURL":"https:\/\/www.verizon.com\/onedp\/api\/mva\/verifyDevice?identifier=IPHONE15,2&promptZip=true",
"tryToReplaceFirst":false,
"browserUrl":"https:\/\/www.verizon.com\/onedp\/api\/mva\/verifyDevice?identifier=IPHONE15,2&promptZip=true",
"actionType":"openURL",
"length":0,
"openOauthWebView":true,
"selected":false,
"clientParameters":{
"timeout":30,
"list":[
{
"type":"eSimCapable"
}
]
},
"customUserAgent":"MY_VZW_APP;IOS;16.3.1;iPhone15,2;10.5.0;VZW-MFA-IOS",
"hideUrl":true
}
}
}]
}
},
{
"moleculeName":"listItem",
"useHorizontalMargins":false,
"topPadding":48,
"bottomPadding":0,
"backgroundColor":"coolGray1",
"molecule":{
"moleculeName":"carousel",
"accessibilityText":"carousel",
"pagingMolecule":{
"moleculeName":"barsCarouselIndicator",
"position":-20
},
"height":92,
"spacing":12,
"itemWidthPercent":45,
"useHorizontalMargins":true,
"leftPadding":16,
"rightPadding":16,
"molecules":[
{
"moleculeName":"carouselItem",
"backgroundColor":"white",
"cornerRadius":8,
"useVerticalMargins":true,
"topPadding":16,
"bottomPadding":16,
"molecule":{
"moleculeName":"stack",
"axis":"vertical",
"molecules":[
{
"moleculeName":"stackItem",
"spacing":0,
"horizontalAlignment":"leading",
"molecule":{
"moleculeName":"label",
"text":"Deals",
"fontStyle":"BoldTitleSmall"
}
},
{
"moleculeName":"stackItem",
"horizontalAlignment":"trailing",
"verticalAlignment":"trailing",
"molecule":{
"moleculeName":"arrow"
}
}
]
},
"action":{
"presentationStyle":"push",
"actionType":"openPage",
"pageType":"deals"
}
},
{
"moleculeName":"carouselItem",
"backgroundColor":"white",
"cornerRadius":8,
"useVerticalMargins":true,
"topPadding":16,
"bottomPadding":16,
"molecule":{
"moleculeName":"stack",
"axis":"vertical",
"molecules":[
{
"moleculeName":"stackItem",
"spacing":0,
"horizontalAlignment":"leading",
"molecule":{
"moleculeName":"label",
"text":"Shop phones",
"fontStyle":"BoldTitleSmall"
}
},
{
"moleculeName":"stackItem",
"horizontalAlignment":"trailing",
"verticalAlignment":"trailing",
"molecule":{
"moleculeName":"arrow"
}
}
]
},
"action":{
"presentationStyle":"push",
"actionType":"openPage",
"pageType":"smartphones"
}
},
{
"moleculeName":"carouselItem",
"backgroundColor":"white",
"cornerRadius":8,
"useVerticalMargins":true,
"topPadding":16,
"bottomPadding":16,
"molecule":{
"moleculeName":"stack",
"axis":"vertical",
"molecules":[
{
"moleculeName":"stackItem",
"spacing":0,
"horizontalAlignment":"leading",
"molecule":{
"moleculeName":"label",
"text":"Shop plans",
"fontStyle":"BoldTitleSmall"
}
},
{
"moleculeName":"stackItem",
"horizontalAlignment":"trailing",
"verticalAlignment":"trailing",
"molecule":{
"moleculeName":"arrow"
}
}
]
},
"action":{
"presentationStyle":"push",
"actionType":"openPage",
"pageType":"plans"
}
}
]
}
},
{
"moleculeName":"listItem",
"topPadding":48,
"bottomPadding":0,
"horizontalAlignment":"center",
"backgroundColor":"coolGray1",
"molecule":{
"moleculeName":"label",
"text":"The network America\nrelies on.",
"textAlignment":"center",
"fontStyle":"BoldTitleMedium"
}
},
{
"moleculeName":"listItem",
"topPadding":24,
"bottomPadding":0,
"backgroundColor":"coolGray1",
"molecule":{
"moleculeName":"stack",
"axis":"horizontal",
"molecules":[
{
"moleculeName":"stackItem",
"molecule":{
"moleculeName":"image",
"image":"Prospect5GChart",
"width":35,
"height":32,
"contentMode":"scaleAspectFit"
}
},
{
"moleculeName":"stackItem",
"molecule":{
"moleculeName":"label",
"text":"5G Nationwide covers 200+ million people in 2,700+ cities.",
"fontStyle":"RegularBodyLarge"
}
}
]
}
},
{
"moleculeName":"listItem",
"backgroundColor":"coolGray1",
"topPadding":16,
"bottomPadding":0,
"molecule":{
"moleculeName":"stack",
"axis":"horizontal",
"molecules":[
{
"moleculeName":"stackItem",
"molecule":{
"moleculeName":"image",
"image":"ProspectDevice",
"width":35,
"height":32,
"contentMode":"scaleAspectFit"
}
},
{
"moleculeName":"stackItem",
"molecule":{
"moleculeName":"label",
"text":"Highest in Customer Satisfaction with Small Business Wireless Service.",
"fontStyle":"RegularBodyLarge"
}
}
]
}
},
{
"moleculeName":"listItem",
"topPadding":24,
"bottomPadding":0,
"backgroundColor":"coolGray1",
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"caretLink",
"title":"Check out the mobile coverage map",
"action":{
"actionType":"openPage",
"pageType":"coverage"
}
}
},
{
"moleculeName":"listItem",
"topPadding":48,
"bottomPadding":0,
"horizontalAlignment":"center",
"backgroundColor":"coolGray1",
"molecule":{
"moleculeName":"label",
"text":"The fastest home\ninternet.",
"textAlignment":"center",
"fontStyle":"BoldTitleXLarge"
}
},
{
"moleculeName":"listItem",
"topPadding":24,
"bottomPadding":0,
"backgroundColor":"coolGray1",
"hideArrow":true,
"molecule":{
"moleculeName":"stack",
"axis":"vertical",
"backgroundColor":"#EE0000",
"cornerRadius":8,
"useHorizontalMargins":true,
"useVerticalMargins":true,
"topPadding":16,
"bottomPadding":16,
"leftPadding":16,
"rightPadding":16,
"molecules":[
{
"moleculeName":"stackItem",
"spacing":0,
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"label",
"textAlignment":"center",
"text":"Get Verizon Home Internet and save.",
"fontStyle":"BoldTitleSmall",
"textColor":"white"
}
},
{
"moleculeName":"stackItem",
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"stack",
"axis":"vertical",
"molecules":[
{
"moleculeName":"stackItem",
"horizontalAlignment":"leading",
"molecule":{
"moleculeName":"label",
"textAlignment":"center",
"text":"Starting at",
"fontStyle":"BoldTitleSmall",
"textColor":"white"
}
},
{
"moleculeName":"stackItem",
"spacing":4,
"molecule":{
"moleculeName":"stack",
"axis":"horizontal",
"molecules":[
{
"moleculeName":"stackItem",
"verticalAlignment":"leading",
"spacing":0,
"molecule":{
"moleculeName":"label",
"text":"$",
"fontStyle":"BoldTitleXLarge",
"textColor":"white"
}
},
{
"moleculeName":"stackItem",
"verticalAlignment":"fill",
"spacing":0,
"molecule":{
"moleculeName":"label",
"text":"25",
"fontStyle":"BoldFeatureMedium",
"textColor":"white"
}
},
{
"moleculeName":"stackItem",
"verticalAlignment":"trailing",
"spacing":0,
"molecule":{
"moleculeName":"label",
"text":"/mo.",
"fontStyle":"BoldBodySmall",
"textColor":"white"
}
}
]
}
}
]
}
},
{
"moleculeName":"stackItem",
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"label",
"textAlignment":"center",
"text":"Switch to Verizon Home Internet starting at a low price, guaranteed. The network America relies on, at a price you can rely on.",
"fontStyle":"RegularBodySmall",
"textColor":"white"
}
},
{
"moleculeName":"stackItem",
"horizontalAlignment":"center",
"molecule":{
"moleculeName":"button",
"size":"small",
"style":"secondary",
"inverted":true,
"title":"Get started",
"action":{
"actionType":"openPage",
"pageType":"home"
}
}
}
]
}
}
]
},
"ModuleMap":{
"tabBar":{
"tabs":[
{
"title":"Discover",
"image":"tab_discover",
"tabBarIndex":0,
"action":{
"actionType":"openPage",
"pageType":"prospectWelcomeTrial",
"presentationStyle":"root"
}
},
{
"title":"Account",
"image":"tab_account",
"tabBarIndex":1,
"action":{
"actionType":"openPage",
"pageType":"account",
"presentationStyle":"root"
}
},
{
"title":"Shop",
"image":"tab_shop_3_0",
"tabBarIndex":2,
"action":{
"actionType":"openPage",
"pageType":"shop",
"requestURL":"https:\/\/mobile-exp-qa3.vzw.com\/mobile\/nsa\/nos\/gw\/launchapp\/unauthenticatedWebview",
"presentationStyle":"root"
}
},
{
"title":"Stores",
"image":"nav_stores_white",
"tabBarIndex":3,
"action":{
"actionType":"openPage",
"pageType":"rtlStoreJourney",
"presentationStyle":"root",
"extraParameters":{
"fromPage":"rtlStoreJourney",
"makeFavourite":"N"
}
}
}
]
},
"SearchField":{
"searchField":{
"moleculeName":"searchTextField",
"placeholder":"What are you looking for?",
"fieldKey":"searchInput"
},
"searchAction":{
"actionType":"openPage",
"pageType":"search"
},
"searchDoneAction":{
"actionType":"openPage",
"pageType":"searchDone"
}
},
"HabContent":{
"habSearch":{
"label":{
"moleculeName":"label",
"text":"How can we help?"
},
"image":{
"moleculeName":"image",
"image":"hab_search_black",
"width":17,
"height":17
},
"image_inverted":{
"moleculeName":"image",
"image":"hab_search_white",
"width":17,
"height":17
},
"action":{
"actionType":"openURL",
"browserUrl":"https://www.verizon.com/onesearch/search?source=MFNative",
"openInWebview":true,
"showNativeNavigation":true
}
},
"habAssistant":{
"label":{
"moleculeName":"label",
"text":"Chat with the Verizon Assistant"
},
"image":{
"moleculeName":"image",
"image":"hab_assistant_black",
"width":20,
"height":20
},
"image_inverted":{
"moleculeName":"image",
"image":"hab_assistant_white",
"width":20,
"height":20
},
"action":{
"actionType":"openPanel",
"panel":"right"
}
},
"habLiveChat":{
"label":{
"moleculeName":"label",
"text":"Chat with an agent"
},
"image":{
"moleculeName":"image",
"image":"hab_live_chat_black",
"imageFormat":"gif",
"width":20,
"height":20
},
"image_inverted":{
"moleculeName":"image",
"image":"hab_live_chat_white",
"imageFormat":"gif",
"width":20,
"height":20
},
"action":{
"actionType":"openPanel",
"panel":"right"
}
},
"habLiveChatNewMessages":{
"label":{
"moleculeName":"label",
"text":"Return to chat with an agent"
},
"image":{
"moleculeName":"image",
"image":"hab_live_chat_newmessage_black",
"imageFormat":"gif",
"width":20,
"height":20
},
"image_inverted":{
"moleculeName":"image",
"image":"hab_live_chat_newmessage_white",
"imageFormat":"gif",
"width":20,
"height":20
},
"action":{
"actionType":"openPanel",
"panel":"right"
}
}
},
"SavedCart":{
"ButtonMap":{
"PrimaryButton":{
"actionType":"openPage",
"pageType":"cart"
}
},
"itemCount":0,
"IS_SHARED_CART":true
},
"webParams":{
"mvaServerDomainUrl":"https://mobile-exp-qa3.vzw.com",
"lob":"vzp",
"isTabBarFlowAllowed":"true"
}
},
"PageMap":{
"shop":{
"pageType":"shop",
"template":"webView",
"browserUrl":"https:\/\/vzwqa3.verizonwireless.com\/sales\/next\/shop.html?isShopFlow=true&entrypoint=tabbar&isProspect=true",
"cache":true,
"tabBarIndex":1,
"navigationBar":{
"line":{
"moleculeName":"line",
"type":"none"
},
"moleculeName":"navigationBar",
"additionalLeftButtons":[
{
"accessibilityText":"Verizon logo, tap anytime to scroll to top of page",
"moleculeName":"navigationImageButton",
"image":"nav_vz_mark",
"imageRenderingMode":"alwaysOriginal",
"action":{
"analyticsData":{
"vzdl.page.linkName":"global black bar nav: vz icon"
},
"actionType":"scrollToTop"
}
}
],
"additionalRightButtons":[
{
"moleculeName":"navigationLabelButton",
"title":"Sign in",
"action":{
"hideCloseButton":false,
"appContext":"mobileFirstSS",
"analyticsData":{
"vzdl.page.id":"prospectTrailWelcome",
"vzdl.target.engagement.intent":"customer sign in",
"vzdl.page.displayChannel":"MVA",
"vzdl.page.linkName":"I'm a customer",
"vzdl.page.name":"prospectTrailWelcome"
},
"requestURL":"https:\/\/mobile-exp.vzw.com\/mobile\/nsa\/nos\/gw\/launchapp\/oauthSignIn?",
"extraParameters":{
"oAuthLaunchAppFlow":"Y"
},
"disableNativeAction":false,
"customUserAgent":"MY_VZW_APP;IOS;16.3.1;iPhone15,2;10.5.0;VZW-MFA-IOS",
"openInWebview":true,
"disableOfflineDevice":false,
"hideUrl":false,
"actionType":"openPage",
"pageType":"userSignIn",
"presentationStyle":"root",
"isSelected":false,
"openOauthWebView":false,
"hideWebNavigation":false,
"selected":false
}
}
],
"style":"dark"
}
},
"cart":{
"pageType":"cart",
"template":"webView",
"browserUrl":"https://www.verizon.com/sales/next/expresscheckout.html?pageName=cart&fromMVA=true&preConfigCart=true&isShopFlow=true&entrypoint=carticon",
"tabBarHidden":true,
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"deals":{
"pageType":"deals",
"template":"webView",
"browserUrl":"https://www.verizon.com/deals",
"tabBarHidden":true,
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"smartphones":{
"pageType":"smartphones",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/smartphones",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"plans":{
"pageType":"plans",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/plans",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"coverage":{
"pageType":"coverage",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/coverage-map",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"home":{
"pageType":"home",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/home",
"backgroundColor":"black",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"homeavailability":{
"pageType":"homeavailability",
"template":"webView",
"tabBarHidden":true,
"backgroundColor":"black",
"browserUrl":"https://www.verizon.com/home#checkAvailability",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"legal":{
"pageType":"legal",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/about/terms-conditions/overview",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"feedback":{
"pageType":"feedback",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/about/terms-conditions/overview",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"preowned":{
"pageType":"preowned",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/certified-pre-owned",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"tablets":{
"pageType":"tablets",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/tablets",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"watches":{
"pageType":"watches",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/connected-devices",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"hotspots":{
"pageType":"hotspots",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/internet-devices",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"accessories":{
"pageType":"accessories",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/products",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
},
"tradein":{
"pageType":"tradein",
"template":"webView",
"tabBarHidden":true,
"browserUrl":"https://www.verizon.com/trade-in",
"navigationBar":{
"moleculeName":"navigationBar",
"style":"light"
}
}
}
}

View File

@ -1,557 +0,0 @@
{
"ResponseInfo": {
"locale": "EN",
"type": "Success"
},
"Page": {
"pageType": "shopLanding",
"template": "list",
"presentationStyle": "root",
"hab": {
"configuration": "single",
"inverted": true
},
"tabBarIndex": 2,
"navigationBar": {
"style" : "dark",
"moleculeName" : "navigationBar",
"additionalLeftButtons" : [
{
"accessibilityText" : "Verizon logo button, tap anytime to scroll to top of page",
"moleculeName" : "navigationImageButton",
"image" : "nav_vz_mark",
"imageRenderingMode" : "alwaysOriginal",
"action" : {
"actionType" : "scrollToTop"
}
}
],
"additionalRightButtons" : [
{
"accessibilityText" : "Stores",
"moleculeName" : "navigationImageButton",
"image" : "nav_stores_white",
"action" : {
"analyticsData" : {
"vzdl.page.linkName" : "global tab nav:stores"
},
"title" : "Stores",
"actionType" : "openPage",
"pageType" : "rtlStoreJourney"
}
}
]
},
"header": {
"moleculeName" : "header",
"backgroundColor": "white",
"bottomPadding": 0,
"topPadding": 16,
"molecule": {
"moleculeName" : "carousel",
"accessibilityText":"carousel",
"pagingMolecule": {
"moleculeName":"barsCarouselIndicator",
"position": -20
},
"height" : 265,
"spacing": 16,
"itemWidthPercent": 70,
"molecules" : [{
"moleculeName" : "carouselItem",
"backgroundColor": "black",
"useHorizontalMargins": false,
"useVerticalMargins": false,
"cornerRadius": 8,
"molecule" : {
"moleculeName": "image",
"image": "https://mobile.vzw.com/hybridClient/is/image/VerizonWireless/vzw-191302-iconic-2022-launch-vbm-shop-tile-live-9-16-22-r2?hei=400&bgc=000000",
"imageFormat": "jpg",
"allowServerParameters": true
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/smartphones/apple/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName" : "carouselItem",
"backgroundColor": "coolGray1",
"topPadding": 12,
"bottomPadding": 12,
"cornerRadius": 8,
"molecule" : {
"moleculeName" : "stack",
"molecules": [{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "label",
"text": "Your next phone could be on us.",
"fontStyle": "RegularTitleLarge"
}
},{
"moleculeName": "stackItem",
"molecule": {
"moleculeName" : "stack",
"axis": "horizontal",
"molecules": [{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "label",
"text": "Includes online exclusive deals. New smartphone line required.",
"fontStyle": "RegularMicro"
}
},{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "image",
"image": "https://ss71.vzw.com/is/image/VerizonWireless/samsung-galaxy-a03s-black-sm-a037?bgc=f6f6f6&fit=fit,1",
"height": 128,
"imageFormat": "jpg",
"allowServerParameters": true
}
}]
}
},{
"moleculeName": "stackItem",
"spacing": 0,
"molecule": {
"moleculeName": "caretLink",
"title": "Shop",
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/shop/online/free-cell-phones/",
"openInWebview": true,
"showNativeNavigation": true
}
}
}]
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/shop/online/free-cell-phones/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName" : "carouselItem",
"backgroundColor": "coolGray1",
"topPadding": 12,
"bottomPadding": 12,
"cornerRadius": 8,
"molecule" : {
"moleculeName" : "stack",
"molecules": [{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "label",
"text": "Great deals on our best tablets.",
"fontStyle": "RegularTitleLarge"
}
},{
"moleculeName": "stackItem",
"molecule": {
"moleculeName" : "stack",
"axis": "horizontal",
"molecules": [{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "label",
"text": "Find incredible savings on all the latest models.",
"fontStyle": "RegularMicro"
}
},{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "image",
"image": "https://ss72.vzw.com/is/image/VerizonWireless/app-189419-sidxxx-generic-tablet-shop-tile-8-19?bgColor=f6f6f6&fit=fit,1",
"height": 128,
"imageFormat": "jpg",
"allowServerParameters": true
}
}]
}
},{
"moleculeName": "stackItem",
"spacing": 0,
"molecule": {
"moleculeName": "caretLink",
"title": "Shop",
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/tablets/",
"openInWebview": true,
"showNativeNavigation": true
}
}
}]
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/tablets/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName" : "carouselItem",
"backgroundColor": "coolGray1",
"topPadding": 12,
"bottomPadding": 12,
"cornerRadius": 8,
"molecule" : {
"moleculeName" : "stack",
"molecules": [{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "label",
"text": "Stay connected on the go.",
"fontStyle": "RegularTitleLarge"
}
},{
"moleculeName": "stackItem",
"molecule": {
"moleculeName" : "stack",
"axis": "horizontal",
"molecules": [{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "label",
"text": "Save on our latest smartwatch.",
"fontStyle": "RegularMicro"
}
},{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "image",
"image": "https://ss71.vzw.com/is/image/VerizonWireless/app-189420-sidxxx-generic-smartwatch-shop-tile-8-19?bgc=f6f6f6&fit=fit,1",
"height": 128,
"imageFormat": "jpg",
"allowServerParameters": true
}
}]
}
},{
"moleculeName": "stackItem",
"spacing": 0,
"molecule": {
"moleculeName": "caretLink",
"title": "Shop",
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/connected-smartwatches/",
"openInWebview": true,
"showNativeNavigation": true
}
}
}]
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/connected-smartwatches/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName" : "carouselItem",
"backgroundColor": "coolGray1",
"topPadding": 12,
"bottomPadding": 12,
"cornerRadius": 8,
"molecule" : {
"moleculeName" : "stack",
"molecules": [{
"moleculeName": "stackItem",
"molecule": {
"moleculeName": "label",
"text": "Bring your device. Get our best deals.",
"fontStyle": "RegularTitleLarge"
}
},{
"moleculeName": "stackItem",
"molecule": {
"moleculeName" : "stack",
"axis": "horizontal",
"molecules": [{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "label",
"text": "Activate your favorite device in minutes.",
"fontStyle": "RegularMicro"
}
},{
"moleculeName": "stackItem",
"verticalAlignment": "center",
"molecule": {
"moleculeName": "image",
"image": "https://ss71.vzw.com/is/image/VerizonWireless/app-189422-sidxxx-generic-boyd-shop-tile-8-19?bgc=f6f6f6&fit=fit,1",
"height": 128,
"imageFormat": "jpg",
"allowServerParameters": true
}
}]
}
},{
"moleculeName": "stackItem",
"spacing": 0,
"molecule": {
"moleculeName": "caretLink",
"title": "Shop",
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/sales/next/shop.html?intcmp=mva-vzw-tabbar",
"openInWebview": true,
"showNativeNavigation": true
}
}
}]
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/sales/next/shop.html?intcmp=mva-vzw-tabbar",
"openInWebview": true,
"showNativeNavigation": true
}
}]
}
},
"molecules": [{
"moleculeName":"list1CTxtDiv1",
"headline": {
"moleculeName": "label",
"text": "Mobile"
},
"line": {
"moleculeName": "line",
"type": "none"
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Deals"
}
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/deals/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Smartphones"
}
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "collection",
"browserUrl": "https://www.verizon.com/smartphones/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Certified Pre-Owned"
}
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/sales/next/shop.html?intcmp=mva-vzw-tabbar",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Tablets"
}
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/tablets/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Watches"
}
},
"action": {
"actionType": "openURL",
"pageType": "gridwall",
"template": "webView",
"browserUrl": "https://www.verizon.com/connected-smartwatches/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Mobile accessories"
}
},
"action": {
"actionType": "openURL",
"pageType": "accessories",
"template": "webView",
"browserUrl": "https://www.verizon.com/sales/next/shop/accessories.html",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Bring your own devices"
}
},
"action": {
"actionType": "openURL",
"pageType": "accessories",
"template": "webView",
"browserUrl": "https://www.verizon.com/sales/digital/byod.html",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Trade in a device"
}
},
"action": {
"actionType": "openURL",
"pageType": "byod",
"template": "webView",
"browserUrl": "https://www.verizon.com/sales/digital/tradein.html#/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "My Offers"
}
},
"action": {
"actionType": "openURL",
"pageType": "offers",
"template": "webView",
"browserUrl": "https://myvpostpay.verizon.com/ui/hub/ao/myoffers?fromMVA=true",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CTxtDiv1",
"headline": {
"moleculeName": "label",
"text": "Home"
},
"line": {
"moleculeName": "line",
"type": "none"
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Home Internets"
}
},
"action": {
"actionType": "openURL",
"pageType": "offers",
"template": "webView",
"browserUrl": "https://www.verizon.com/vfw/auth/fiveGLandingPage?fromApp=true",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Smart home accessories"
}
},
"action": {
"actionType": "openURL",
"pageType": "offers",
"template": "webView",
"browserUrl": "https://www.verizon.com/products/smart-home/",
"openInWebview": true,
"showNativeNavigation": true
}
},{
"moleculeName":"list1CFWBdy",
"headlineBody": {
"headline": {
"moleculeName": "label",
"text": "Home phone"
}
},
"action": {
"actionType": "openURL",
"pageType": "offers",
"template": "webView",
"browserUrl": "https://www.verizon.com/home-office-solutions/",
"openInWebview": true,
"showNativeNavigation": true
}
}]
}
}

View File

@ -187,7 +187,7 @@
"pageType":"manageSafeWIFI" "pageType":"manageSafeWIFI"
}, },
"style":"secondary", "style":"secondary",
"size":"small", "size":"tiny",
"validationRequired":false "validationRequired":false
} }
}] }]
@ -241,7 +241,7 @@
"pageType":"manageSafeWIFI" "pageType":"manageSafeWIFI"
}, },
"style":"secondary", "style":"secondary",
"size":"small", "size":"tiny",
"validationRequired":false "validationRequired":false
} }
}] }]
@ -290,7 +290,7 @@
"pageType":"manageSafeWIFI" "pageType":"manageSafeWIFI"
}, },
"style":"secondary", "style":"secondary",
"size":"small", "size":"tiny",
"validationRequired":false "validationRequired":false
} }
}] }]

Some files were not shown because too many files have changed in this diff Show More