Compare commits
No commits in common. "develop" and "feature/ONEAPP-2811-Tilet" have entirely different histories.
develop
...
feature/ON
20
.gitignore
vendored
20
.gitignore
vendored
@ -10,17 +10,20 @@ mobilefirst_ios
|
||||
mvm_core
|
||||
mfprepayshop_ios
|
||||
mvm_core_ui
|
||||
chatbot_ios
|
||||
mvmreactnative
|
||||
mvm_5g_ios
|
||||
mvm_dhc_ios
|
||||
vds_ios
|
||||
|
||||
# Exclude all frameworks
|
||||
SharedFrameworks/*
|
||||
|
||||
# Exception to the rule above (Keeps the folder around)
|
||||
!SharedFrameworks/.gitkeep
|
||||
# frameworks
|
||||
contentTransferFramework.framework
|
||||
ActivationFramework.framework
|
||||
RemoteView.framework
|
||||
RemoteViewCore.framework
|
||||
RemoteViewReplayKit.framework
|
||||
MVMAnimationFramework.framework
|
||||
VZAnalytics.framework
|
||||
VZWAuthentication.framework
|
||||
CardinalMobile.framework
|
||||
MVDRetailFramework.framework
|
||||
|
||||
VDSTypographyTokens.framework
|
||||
VDSFormControlsTokens.framework
|
||||
@ -39,6 +42,7 @@ __MACOSX
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
SharedFrameworks/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
|
||||
@ -32,6 +32,13 @@
|
||||
/* End PBXAggregateTarget 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 */; };
|
||||
D2B1E3F322F4A68F0065F95C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */; };
|
||||
D2B1E3F522F4A68F0065F95C /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3F422F4A68F0065F95C /* MasterViewController.swift */; };
|
||||
@ -40,7 +47,39 @@
|
||||
D2B1E3FC22F4A6930065F95C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E3FB22F4A6930065F95C /* Assets.xcassets */; };
|
||||
D2B1E3FF22F4A6930065F95C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D2B1E3FD22F4A6930065F95C /* LaunchScreen.storyboard */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
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, ); }; };
|
||||
EA3361FB2891D54A0071C351 /* VDSTypographyTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */; };
|
||||
@ -49,6 +88,7 @@
|
||||
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 */; };
|
||||
EA5B69712866BC1000B17D2E /* MVMCoreUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA5B696D2866BC1000B17D2E /* MVMCoreUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
EA797B2C2902D4BB00DBAFE6 /* TestToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA797B2B2902D4BB00DBAFE6 /* TestToggle.swift */; };
|
||||
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, ); }; };
|
||||
EACA5E5E2853DBC900CBA65B /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EACA5E5D2853DBC900CBA65B /* VDSColorTokens.xcframework */; };
|
||||
@ -75,6 +115,13 @@
|
||||
/* End PBXCopyFilesBuildPhase 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>"; };
|
||||
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>"; };
|
||||
@ -88,7 +135,39 @@
|
||||
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; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
EA2ED27E285BD00D00781478 /* MVMCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MVMCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -97,6 +176,7 @@
|
||||
EA3361FA2891D54A0071C351 /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; };
|
||||
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; };
|
||||
EA797B2B2902D4BB00DBAFE6 /* TestToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestToggle.swift; sourceTree = "<group>"; };
|
||||
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; };
|
||||
EAA658142875FA5E00484A7D /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
|
||||
@ -124,7 +204,9 @@
|
||||
D288D69B26CAE26900A5C365 /* MF */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2431DEA25E93A4F001C7AAC /* buttimag.swift */,
|
||||
D29C557725BF1F340082E7D6 /* JSONCreatorActionHandler.swift */,
|
||||
D2FC4FA825897ACB00061EA4 /* Order Tracker */,
|
||||
);
|
||||
path = MF;
|
||||
sourceTree = "<group>";
|
||||
@ -149,6 +231,7 @@
|
||||
D2B1E3F122F4A68F0065F95C /* JSONCreator */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA09CD9A282C3F6B00A7835F /* 5G */,
|
||||
D288D69B26CAE26900A5C365 /* MF */,
|
||||
D2B1E40922F4C9F00065F95C /* JSON */,
|
||||
D2B1E3F222F4A68F0065F95C /* AppDelegate.swift */,
|
||||
@ -158,6 +241,7 @@
|
||||
D2B1E3FB22F4A6930065F95C /* Assets.xcassets */,
|
||||
D2B1E3FD22F4A6930065F95C /* LaunchScreen.storyboard */,
|
||||
D2B1E40022F4A6930065F95C /* Info.plist */,
|
||||
EA797B2B2902D4BB00DBAFE6 /* TestToggle.swift */,
|
||||
);
|
||||
path = JSONCreator;
|
||||
sourceTree = "<group>";
|
||||
@ -185,6 +269,106 @@
|
||||
name = Frameworks;
|
||||
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 */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -305,10 +489,50 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
EA09CDFC282C430400A7835F /* CharacteristicModel.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 */,
|
||||
EA09CE05282C45C200A7835F /* BluetoothPairBehavior.swift in Sources */,
|
||||
EA09CDFA282C430400A7835F /* BluetoothConfigModel.swift in Sources */,
|
||||
D27564CA25939E91003CA713 /* LinksModel.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 */,
|
||||
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 */,
|
||||
EA797B2C2902D4BB00DBAFE6 /* TestToggle.swift in Sources */,
|
||||
EA09CDD6282C40CC00A7835F /* GMFGConstant.swift in Sources */,
|
||||
D27564C925939E91003CA713 /* Links.swift in Sources */,
|
||||
EA09CDE6282C416C00A7835F /* BluetoothDebuggableProtocol.swift in Sources */,
|
||||
EA09CDD2282C40CC00A7835F /* GMFGBluetoothPair.swift in Sources */,
|
||||
EA09CDE9282C416C00A7835F /* BluetoothDebuggerView.swift in Sources */,
|
||||
D2FC4FAE25897ACB00061EA4 /* OrderTrackerModel.swift in Sources */,
|
||||
D21B3A27259B93ED001483DC /* SelfSizingCollectionView.swift in Sources */,
|
||||
EA09CDD9282C40CC00A7835F /* GMFG5GCBandSignalHandler.swift in Sources */,
|
||||
EA09CDF8282C430400A7835F /* BluetoothPairingProtocol.swift in Sources */,
|
||||
D2B1E3F322F4A68F0065F95C /* AppDelegate.swift in Sources */,
|
||||
EA09CDDA282C40CC00A7835F /* GMFGOperationHandler.swift in Sources */,
|
||||
EA09CDE7282C416C00A7835F /* MulticastDelegate.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;
|
||||
};
|
||||
@ -455,7 +679,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 59V5935DHZ;
|
||||
DEVELOPMENT_TEAM = FCMA4QKS77;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../SharedFrameworks",
|
||||
@ -479,7 +703,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 59V5935DHZ;
|
||||
DEVELOPMENT_TEAM = FCMA4QKS77;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../SharedFrameworks",
|
||||
|
||||
@ -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>
|
||||
@ -0,0 +1,9 @@
|
||||
//
|
||||
// BluetoothPairBehavior.swift
|
||||
// JSONCreator
|
||||
//
|
||||
// Created by Matt Bruce on 5/11/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
327
JSONCreator_iOS/JSONCreator/5G/Debugger/BluetoothDebugger.swift
Normal file
327
JSONCreator_iOS/JSONCreator/5G/Debugger/BluetoothDebugger.swift
Normal 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: "")
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
@ -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) }
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
217
JSONCreator_iOS/JSONCreator/5G/MFFGHSAnalyticsProtocol.swift
Normal file
217
JSONCreator_iOS/JSONCreator/5G/MFFGHSAnalyticsProtocol.swift
Normal 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
|
||||
}
|
||||
}
|
||||
547
JSONCreator_iOS/JSONCreator/5G/MFFGHSBluetoothPair.swift
Normal file
547
JSONCreator_iOS/JSONCreator/5G/MFFGHSBluetoothPair.swift
Normal 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 } ?? []
|
||||
}
|
||||
}
|
||||
17
JSONCreator_iOS/JSONCreator/5G/MFFGHSUtility.swift
Normal file
17
JSONCreator_iOS/JSONCreator/5G/MFFGHSUtility.swift
Normal 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
|
||||
}
|
||||
}
|
||||
103
JSONCreator_iOS/JSONCreator/5G/Models/BluetoothConfigModel.swift
Normal file
103
JSONCreator_iOS/JSONCreator/5G/Models/BluetoothConfigModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
34
JSONCreator_iOS/JSONCreator/5G/Models/PeripheralModel.swift
Normal file
34
JSONCreator_iOS/JSONCreator/5G/Models/PeripheralModel.swift
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
44
JSONCreator_iOS/JSONCreator/5G/Models/ServiceModel.swift
Normal file
44
JSONCreator_iOS/JSONCreator/5G/Models/ServiceModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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) }
|
||||
}
|
||||
}
|
||||
@ -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) }
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
509
JSONCreator_iOS/JSONCreator/5G/Utility/GMFGBluetoothPair.swift
Normal file
509
JSONCreator_iOS/JSONCreator/5G/Utility/GMFGBluetoothPair.swift
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
87
JSONCreator_iOS/JSONCreator/5G/Utility/GMFGConstant.swift
Normal file
87
JSONCreator_iOS/JSONCreator/5G/Utility/GMFGConstant.swift
Normal 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"
|
||||
}
|
||||
@ -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] }
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
@ -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 }
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,6 @@ import VDS
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var splitViewController: UISplitViewController?
|
||||
var mvcNav: UINavigationController?
|
||||
var dvcNav: UINavigationController?
|
||||
var mvc: UIViewController?
|
||||
@ -23,26 +22,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
// Setup our core object with the default implementation
|
||||
CoreUIObject.sharedInstance()?.defaultInitialSetup()
|
||||
CoreUIObject.sharedInstance()?.globalTopAlertDelegate = self
|
||||
return true
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
|
||||
// Override point for customization after application launch.
|
||||
splitViewController = window!.rootViewController as? UISplitViewController
|
||||
NavigationHandler.shared().viewControllerToPresentOn = splitViewController
|
||||
mvcNav = splitViewController?.viewControllers[0] as? UINavigationController
|
||||
let splitViewController = window!.rootViewController as! UISplitViewController
|
||||
mvcNav = splitViewController.viewControllers[0] as? UINavigationController
|
||||
mvcNav?.delegate = self
|
||||
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?.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
|
||||
dvc?.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
|
||||
dvc?.navigationItem.leftItemsSupplementBackButton = true
|
||||
splitViewController?.delegate = self
|
||||
splitViewController?.preferredDisplayMode = .allVisible
|
||||
splitViewController.delegate = self
|
||||
splitViewController.preferredDisplayMode = .allVisible
|
||||
|
||||
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
|
||||
if let strongSelf = self, let svc = notification.object as? UISplitViewController {
|
||||
@ -54,6 +53,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||
}
|
||||
}
|
||||
}
|
||||
self.register()
|
||||
return true
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||
|
||||
// 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.topViewController as? DetailViewController else { return false }
|
||||
return true
|
||||
@ -106,3 +106,22 @@ 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: TestToggle.self, for: TestToggleModel.self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,9 @@ class DetailViewController: UIViewController {
|
||||
return
|
||||
}
|
||||
|
||||
modalPresentationStyle = .fullScreen
|
||||
modalPresentationStyle = .formSheet
|
||||
MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = self
|
||||
|
||||
view.addSubview(textView)
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
textView.font = UIFont.systemFont(ofSize: 40)
|
||||
@ -68,45 +70,40 @@ class DetailViewController: UIViewController {
|
||||
@objc func play() {
|
||||
do {
|
||||
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 error = NSError(domain: ErrorDomainNative, code: ErrorCode.parsingJSON.rawValue, userInfo: [NSLocalizedDescriptionKey: "Needs a Page to show."])
|
||||
showError(error)
|
||||
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)
|
||||
let page = jsonObject.optionalDictionaryForKey(KeyPage)
|
||||
let pageType = page?.optionalStringForKey(KeyPageType)
|
||||
let template = page?.optionalStringForKey("template")
|
||||
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),
|
||||
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) {
|
||||
|
||||
Task(priority: .userInitiated) { @MainActor in
|
||||
let gr = UILongPressGestureRecognizer(target: self, action: #selector(DetailViewController.close))
|
||||
viewController.view.addGestureRecognizer(gr)
|
||||
|
||||
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 split = MVMCoreUISplitViewController.setup(asMainController: nil, rightPanel: nil)!
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
|
||||
viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.close))
|
||||
}
|
||||
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 {
|
||||
let error = NSError(domain: ErrorDomainNative, code: ErrorCode.initViewController.rawValue, userInfo: [NSLocalizedDescriptionKey: errorObject.messageToLog ?? errorObject.messageToDisplay!])
|
||||
showError(error)
|
||||
@ -118,9 +115,7 @@ class DetailViewController: UIViewController {
|
||||
}
|
||||
|
||||
@objc func close() {
|
||||
guard let splitViewController = (UIApplication.shared.delegate as? AppDelegate)?.splitViewController else { return }
|
||||
NavigationHandler.shared().viewControllerToPresentOn = splitViewController
|
||||
UIApplication.shared.delegate?.window??.rootViewController = splitViewController
|
||||
MVMCoreNavigationHandler.shared()?.dismissTopViewController(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
"moleculeName":"headerH1",
|
||||
"headlineBody": {
|
||||
"headline": {
|
||||
"moleculeName": "label",
|
||||
"text": "headline"
|
||||
},
|
||||
"body":{
|
||||
"moleculeName": "label",
|
||||
"text": "body"
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,23 @@
|
||||
"moleculeName":"headerH1Landing",
|
||||
"headline":{
|
||||
"moleculeName": "label",
|
||||
"text":"headline"
|
||||
"text":"x"
|
||||
},
|
||||
"headline2":{
|
||||
"moleculeName": "label",
|
||||
"text":"headline2"
|
||||
"text":"x"
|
||||
},
|
||||
"subHeadline":{
|
||||
"moleculeName": "label",
|
||||
"text":"subHeadline"
|
||||
"text":"y"
|
||||
},
|
||||
"body":{
|
||||
"moleculeName": "label",
|
||||
"text":"body"
|
||||
"text":"y"
|
||||
},
|
||||
"link":{
|
||||
"moleculeName": "link",
|
||||
"title":"link",
|
||||
"title":"y",
|
||||
"action": {
|
||||
"actionType": "back"
|
||||
}
|
||||
@ -26,16 +26,17 @@
|
||||
"moleculeName":"twoButtonView",
|
||||
"primaryButton":{
|
||||
"moleculeName": "button",
|
||||
"title":"primary",
|
||||
"title":"x",
|
||||
"action": {
|
||||
"actionType": "noop"
|
||||
"actionType": "openPage",
|
||||
"pageType": "verifyZip"
|
||||
}
|
||||
},
|
||||
"secondaryButton":{
|
||||
"moleculeName": "button",
|
||||
"title":"secondary",
|
||||
"title":"x",
|
||||
"action": {
|
||||
"actionType": "noop"
|
||||
"actionType": "back"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
"moleculeName": "headlineBody",
|
||||
"headline":{
|
||||
"moleculeName": "label",
|
||||
"text":"headline"
|
||||
"text":"x"
|
||||
},
|
||||
"body":{
|
||||
"moleculeName": "label",
|
||||
"text":"body"
|
||||
"text":"y"
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -1,29 +1,29 @@
|
||||
"moleculeName":"headerH2TwoRows",
|
||||
"headline":{
|
||||
"moleculeName": "label",
|
||||
"text":"headline"
|
||||
"text":"x"
|
||||
},
|
||||
"body":{
|
||||
"moleculeName": "label",
|
||||
"text":"body"
|
||||
"text":"y"
|
||||
},
|
||||
"subBody":{
|
||||
"moleculeName": "label",
|
||||
"text":"subBody"
|
||||
"text":"y"
|
||||
},
|
||||
"body2":{
|
||||
"moleculeName": "label",
|
||||
"text":"body2"
|
||||
"text":"y"
|
||||
},
|
||||
"subBody2":{
|
||||
"moleculeName": "label",
|
||||
"text":"subBody2"
|
||||
"text":"y"
|
||||
},
|
||||
"body3":{
|
||||
"moleculeName": "label",
|
||||
"text":"body3"
|
||||
"text":"y"
|
||||
},
|
||||
"subBody3":{
|
||||
"moleculeName": "label",
|
||||
"text":"subBody3"
|
||||
"text":"y"
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -6,19 +6,19 @@
|
||||
"moleculeName" : "eyebrowHeadlineBodyLink",
|
||||
"eyebrow" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "eyebrow"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"link" : {
|
||||
"moleculeName" : "link",
|
||||
"title" : "link",
|
||||
"title" : "Hello",
|
||||
"action": {
|
||||
"actionType":"back"
|
||||
}
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
"moleculeName" : "headlineBody",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
"moleculeName": "listLVImg",
|
||||
"leftLabel": {
|
||||
"moleculeName": "label",
|
||||
"text": "left"
|
||||
"text": "Lorem ipsum"
|
||||
},
|
||||
"rightLabel": {
|
||||
"moleculeName": "label",
|
||||
"text": "right"
|
||||
"text": "Label"
|
||||
},
|
||||
"image": {
|
||||
"moleculeName": "image",
|
||||
"image": "alert_standard"
|
||||
"image": "imageName_PayPal_logo"
|
||||
},
|
||||
"action" : {
|
||||
"disabled" : false,
|
||||
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
"number": 1,
|
||||
"moleculeName" : "listLVNLBdy",
|
||||
"headlineBody" : {
|
||||
"moleculeName" : "headlineBody",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
"radioButton" : {
|
||||
"moleculeName" : "radioButton"
|
||||
},
|
||||
"moleculeName" : "listLVRBBdy",
|
||||
"headlineBody" : {
|
||||
"moleculeName" : "headlineBody",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -5,21 +5,18 @@
|
||||
},
|
||||
"leftHeadline": {
|
||||
"moleculeName": "label",
|
||||
"text": "headline"
|
||||
"text": "Lorem ipsum dolor sit."
|
||||
},
|
||||
"leftBody": {
|
||||
"moleculeName": "label",
|
||||
"text": "body"
|
||||
"text": "Lorem ipsum dolor sit."
|
||||
},
|
||||
"leftSubBody": {
|
||||
"moleculeName": "label",
|
||||
"text": "subBody"
|
||||
"text": "Lorem ipsum dolor sit."
|
||||
},
|
||||
"rightLabel": {
|
||||
"moleculeName": "label",
|
||||
"text": "right"
|
||||
},
|
||||
"action": {
|
||||
"actionType": "noop"
|
||||
}
|
||||
"text": "Label"
|
||||
}
|
||||
|
||||
|
||||
@ -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"
|
||||
}
|
||||
@ -2,13 +2,13 @@
|
||||
"headlineBody" : {
|
||||
"headline": {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"body": {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello"
|
||||
}
|
||||
},
|
||||
"action": {
|
||||
"actionType": "noop"
|
||||
"actionType": "back"
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
"moleculeName" : "listPrgBarThin",
|
||||
"leftBody" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "x alkdfjaldf kjasdlkfj salkdfj aslkfdj lksafdj aslkdfj slkfd jsalk jasdlk jsadl kjakslfj "
|
||||
},
|
||||
"action" : {
|
||||
"actionType" : "back"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightBar" : {
|
||||
"moleculeName" : "line",
|
||||
@ -21,5 +21,5 @@
|
||||
},
|
||||
"leftHeadline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "alkjf dsalkjf kjadfl kja"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "heeeeyy"
|
||||
},
|
||||
"moleculeName" : "listRVLine",
|
||||
"bar" : {
|
||||
@ -9,7 +9,7 @@
|
||||
},
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"action": {
|
||||
"actionType": "back"
|
||||
|
||||
@ -4,5 +4,5 @@
|
||||
},
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
"text" : "Hello Ryan!!!"
|
||||
}
|
||||
|
||||
@ -2,19 +2,19 @@
|
||||
"eyebrowHeadlineBodyLink": {
|
||||
"eyebrow" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "eyebrow"
|
||||
"text" : "Hello Ryan!!!"
|
||||
},
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "Hello Ryan!!!"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello Ryan!!!"
|
||||
},
|
||||
"link" : {
|
||||
"moleculeName" : "link",
|
||||
"title" : "link",
|
||||
"title" : "Hello",
|
||||
"action": {
|
||||
"actionType":"back"
|
||||
}
|
||||
@ -22,7 +22,7 @@
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "Hello Ryan!!!"
|
||||
},
|
||||
"arrow": {
|
||||
"moleculeName": "arrow"
|
||||
|
||||
@ -3,16 +3,16 @@
|
||||
"moleculeName":"headlineBody",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "Hello Ryan!!!"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello Ryan!!!"
|
||||
}
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "Hello Ryan!!!"
|
||||
},
|
||||
"arrow": {
|
||||
"moleculeName": "arrow"
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "heeeeyy"
|
||||
},
|
||||
"moleculeName" : "listRVWheel",
|
||||
"wheel" : {
|
||||
@ -8,7 +8,7 @@
|
||||
},
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"action": {
|
||||
"actionType": "back"
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
"moleculeName" : "list3CBillChg",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"centerLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "center"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
"moleculeName" : "list3CBillHst",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"centerLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "center"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -1,46 +1,46 @@
|
||||
"moleculeName" : "list2CCmpr1",
|
||||
"leftHeadline1" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline1"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"leftHeadline2" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline2"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"leftHeadline3" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline3"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"leftBody" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"leftLink" : {
|
||||
"moleculeName" : "label",
|
||||
"title" : "link",
|
||||
"title" : "Hello",
|
||||
"action": {
|
||||
"actionType": "back"
|
||||
}
|
||||
},
|
||||
"rightHeadline1" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline1"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightHeadline2" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline2"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightHeadline3" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline3"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightBody" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightLink" : {
|
||||
"moleculeName" : "label",
|
||||
"title" : "link",
|
||||
"title" : "Hello",
|
||||
"action": {
|
||||
"actionType": "back"
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
"moleculeName" : "list2CDrpDrp1",
|
||||
"leftDropDown" : {
|
||||
"moleculeName": "dropDown",
|
||||
"options": ["Option1","Option2","Option3"]
|
||||
},
|
||||
"rightDropDown" : {
|
||||
"moleculeName": "dropDown",
|
||||
"options": ["Option1","Option2","Option3"]
|
||||
}
|
||||
@ -1,17 +1,17 @@
|
||||
"moleculeName" : "list2CTxtPrc1",
|
||||
"leftHeadline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"leftBody" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightSubLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "rightSub"
|
||||
"text" : "Hello"
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
"moleculeName" : "list2CTxtPrc2",
|
||||
"moleculeName" : "list2CTxtPrc1",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
"text" : "Hello"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
"text" : "Hello"
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}]
|
||||
@ -1,13 +0,0 @@
|
||||
"moleculeName" : "planNamesLockup",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
},
|
||||
"subHeadline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "subHeadline"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
"moleculeName" : "list1CTxtDiv1",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
"moleculeName" : "list1CTxtDiv2",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
"moleculeName" : "list1CTxtDiv3",
|
||||
"headline" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "headline"
|
||||
"text" : "8.0 GB"
|
||||
},
|
||||
"body" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "body"
|
||||
"text" : "Verizon L data"
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
"moleculeName" : "list3CBillChgDiv",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"centerLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
"moleculeName" : "list3CBillHisDiv",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"centerLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
"moleculeName" : "list3CSpdTstDiv",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"centerLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
"moleculeName" : "list2CSbscDiv",
|
||||
"leftLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "left"
|
||||
},
|
||||
"rightLabel" : {
|
||||
"moleculeName" : "label",
|
||||
"text" : "right"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,7 +86,7 @@
|
||||
"moleculeName": "button",
|
||||
"title": "Learn more",
|
||||
"style": "secondary",
|
||||
"size": "small",
|
||||
"size": "tiny",
|
||||
"action": {
|
||||
"actionType": "openPage",
|
||||
"pageType": "x"
|
||||
@ -147,7 +147,7 @@
|
||||
"moleculeName": "button",
|
||||
"title": "Learn more",
|
||||
"style": "secondary",
|
||||
"size": "small",
|
||||
"size": "tiny",
|
||||
"action": {
|
||||
"actionType": "openPage",
|
||||
"pageType": "x"
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
@ -187,7 +187,7 @@
|
||||
"pageType":"manageSafeWIFI"
|
||||
},
|
||||
"style":"secondary",
|
||||
"size":"small",
|
||||
"size":"tiny",
|
||||
"validationRequired":false
|
||||
}
|
||||
}]
|
||||
@ -241,7 +241,7 @@
|
||||
"pageType":"manageSafeWIFI"
|
||||
},
|
||||
"style":"secondary",
|
||||
"size":"small",
|
||||
"size":"tiny",
|
||||
"validationRequired":false
|
||||
}
|
||||
}]
|
||||
@ -290,7 +290,7 @@
|
||||
"pageType":"manageSafeWIFI"
|
||||
},
|
||||
"style":"secondary",
|
||||
"size":"small",
|
||||
"size":"tiny",
|
||||
"validationRequired":false
|
||||
}
|
||||
}]
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
{
|
||||
"ResponseInfo" : {
|
||||
"code" : "00000",
|
||||
"type" : "Success"
|
||||
},
|
||||
"TopNotification": {
|
||||
"type": "testing",
|
||||
"molecule": {
|
||||
"moleculeName": "notification",
|
||||
"style": "warning",
|
||||
"headline": {
|
||||
"moleculeName": "label",
|
||||
"text": "headline"
|
||||
},
|
||||
"body": {
|
||||
"moleculeName": "label",
|
||||
"text": "body"
|
||||
},
|
||||
"button": {
|
||||
"moleculeName": "button",
|
||||
"title": "button",
|
||||
"action": {
|
||||
"actionType": "noop"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Page": {
|
||||
"pageType":"x",
|
||||
"template":"stack",
|
||||
"header": {
|
||||
"moleculeName": "headerH2",
|
||||
"headlineBody": {
|
||||
"moleculeName": "headlineBody",
|
||||
"headline":{
|
||||
"moleculeName": "label",
|
||||
"text": "Top Notification Testing!"
|
||||
}
|
||||
}
|
||||
},
|
||||
"stack": {
|
||||
"moleculeName": "stack",
|
||||
"molecules": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,42 +9,28 @@
|
||||
import Foundation
|
||||
import MVMCoreUI
|
||||
|
||||
public protocol MVMCoreActionScrollProtocol: MVMCoreActionDelegateProtocol {
|
||||
|
||||
@MainActor
|
||||
func handleScrollTopAction(action: ActionModelProtocol, additionalData: [AnyHashable: Any]?)
|
||||
}
|
||||
|
||||
public struct ActionScrollToTopModel: ActionModelProtocol {
|
||||
@objcMembers public class ActionPrintModel: ActionModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "scrollToTop"
|
||||
public var actionType: String = ActionScrollToTopModel.identifier
|
||||
public static var identifier: String = "print"
|
||||
public var actionType: String = ActionPrintModel.identifier
|
||||
public var text: String = ""
|
||||
public var delay = false
|
||||
public var extraParameters: JSONValueDictionary?
|
||||
public var analyticsData: JSONValueDictionary?
|
||||
}
|
||||
|
||||
public struct ScrollToTopActionHandler: MVMCoreActionHandlerProtocol {
|
||||
public init(){}
|
||||
public func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
||||
guard let model = model as? ActionScrollToTopModel else { return }
|
||||
await (delegateObject?.actionDelegate as? MVMCoreActionScrollProtocol)?.handleScrollTopAction(action: model, additionalData: additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
extension ScrollingViewController: MVMCoreActionScrollProtocol {
|
||||
@MainActor
|
||||
public func handleScrollTopAction(action: ActionModelProtocol, additionalData: [AnyHashable: Any]?) {
|
||||
scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.adjustedContentInset.top), animated: true)
|
||||
}
|
||||
}
|
||||
public class JSONCreatorActionHandler: MVMCoreUIActionHandler {
|
||||
|
||||
|
||||
public static func doStuff() {
|
||||
MVMCoreObject.sharedInstance()?.actionHandler = JSONCreatorActionHandler()
|
||||
ModelRegistry.register(handler: ScrollToTopActionHandler.self, for: ActionScrollToTopModel.self)
|
||||
ModelRegistry.register(ActionPrintModel.self)
|
||||
ModelRegistry.register(handler: ButtonWithImage.self, for: ButtonWithImageModel.self)
|
||||
ModelRegistry.register(handler: OrderTracker.self, for: OrderTrackerModel.self)
|
||||
ModelRegistry.register(handler: ListDeviceRightVariableCaret.self, for: ListDeviceRightVariableCaretModel.self)
|
||||
ModelRegistry.register(handler: Links.self, for: LinksModel.self)
|
||||
try? ModelRegistry.throwable_register(handler: neView.self, model: neViewModl.self)
|
||||
if let bundle = MVMCoreUIUtility.bundleForMVMCoreUI() {
|
||||
MVMCoreCache.shared()?.registerBundle(forImages: bundle)
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
//
|
||||
// LinkCollectionViewCell.swift
|
||||
// MobileFirstFramework
|
||||
//
|
||||
// Created by Lekshmi S on 15/12/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCoreUI
|
||||
|
||||
open class LinkCollectionViewCell: CollectionViewCell {
|
||||
public let link = Link()
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
isAccessibilityElement = true
|
||||
addMolecule(link)
|
||||
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let model = model as? LinkModel else { return }
|
||||
link.set(with: model, delegateObject, additionalData)
|
||||
updateAccessibility()
|
||||
}
|
||||
|
||||
open func updateAccessibility() {
|
||||
accessibilityLabel = link.accessibilityLabel
|
||||
accessibilityHint = link.accessibilityHint
|
||||
accessibilityTraits = link.accessibilityTraits
|
||||
}
|
||||
}
|
||||
|
||||
108
JSONCreator_iOS/JSONCreator/MF/Order Tracker/Links.swift
Normal file
108
JSONCreator_iOS/JSONCreator/MF/Order Tracker/Links.swift
Normal file
@ -0,0 +1,108 @@
|
||||
//
|
||||
// Links.swift
|
||||
// MobileFirstFramework
|
||||
//
|
||||
// Created by Lekshmi S on 15/12/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCoreUI
|
||||
|
||||
open class Links: View, UICollectionViewDelegate {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
public var collectionView: SelfSizingCollectionView!
|
||||
public var links: [LinkModel]?
|
||||
private var size: CGFloat?
|
||||
private var delegateObject: MVMCoreUIDelegateObject?
|
||||
private let itemSpacing: CGFloat = 24.0
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
override open var intrinsicContentSize: CGSize {
|
||||
return collectionView.intrinsicContentSize
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
collectionView = createCollectionView()
|
||||
addSubview(collectionView)
|
||||
isAccessibilityElement = false
|
||||
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: collectionView, useMargins: false).values))
|
||||
}
|
||||
|
||||
@objc override open func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
self.size = size
|
||||
collectionView.updateView(size)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
|
||||
guard let linksModel = model as? LinksModel else { return }
|
||||
links = linksModel.links
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
open override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
|
||||
frame = CGRect(x: 0, y: 0, width: targetSize.width, height: CGFloat(MAXFLOAT))
|
||||
layoutIfNeeded()
|
||||
print("sssC \(targetSize.width) \(collectionView.contentSize)")
|
||||
return collectionView.contentSize
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//------------------------------------------------------
|
||||
/// Creates the collection view.
|
||||
open func createCollectionView() -> SelfSizingCollectionView {
|
||||
let collection = SelfSizingCollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
|
||||
collection.dataSource = self
|
||||
collection.delegate = self
|
||||
collection.register(LinkCollectionViewCell.self, forCellWithReuseIdentifier: "LinkCollectionViewCell")
|
||||
return collection
|
||||
}
|
||||
|
||||
/// Creates the layout for the collection.
|
||||
func createCollectionViewLayout() -> UICollectionViewLeftAlignedLayout {
|
||||
let layout = UICollectionViewLeftAlignedLayout()
|
||||
layout.scrollDirection = .vertical
|
||||
layout.minimumLineSpacing = itemSpacing
|
||||
layout.minimumInteritemSpacing = itemSpacing
|
||||
layout.estimatedItemSize = CGSize(width: 20, height: 30)
|
||||
return layout
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Delegate methods
|
||||
//------------------------------------------------------
|
||||
|
||||
extension Links: UICollectionViewDataSource {
|
||||
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return links?.count ?? 0
|
||||
}
|
||||
|
||||
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
guard let molecule = links?[indexPath.item], let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LinkCollectionViewCell", for: indexPath) as? LinkCollectionViewCell else {
|
||||
fatalError()
|
||||
}
|
||||
cell.reset()
|
||||
cell.set(with: molecule, delegateObject, nil)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
//extension Links: MoleculeTableViewCellMoleculeProtocol {
|
||||
// public func getSystemFittingTargetSize(for targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority, cell: MoleculeTableViewCell) -> CGSize {
|
||||
// print("sss \(targetSize.width)")
|
||||
// cell.frame = CGRect(x: 0, y: 0, width: targetSize.width, height: CGFloat(MAXFLOAT))
|
||||
// cell.layoutIfNeeded()
|
||||
//
|
||||
// return CGSize(width: collectionView.contentSize.width + cell.contentView.directionalLayoutMargins.leading + cell.contentView.directionalLayoutMargins.trailing, height: collectionView.contentSize.height + cell.contentView.directionalLayoutMargins.top + cell.contentView.directionalLayoutMargins.bottom)
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,34 @@
|
||||
//
|
||||
// LinksModel.swift
|
||||
// MobileFirstFramework
|
||||
//
|
||||
// Created by Lekshmi S on 15/12/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import MVMCoreUI
|
||||
|
||||
@objcMembers public class LinksModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "links"
|
||||
public var backgroundColor: Color?
|
||||
public var links: [LinkModel]
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case links
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
links = try typeContainer.decode([LinkModel].self, forKey: .links)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(links, forKey: .links)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
//
|
||||
// ListDeviceRightVariableCaret.swift
|
||||
// MobileFirstFramework
|
||||
//
|
||||
// Created by Lekshmi S on 09/12/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCoreUI
|
||||
|
||||
@objcMembers open class ListDeviceRightVariableCaret: TableViewCell {
|
||||
//-----------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//-----------------------------------------------------
|
||||
public let eyebrow = Label(fontStyle: .RegularMicro)
|
||||
public let headline = Label(fontStyle: .BoldBodySmall)
|
||||
public let body1 = Label(fontStyle: .RegularBodySmall)
|
||||
public let body2 = Label(fontStyle: .RegularBodySmall)
|
||||
public let body3 = Label(fontStyle: .RegularBodySmall)
|
||||
public let rightLabel = Label(fontStyle: .RegularBodySmall)
|
||||
public let rightImage = LoadImageView()
|
||||
public weak var rightVerticalStackTopConstraint: NSLayoutConstraint?
|
||||
|
||||
public lazy var leftVerticalStack: Stack<StackModel> = {
|
||||
return Stack<StackModel>.createStack(with: [eyebrow, headline, body1, body2, body3], axis: .vertical, spacing: 2)
|
||||
}()
|
||||
|
||||
public lazy var rightVerticalStack: Stack<StackModel> = {
|
||||
return Stack<StackModel>.createStack(with: [(view: rightLabel, model: StackItemModel(horizontalAlignment: .trailing)),
|
||||
(view: rightImage, model: StackItemModel(horizontalAlignment: .trailing))],
|
||||
axis: .vertical)
|
||||
}()
|
||||
|
||||
public lazy var stack: Stack<StackModel> = {
|
||||
return Stack<StackModel>.createStack(with: [(view: leftVerticalStack, model: StackItemModel(verticalAlignment: .top)),
|
||||
(view: rightVerticalStack, model: StackItemModel(verticalAlignment: .top))],
|
||||
axis: .horizontal)
|
||||
}()
|
||||
|
||||
//-----------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//-----------------------------------------------------
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
addMolecule(stack)
|
||||
rightImage.imageView.contentMode = .scaleAspectFit
|
||||
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||
rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||
rightLabel.numberOfLines = 1
|
||||
leftVerticalStack.restack()
|
||||
rightVerticalStack.restack()
|
||||
stack.restack()
|
||||
}
|
||||
|
||||
func alignRightStack(toHeadline: Bool) {
|
||||
if toHeadline {
|
||||
rightVerticalStack.containerHelper.topConstraint?.isActive = false
|
||||
if rightVerticalStackTopConstraint == nil {
|
||||
rightVerticalStackTopConstraint = headline.topAnchor.constraint(equalTo: rightVerticalStack.contentView.topAnchor)
|
||||
}
|
||||
rightVerticalStackTopConstraint?.isActive = true
|
||||
} else {
|
||||
rightVerticalStack.containerHelper.topConstraint?.isActive = true
|
||||
rightVerticalStackTopConstraint?.isActive = false
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Molecule
|
||||
//------------------------------------------------------
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ListDeviceRightVariableCaretModel else { return }
|
||||
leftVerticalStack.updateContainedMolecules(with: [model.eyebrow, model.headline, model.body1, model.body2, model.body3], delegateObject, additionalData)
|
||||
rightVerticalStack.updateContainedMolecules(with: [model.rightLabel, model.image], delegateObject, additionalData)
|
||||
alignRightStack(toHeadline: model.headline != nil)
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 230
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
eyebrow.setFontStyle(.RegularMicro)
|
||||
headline.setFontStyle(.BoldBodySmall)
|
||||
body1.setFontStyle(.RegularBodySmall)
|
||||
body2.setFontStyle(.RegularBodySmall)
|
||||
body3.setFontStyle(.RegularBodySmall)
|
||||
rightLabel.setFontStyle(.RegularBodySmall)
|
||||
eyebrow.textColor = .mvmCoolGray6
|
||||
}
|
||||
|
||||
//----------------------------------------------------
|
||||
// MARK: - Accessibility
|
||||
//----------------------------------------------------
|
||||
|
||||
func updateAccessibilityLabel() {
|
||||
isAccessibilityElement = true
|
||||
var message = ""
|
||||
|
||||
if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty {
|
||||
message += eyebrowText + ", "
|
||||
}
|
||||
if let headlineText = headline.text, !headlineText.isEmpty {
|
||||
message += headlineText + ", "
|
||||
}
|
||||
if let body1Text = body1.text, !body1Text.isEmpty {
|
||||
message += body1Text + ", "
|
||||
}
|
||||
if let body2Text = body2.text, !body2Text.isEmpty {
|
||||
message += body2Text + ", "
|
||||
}
|
||||
if let body3Text = body3.text, !body3Text.isEmpty {
|
||||
message += body3Text + ", "
|
||||
}
|
||||
if let rightLabelText = rightLabel.text, !rightLabelText.isEmpty {
|
||||
message += rightLabelText + ", "
|
||||
}
|
||||
if let rightImageViewText = rightImage.imageView.accessibilityLabel, !rightImageViewText.isEmpty {
|
||||
message += rightImageViewText
|
||||
}
|
||||
|
||||
accessibilityLabel = message
|
||||
accessibilityTraits = (accessoryView != nil) ? .button : .none
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
//
|
||||
// ListDeviceRightVariableCaretModel.swift
|
||||
// MobileFirstFramework
|
||||
//
|
||||
// Created by Lekshmi S on 09/12/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCoreUI
|
||||
|
||||
public class ListDeviceRightVariableCaretModel: ListItemModel, MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "listDvcRvCaret"
|
||||
public var eyebrow: LabelModel?
|
||||
public var headline: LabelModel?
|
||||
public var body1: LabelModel?
|
||||
public var body2: LabelModel?
|
||||
public var body3: LabelModel?
|
||||
public var image: ImageViewModel
|
||||
public var rightLabel: LabelModel
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(eyebrow: LabelModel? = nil, headline: LabelModel? = nil, body1: LabelModel? = nil, body2: LabelModel? = nil, body3: LabelModel? = nil, image: ImageViewModel, rightLabel: LabelModel) {
|
||||
self.eyebrow = eyebrow
|
||||
self.headline = headline
|
||||
self.body1 = body1
|
||||
self.body2 = body2
|
||||
self.body3 = body3
|
||||
self.image = image
|
||||
self.rightLabel = rightLabel
|
||||
super.init()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Method
|
||||
//--------------------------------------------------
|
||||
|
||||
override public func setDefaults() {
|
||||
super.setDefaults()
|
||||
rightLabel.hero = 0
|
||||
if image.width == nil, image.height == nil {
|
||||
image.width = 36
|
||||
image.height = 72
|
||||
}
|
||||
}
|
||||
|
||||
/// The left stack requires content.
|
||||
func validateContent() throws {
|
||||
if eyebrow == nil,
|
||||
headline == nil,
|
||||
body1 == nil,
|
||||
body2 == nil,
|
||||
body3 == nil {
|
||||
throw ModelRegistry.Error.decoderOther(message: "\(self) requires one left label")
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case eyebrow
|
||||
case headline
|
||||
case body1
|
||||
case body2
|
||||
case body3
|
||||
case image
|
||||
case rightLabel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
|
||||
headline = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .headline)
|
||||
body1 = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body1)
|
||||
body2 = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body2)
|
||||
body3 = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body3)
|
||||
image = try typeContainer.decode(ImageViewModel.self, forKey: .image)
|
||||
rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel)
|
||||
try super.init(from: decoder)
|
||||
try validateContent()
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
|
||||
try container.encodeIfPresent(headline, forKey: .headline)
|
||||
try container.encodeIfPresent(body1, forKey: .body1)
|
||||
try container.encodeIfPresent(body2, forKey: .body2)
|
||||
try container.encodeIfPresent(body3, forKey: .body3)
|
||||
try container.encode(image, forKey: .image)
|
||||
try container.encode(rightLabel, forKey: .rightLabel)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user