From a24d60e938ba3f9313d5dd80b7bc7238b2deefb5 Mon Sep 17 00:00:00 2001 From: Mantosh Kumar <> Date: Fri, 28 Jul 2023 14:37:52 +0530 Subject: [PATCH] Branch release2.7.1 merge into master gitHub branch --- .../SILESLCommandConnectTestSpec.swift | 43 ++++++----------- .../SILESLProvisioningTagTestSpec.swift | 12 ++--- .../SILESLCommandConnectRunnerTestSpec.swift | 4 +- .../SILESLCommandRunnerFactoryTestSpec.swift | 16 +++++-- .../ESLDemo/QRScannerViewModelTestSpec.swift | 47 ++++--------------- .../ESLDemo/SILESLDemoViewModelTestSpec.swift | 16 +++---- Podfile | 1 + Podfile.lock | 10 ++-- README.md | 17 ------- SiliconLabsApp.xcodeproj/project.pbxproj | 23 ++++++--- .../Categories/UITabBarController+Hide.swift | 23 +++++++++ .../FieldRows/SILBitRowModel.m | 29 ++++++++++-- .../Redesign/MainNavigationView.swift | 16 ------- SiliconLabsApp/Redesign/PickerTabView.swift | 9 +++- .../DevelopApps/SILAppAdvertiser.storyboard | 17 +++---- .../SILAppBluetoothBrowser.storyboard | 30 ++++++------ .../SILAppGATTConfigurator.storyboard | 19 ++++---- .../SILAdvertiserHomeViewController.swift | 5 +- .../SILBrowserConnectionsViewController.m | 5 +- .../SILBluetoothBrowserViewController.m | 4 +- .../SILDebugServicesViewController.m | 11 +++++ .../Model/Commands/SILESLCommandConnect.swift | 37 ++++++++++----- .../Processes/SILESLProvisioningTag.swift | 17 +++---- .../Model/SILESLCommandRunnerFactory.swift | 26 +++++----- .../ESLDemo/UI/QRScannerViewController.swift | 13 +++-- .../ESLDemo/UI/SILESLDemoViewController.swift | 8 ++-- .../ViewModel/QRScannerViewModel.swift | 45 +++--------------- .../ViewModel/SILESLDemoViewModel.swift | 5 +- ...ILGattConfiguratorHomeViewController.swift | 5 +- ...CharacteristicToggleFieldTableViewCell.xib | 11 +++-- 30 files changed, 254 insertions(+), 270 deletions(-) diff --git a/BlueGeckoTests/ViewModels/ESLDemo/Model/Commands/SILESLCommandConnectTestSpec.swift b/BlueGeckoTests/ViewModels/ESLDemo/Model/Commands/SILESLCommandConnectTestSpec.swift index 7ac2f819..65a2d67a 100644 --- a/BlueGeckoTests/ViewModels/ESLDemo/Model/Commands/SILESLCommandConnectTestSpec.swift +++ b/BlueGeckoTests/ViewModels/ESLDemo/Model/Commands/SILESLCommandConnectTestSpec.swift @@ -20,35 +20,34 @@ class SILESLCommandConnectTestSpec: QuickSpec { var sut: SILESLCommandConnect! override func spec() { - describe("connect bt_addr") { - it("should prepare data for public address") { + describe("raw data") { + it("should prepare connect from raw data") { let btAddress = "8c:f6:81:b8:82:b2" - self.address = SILAddress.btAddress(SILBluetoothAddress(address: btAddress, addressType: .public)) - self.sut = SILESLCommandConnect(address: self.address) - let dataToSend = "connect \(btAddress)".bytes + self.sut = SILESLCommandConnect(qrData: dataToSend) + expect(self.sut.dataToSend).to(equal(dataToSend)) } - - it("should prepare data for public address with passcode") { + } + + describe("connect bt_addr") { + it("should prepare data for public address") { let btAddress = "8c:f6:81:b8:82:b2" - let passcode = "1234" self.address = SILAddress.btAddress(SILBluetoothAddress(address: btAddress, addressType: .public)) - self.sut = SILESLCommandConnect(address: self.address, passcode: passcode) + self.sut = SILESLCommandConnect(address: self.address) - let dataToSend = "connect \(btAddress) \(passcode)".bytes + let dataToSend = "connect \(btAddress)".bytes expect(self.sut.dataToSend).to(equal(dataToSend)) } - it("should prepare data for static address with passcode") { + it("should prepare data for static address") { let btAddress = "X" - let passcode = "1234" self.address = SILAddress.btAddress(SILBluetoothAddress(address: btAddress, addressType: .static)) - self.sut = SILESLCommandConnect(address: self.address, passcode: passcode) + self.sut = SILESLCommandConnect(address: self.address) - let dataToSend = "connect \(btAddress) static \(passcode)".bytes + let dataToSend = "connect \(btAddress) static".bytes expect(self.sut.dataToSend).to(equal(dataToSend)) } @@ -65,11 +64,10 @@ class SILESLCommandConnectTestSpec: QuickSpec { it("should prepare data for rand_nonres address") { let btAddress = "XXX" - let passcode = "4321" self.address = SILAddress.btAddress(SILBluetoothAddress(address: btAddress, addressType: .rand_nonres)) - self.sut = SILESLCommandConnect(address: self.address, passcode: passcode) + self.sut = SILESLCommandConnect(address: self.address) - let dataToSend = "connect \(btAddress) rand_nonres \(passcode)".bytes + let dataToSend = "connect \(btAddress) rand_nonres".bytes expect(self.sut.dataToSend).to(equal(dataToSend)) } @@ -85,17 +83,6 @@ class SILESLCommandConnectTestSpec: QuickSpec { expect(self.sut.dataToSend).to(equal(dataToSend)) } - - it("should prepare data for esl_id with passcode") { - let eslId = 55 - let passcode = "56789" - self.address = SILAddress.eslId(SILESLIdAddress.unicast(id: 55)) - self.sut = SILESLCommandConnect(address: self.address, passcode: passcode) - - let dataToSend = "connect \(eslId) \(passcode)".bytes - - expect(self.sut.dataToSend).to(equal(dataToSend)) - } } } } diff --git a/BlueGeckoTests/ViewModels/ESLDemo/Model/Processes/SILESLProvisioningTagTestSpec.swift b/BlueGeckoTests/ViewModels/ESLDemo/Model/Processes/SILESLProvisioningTagTestSpec.swift index 71df6de5..66752637 100644 --- a/BlueGeckoTests/ViewModels/ESLDemo/Model/Processes/SILESLProvisioningTagTestSpec.swift +++ b/BlueGeckoTests/ViewModels/ESLDemo/Model/Processes/SILESLProvisioningTagTestSpec.swift @@ -30,7 +30,7 @@ class SILESLProvisioningTagTestSpec: QuickSpec { self.sut = SILESLProvisioningTag(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, commandRunnerFactory: self.commandRunnerFactoryMock, - address: .init(address: "", addressType: .public)) + qrData: [UInt8]()) } afterEach { @@ -39,11 +39,10 @@ class SILESLProvisioningTagTestSpec: QuickSpec { describe("perform(timeout:)") { it("should call function and return success") { - let btAddress = SILBluetoothAddress(address: "", addressType: .public) - let connectCommandMock = mock(SILESLCommandConnect.self).initialize(address: .btAddress(btAddress), passcode: "1234") + let connectCommandMock = mock(SILESLCommandConnect.self).initialize(qrData: [UInt8]()) let connect = mock(SILESLCommandConnectRunner.self).initialize(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, command: connectCommandMock) - given(self.commandRunnerFactoryMock.createCommandConnectRunner(peripheral: self.peripheralMock, peripheralReferences: any(), address: any(), passcode: any())).willReturn(connect) + given(self.commandRunnerFactoryMock.createCommandConnectRunner(peripheral: self.peripheralMock, peripheralReferences: any(), qrData: any(), address: nil)).willReturn(connect) let publishRelay: PublishRelay> = PublishRelay() given(connect.commandResult).willReturn(publishRelay) @@ -62,11 +61,10 @@ class SILESLProvisioningTagTestSpec: QuickSpec { } it("should call function and return error") { - let btAddress = SILBluetoothAddress(address: "", addressType: .public) - let connectCommandMock = mock(SILESLCommandConnect.self).initialize(address: .btAddress(btAddress), passcode: "1234") + let connectCommandMock = mock(SILESLCommandConnect.self).initialize(qrData: [UInt8]()) let connect = mock(SILESLCommandConnectRunner.self).initialize(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, command: connectCommandMock) - given(self.commandRunnerFactoryMock.createCommandConnectRunner(peripheral: self.peripheralMock, peripheralReferences: any(), address: any(), passcode: any())).willReturn(connect) + given(self.commandRunnerFactoryMock.createCommandConnectRunner(peripheral: self.peripheralMock, peripheralReferences: any(), qrData: any(), address: nil)).willReturn(connect) let publishRelay: PublishRelay> = PublishRelay() given(connect.commandResult).willReturn(publishRelay) diff --git a/BlueGeckoTests/ViewModels/ESLDemo/Model/Runners/SILESLCommandConnectRunnerTestSpec.swift b/BlueGeckoTests/ViewModels/ESLDemo/Model/Runners/SILESLCommandConnectRunnerTestSpec.swift index 4afa4568..b2bbb05b 100644 --- a/BlueGeckoTests/ViewModels/ESLDemo/Model/Runners/SILESLCommandConnectRunnerTestSpec.swift +++ b/BlueGeckoTests/ViewModels/ESLDemo/Model/Runners/SILESLCommandConnectRunnerTestSpec.swift @@ -28,9 +28,9 @@ class SILESLCommandConnectRunnerTestSpec: QuickSpec { override func spec() { beforeEach { self.address = .eslId(.broadcast) - self.commandMock = mock(SILESLCommandConnect.self).initialize(address: self.address, passcode: nil) + self.commandMock = mock(SILESLCommandConnect.self).initialize(address: self.address) let defaultMock = SILESLPeripheralMockFactory().getDefault() - given(self.commandMock.getFullCommand()).willReturn("") + given(self.commandMock.getDataToSend()).willReturn([UInt8]()) self.eslDemoServiceMock = defaultMock.eslDemoServiceMock self.eslControlPointMock = defaultMock.eslControlPointMock self.peripheralMock = defaultMock.peripheralMock diff --git a/BlueGeckoTests/ViewModels/ESLDemo/Model/SILESLCommandRunnerFactoryTestSpec.swift b/BlueGeckoTests/ViewModels/ESLDemo/Model/SILESLCommandRunnerFactoryTestSpec.swift index ab751fa5..2bedbbee 100644 --- a/BlueGeckoTests/ViewModels/ESLDemo/Model/SILESLCommandRunnerFactoryTestSpec.swift +++ b/BlueGeckoTests/ViewModels/ESLDemo/Model/SILESLCommandRunnerFactoryTestSpec.swift @@ -34,8 +34,7 @@ class SILESLCommandRunnerFactoryTestSpec: QuickSpec { let provisioning = self.sut.createCommandProvisioning(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, commandRunnerFactory: self.sut, - address: SILBluetoothAddress(address: "", addressType: .public), - passcode: "12345") + qrData: [UInt8]()) expect(provisioning.isKind(of: SILESLProvisioningTag.self)).to(beTrue()) } @@ -56,11 +55,18 @@ class SILESLCommandRunnerFactoryTestSpec: QuickSpec { } describe("createCommandConnectRunner") { - it("should create proper object") { + it("should create proper object with address") { + let connectRunner = self.sut.createCommandConnectRunner(peripheral: self.peripheralMock, + peripheralReferences: self.peripheralReferencesMock, + address: self.addressMock) + + expect(connectRunner.isKind(of: SILESLCommandConnectRunner.self)).to(beTrue()) + } + + it("should create proper object with qrCode") { let connectRunner = self.sut.createCommandConnectRunner(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, - address: self.addressMock, - passcode: "12345") + qrData: [UInt8]()) expect(connectRunner.isKind(of: SILESLCommandConnectRunner.self)).to(beTrue()) } diff --git a/BlueGeckoTests/ViewModels/ESLDemo/QRScannerViewModelTestSpec.swift b/BlueGeckoTests/ViewModels/ESLDemo/QRScannerViewModelTestSpec.swift index 3ccea741..4b105695 100644 --- a/BlueGeckoTests/ViewModels/ESLDemo/QRScannerViewModelTestSpec.swift +++ b/BlueGeckoTests/ViewModels/ESLDemo/QRScannerViewModelTestSpec.swift @@ -26,66 +26,39 @@ class QRScannerViewModelTestSpec: QuickSpec { describe("readQR - correct") { it("should read correct two words") { let address = "00:01:02:03:04:05" - let qrData = self.sut.readQR(metadata: "connect \(address)") + let full = "connect \(address)" + let qrData = self.sut.readQR(metadata: full) expect(qrData).notTo(beNil()) expect(qrData?.bluetoothAddress.addressType).to(equal(.public)) expect(qrData?.bluetoothAddress.address).to(equal(address)) - expect(qrData?.passcode).to(beNil()) + expect(qrData?.rawData).to(equal(full.bytes)) } - it("should read correct three words") { + it("should read correct with more characters") { let address = "00:01:02:03:04:05" - let qrData = self.sut.readQR(metadata: "connect \(address) static") + let full = "abc dconnect \(address) static" + let qrData = self.sut.readQR(metadata: full) expect(qrData).notTo(beNil()) - expect(qrData?.bluetoothAddress.addressType).to(equal(.static)) - expect(qrData?.bluetoothAddress.address).to(equal(address)) - expect(qrData?.passcode).to(beNil()) - } - - it("should read correct four words") { - let address = "00:01:02:03:04:05" - let passcode = "1234" - let qrData = self.sut.readQR(metadata: "connect \(address) rand_nonres \(passcode)") - - expect(qrData).notTo(beNil()) - expect(qrData?.bluetoothAddress.addressType).to(equal(.rand_nonres)) + expect(qrData?.bluetoothAddress.addressType).to(equal(.public)) expect(qrData?.bluetoothAddress.address).to(equal(address)) - expect(qrData?.passcode).to(equal(passcode)) + expect(qrData?.rawData).to(equal(full.bytes)) } } describe("readQR - incorrect") { - it("return nil - words.count = 1") { - let qrData = self.sut.readQR(metadata: "connect") - - expect(qrData).to(beNil()) - } - - it("return nil - words.count = 5") { + it("return nil - missing btAddress") { let qrData = self.sut.readQR(metadata: "connect a b c d") expect(qrData).to(beNil()) } - it("return nil - words[0] != connect") { - let qrData = self.sut.readQR(metadata: "connected 11:12:13:14:15:16") - - expect(qrData).to(beNil()) - } - - it("return nil - words[1].isValid = false") { + it("return nil - btAddress wrong") { let qrData = self.sut.readQR(metadata: "connect 100:12:13:14:15:16") expect(qrData).to(beNil()) } - - it("return nil - words[2] invalid type") { - let qrData = self.sut.readQR(metadata: "connect 11:12:13:14:15:16 nonpublic") - - expect(qrData).to(beNil()) - } } } } diff --git a/BlueGeckoTests/ViewModels/ESLDemo/SILESLDemoViewModelTestSpec.swift b/BlueGeckoTests/ViewModels/ESLDemo/SILESLDemoViewModelTestSpec.swift index 5c4877cb..ec357cce 100644 --- a/BlueGeckoTests/ViewModels/ESLDemo/SILESLDemoViewModelTestSpec.swift +++ b/BlueGeckoTests/ViewModels/ESLDemo/SILESLDemoViewModelTestSpec.swift @@ -143,14 +143,12 @@ class SILESLDemoViewModelTestSpec: QuickSpec { describe("provisionTag") { it("should call perform on runner and finish with success") { - let btAddress = SILBluetoothAddress(address: "", addressType: .public) let provisionCommandMock = mock(SILESLProvisioningTag.self).initialize(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, commandRunnerFactory: self.commandRunnerFactoryMock, - address: btAddress, - passcode: nil) + qrData: [UInt8]()) - given(self.commandRunnerFactoryMock.createCommandProvisioning(peripheral: self.peripheralMock, peripheralReferences: any(), commandRunnerFactory: self.commandRunnerFactoryMock, address: any(), passcode: any())).willReturn(provisionCommandMock) + given(self.commandRunnerFactoryMock.createCommandProvisioning(peripheral: self.peripheralMock, peripheralReferences: any(), commandRunnerFactory: self.commandRunnerFactoryMock, qrData: any())).willReturn(provisionCommandMock) let publishRelay: PublishRelay> = PublishRelay() given(provisionCommandMock.commandResult).willReturn(publishRelay) @@ -160,7 +158,7 @@ class SILESLDemoViewModelTestSpec: QuickSpec { expectedState = commandState }).disposed(by: self.disposeBag) - self.sut.provisionTag(with: btAddress, passcode: "1234") + self.sut.provisionTag(with: [UInt8]()) publishRelay.accept(.success(.provisioningInProgressConfig)) verify(provisionCommandMock.perform(timeout: 10.0)).wasCalled(1) @@ -168,14 +166,12 @@ class SILESLDemoViewModelTestSpec: QuickSpec { } it("should call perform on runner and finish with failure") { - let btAddress = SILBluetoothAddress(address: "", addressType: .public) let provisionCommandMock = mock(SILESLProvisioningTag.self).initialize(peripheral: self.peripheralMock, peripheralReferences: self.peripheralReferencesMock, commandRunnerFactory: self.commandRunnerFactoryMock, - address: btAddress, - passcode: nil) + qrData: [UInt8]()) - given(self.commandRunnerFactoryMock.createCommandProvisioning(peripheral: self.peripheralMock, peripheralReferences: any(), commandRunnerFactory: self.commandRunnerFactoryMock, address: any(), passcode: any())).willReturn(provisionCommandMock) + given(self.commandRunnerFactoryMock.createCommandProvisioning(peripheral: self.peripheralMock, peripheralReferences: any(), commandRunnerFactory: self.commandRunnerFactoryMock, qrData: any())).willReturn(provisionCommandMock) let publishRelay: PublishRelay> = PublishRelay() given(provisionCommandMock.commandResult).willReturn(publishRelay) @@ -185,7 +181,7 @@ class SILESLDemoViewModelTestSpec: QuickSpec { expectedState = commandState }).disposed(by: self.disposeBag) - self.sut.provisionTag(with: btAddress, passcode: "1234") + self.sut.provisionTag(with: [UInt8]()) publishRelay.accept(.failure(.timeout)) verify(provisionCommandMock.perform(timeout: 10.0)).wasCalled(1) diff --git a/Podfile b/Podfile index ee5338cc..559c56ff 100644 --- a/Podfile +++ b/Podfile @@ -24,6 +24,7 @@ def shared_pods pod 'AEXML' pod 'RxSwift', '~> 6.2.0' pod 'RxCocoa', '~> 6.2.0' + pod 'Introspect' end def test_pods diff --git a/Podfile.lock b/Podfile.lock index a5e14735..d472747d 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -11,6 +11,7 @@ PODS: - Crashlytics (3.12.0): - Fabric (~> 1.9.0) - Fabric (1.9.0) + - Introspect (0.1.4) - IP-UIKit-Wisdom (0.0.10) - KVOController (1.2.0) - MockingbirdFramework (0.20.0) @@ -43,6 +44,7 @@ DEPENDENCIES: - Charts (~> 4.1.0) - Crashlytics (~> 3.12.0) - Fabric (~> 1.9.0) + - Introspect - IP-UIKit-Wisdom (~> 0.0.10) - KVOController (~> 1.2.0) - MockingbirdFramework (~> 0.20) @@ -68,6 +70,7 @@ SPEC REPOS: - Charts - Crashlytics - Fabric + - Introspect - IP-UIKit-Wisdom - KVOController - MockingbirdFramework @@ -99,9 +102,10 @@ SPEC CHECKSUMS: ActionSheetPicker-3.0: 2f5e3fde6b3205a7318f9338e4ec0f373ce7e75c AEXML: 1e255ecc6597212f97a7454a69ebd3ede64ac1cf ChameleonFramework: d21a3cc247abfe5e37609a283a8238b03575cf64 - Charts: 354f86803d11d9c35de280587fef50d1af063978 + Charts: ce0768268078eee0336f122c3c4ca248e4e204c5 Crashlytics: a33af323773f73904037dc2e684cd2f0d29f4fe2 Fabric: 09ef2d9b99b104702bede1acaf469fb8f20a9146 + Introspect: b62c4dd2063072327c21d618ef2bedc3c87bc366 IP-UIKit-Wisdom: b395a065344071b33659e5f6b918043a97c48a44 KVOController: d72ace34afea42468329623b3379ab3cd1d286b6 MockingbirdFramework: 54e35fbbb47b806c1a1fae2cf3ef99f6eceb55e5 @@ -121,6 +125,6 @@ SPEC CHECKSUMS: WYPopoverController: a9db25ac2841a686acdc0f3a99bdb21545db32f4 XMLDictionary: fa07b6ff422b3a91d47a5de9bc82e3fc04fbd167 -PODFILE CHECKSUM: 2a7bf762833c9e5113333b740d5adcf2e3da73dc +PODFILE CHECKSUM: ccf13e60e9ab41471864f78e72f744756afc259a -COCOAPODS: 1.10.0 +COCOAPODS: 1.12.1 diff --git a/README.md b/README.md index 450efafe..4a38eac1 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ EFR Connect includes many demos to test sample apps in the Silicon Labs GSDK qui - **Motion**: Control a 3D render of a Silicon Labs Thunderboard or Dev Kit that follows the phyiscal board movements. - **Environment**: Read and display the data from the on-board sensors on a Silicon Labs Thunderboard or Dev Kit. - **Wi-Fi Commissioning**: Commission a Wi-Fi device over BLE. -- **Bluetooth Electronic Shelf Labels (ESL)**: Adds and commissions ESL tags to the system network by scanning the tag's QR code with the mobile device's camera and provides the user a UI to view the list commissioned tags and control them. ## Development Features EFR Connect helps developers create and troubleshoot Bluetooth applications running on Silicon Labs’ BLE hardware. Here’s a rundown of some example functionalities. @@ -61,22 +60,6 @@ EFR Connect helps developers create and troubleshoot Bluetooth applications runn - Export results log -## How to build project -To build project you need Install [Cocoapods](https://cocoapods.org/). -Run command `pod install` in the main folder of the project and then use generated `SiliconLabsApp.xcworkspace` file to open project. Use `BlueGecko` scheme to run or test app. - - -## How to start developing -Applications are written using [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) pattern. -The View Controllers layer (also a starting point for each of app - Demo, IOP, Browser, Develop) is in the `/ViewController` folder. -You can find there references to View Models and the Models that are used in the specific applications. -Each app has mostly separated files so is almost unlikely that modifying one part of code is going to break other app. -For storing data we are using [Realm](https://realm.io/) database. -Please notice that you must take care of migrations when you are modifying scheme of objects (modify `SILRealmConfiguration.swift` file). -At `/Supporting Files` you can find XMLs of [SIG Group](https://www.bluetooth.com/) defined GATT services, characteristics and descriptors. -The IOP test suites are in folder `/ViewControllers/IOP Test App/TestScenario`. -The OTA related code is located in `/ViewControllers/BluetoothBrowser/Details/OTA`. - ## Additional information The app can be found on the [Google PlayStore](https://play.google.com/store/apps/details?id=com.siliconlabs.bledemo&hl=en) and [Apple App Store](https://apps.apple.com/us/app/blue-gecko/id1030932759). diff --git a/SiliconLabsApp.xcodeproj/project.pbxproj b/SiliconLabsApp.xcodeproj/project.pbxproj index 9c28c1ed..70ea00fa 100644 --- a/SiliconLabsApp.xcodeproj/project.pbxproj +++ b/SiliconLabsApp.xcodeproj/project.pbxproj @@ -482,7 +482,6 @@ 1E26ECCD25529BC6002FFAAB /* SILScanResponseValueCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E26ECCC25529BC6002FFAAB /* SILScanResponseValueCellViewModel.swift */; }; 1E26ECD225529C20002FFAAB /* SILScanResponseTitleCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E26ECD125529C20002FFAAB /* SILScanResponseTitleCellView.swift */; }; 1E26ECD425529C3F002FFAAB /* SILScanResponseValueCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E26ECD325529C3F002FFAAB /* SILScanResponseValueCellView.swift */; }; - 1E29C33F29D315CD00D239C4 /* QRScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29C33E29D315CD00D239C4 /* QRScannerViewModel.swift */; }; 1E29C34129D31B0300D239C4 /* QRScannerViewModelTestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29C34029D31B0300D239C4 /* QRScannerViewModelTestSpec.swift */; }; 1E29C34629D596F000D239C4 /* SILESLImageUpdatePopup.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1E29C34529D596F000D239C4 /* SILESLImageUpdatePopup.xib */; }; 1E29C34829D5970B00D239C4 /* SILESLDisplayImagePopup.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1E29C34729D5970B00D239C4 /* SILESLDisplayImagePopup.xib */; }; @@ -497,6 +496,7 @@ 1E38C2952684F548001F3033 /* SILGattPropertyMarkerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E38C2942684F547001F3033 /* SILGattPropertyMarkerTest.swift */; }; 1E38C2BC268503A5001F3033 /* SILGattCapabilitiesMarkerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E38C2BB268503A5001F3033 /* SILGattCapabilitiesMarkerTest.swift */; }; 1E38C2C32685CC38001F3033 /* SILGattPropertiesMarkerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E38C2C22685CC38001F3033 /* SILGattPropertiesMarkerTest.swift */; }; + 1E3D6A332A45DB49006946E1 /* QRScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3D6A322A45DB49006946E1 /* QRScannerViewModel.swift */; }; 1E3FC7D8252B5E40002F740D /* UITextField+DoneButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3FC7D7252B5E40002F740D /* UITextField+DoneButton.swift */; }; 1E48A1E92484E27300C188C0 /* SILAnimatedUIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E48A1E82484E27300C188C0 /* SILAnimatedUIButton.swift */; }; 1E48A1EF2484FC0B00C188C0 /* SILToastModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E48A1EE2484FC0B00C188C0 /* SILToastModelType.swift */; }; @@ -1389,7 +1389,6 @@ 1E26ECCC25529BC6002FFAAB /* SILScanResponseValueCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILScanResponseValueCellViewModel.swift; sourceTree = ""; }; 1E26ECD125529C20002FFAAB /* SILScanResponseTitleCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILScanResponseTitleCellView.swift; sourceTree = ""; }; 1E26ECD325529C3F002FFAAB /* SILScanResponseValueCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILScanResponseValueCellView.swift; sourceTree = ""; }; - 1E29C33E29D315CD00D239C4 /* QRScannerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerViewModel.swift; sourceTree = ""; }; 1E29C34029D31B0300D239C4 /* QRScannerViewModelTestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerViewModelTestSpec.swift; sourceTree = ""; }; 1E29C34529D596F000D239C4 /* SILESLImageUpdatePopup.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SILESLImageUpdatePopup.xib; sourceTree = ""; }; 1E29C34729D5970B00D239C4 /* SILESLDisplayImagePopup.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SILESLDisplayImagePopup.xib; sourceTree = ""; }; @@ -1405,6 +1404,7 @@ 1E38C2942684F547001F3033 /* SILGattPropertyMarkerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILGattPropertyMarkerTest.swift; sourceTree = ""; }; 1E38C2BB268503A5001F3033 /* SILGattCapabilitiesMarkerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILGattCapabilitiesMarkerTest.swift; sourceTree = ""; }; 1E38C2C22685CC38001F3033 /* SILGattPropertiesMarkerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILGattPropertiesMarkerTest.swift; sourceTree = ""; }; + 1E3D6A322A45DB49006946E1 /* QRScannerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerViewModel.swift; sourceTree = ""; }; 1E3FC7D7252B5E40002F740D /* UITextField+DoneButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+DoneButton.swift"; sourceTree = ""; }; 1E48A1E82484E27300C188C0 /* SILAnimatedUIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILAnimatedUIButton.swift; sourceTree = ""; }; 1E48A1EE2484FC0B00C188C0 /* SILToastModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILToastModelType.swift; sourceTree = ""; }; @@ -2810,7 +2810,7 @@ 1E29C35029D5AC7700D239C4 /* Cells */, 1E29C34F29D5AC6E00D239C4 /* Popups */, 1E0C1276298BE7BA00BCADFC /* SILESLDemoViewModel.swift */, - 1E29C33E29D315CD00D239C4 /* QRScannerViewModel.swift */, + 1E3D6A322A45DB49006946E1 /* QRScannerViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -5333,6 +5333,7 @@ "${BUILT_PRODUCTS_DIR}/ChameleonFramework/ChameleonFramework.framework", "${BUILT_PRODUCTS_DIR}/Charts/Charts.framework", "${BUILT_PRODUCTS_DIR}/IP-UIKit-Wisdom/IP_UIKit_Wisdom.framework", + "${BUILT_PRODUCTS_DIR}/Introspect/Introspect.framework", "${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework", "${BUILT_PRODUCTS_DIR}/MZTimerLabel/MZTimerLabel.framework", "${BUILT_PRODUCTS_DIR}/PureLayout/PureLayout.framework", @@ -5358,6 +5359,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ChameleonFramework.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IP_UIKit_Wisdom.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Introspect.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MZTimerLabel.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PureLayout.framework", @@ -5424,6 +5426,7 @@ "${BUILT_PRODUCTS_DIR}/ChameleonFramework/ChameleonFramework.framework", "${BUILT_PRODUCTS_DIR}/Charts/Charts.framework", "${BUILT_PRODUCTS_DIR}/IP-UIKit-Wisdom/IP_UIKit_Wisdom.framework", + "${BUILT_PRODUCTS_DIR}/Introspect/Introspect.framework", "${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework", "${BUILT_PRODUCTS_DIR}/MZTimerLabel/MZTimerLabel.framework", "${BUILT_PRODUCTS_DIR}/PureLayout/PureLayout.framework", @@ -5445,6 +5448,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ChameleonFramework.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IP_UIKit_Wisdom.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Introspect.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MZTimerLabel.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PureLayout.framework", @@ -5507,6 +5511,7 @@ "${BUILT_PRODUCTS_DIR}/ChameleonFramework/ChameleonFramework.framework", "${BUILT_PRODUCTS_DIR}/Charts/Charts.framework", "${BUILT_PRODUCTS_DIR}/IP-UIKit-Wisdom/IP_UIKit_Wisdom.framework", + "${BUILT_PRODUCTS_DIR}/Introspect/Introspect.framework", "${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework", "${BUILT_PRODUCTS_DIR}/MZTimerLabel/MZTimerLabel.framework", "${BUILT_PRODUCTS_DIR}/PureLayout/PureLayout.framework", @@ -5528,6 +5533,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ChameleonFramework.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IP_UIKit_Wisdom.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Introspect.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MZTimerLabel.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PureLayout.framework", @@ -5559,6 +5565,7 @@ "${BUILT_PRODUCTS_DIR}/ChameleonFramework/ChameleonFramework.framework", "${BUILT_PRODUCTS_DIR}/Charts/Charts.framework", "${BUILT_PRODUCTS_DIR}/IP-UIKit-Wisdom/IP_UIKit_Wisdom.framework", + "${BUILT_PRODUCTS_DIR}/Introspect/Introspect.framework", "${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework", "${BUILT_PRODUCTS_DIR}/MZTimerLabel/MZTimerLabel.framework", "${BUILT_PRODUCTS_DIR}/PureLayout/PureLayout.framework", @@ -5580,6 +5587,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ChameleonFramework.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IP_UIKit_Wisdom.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Introspect.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MZTimerLabel.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PureLayout.framework", @@ -5848,6 +5856,7 @@ FE05894C29434573002F3BFE /* SettingsView.swift in Sources */, 205131FC270365A800C27B92 /* IoDemoViewController.swift in Sources */, 1E4DB3BC266A720600405BD2 /* SILCheckBox.swift in Sources */, + 1E3D6A332A45DB49006946E1 /* QRScannerViewModel.swift in Sources */, FE075BC028C5F9D000382903 /* BinaryFloatConverter.swift in Sources */, 1E4D8F5C26035FE000924430 /* SILIOPTestScenarioCellView.swift in Sources */, 80B3E2D627D1044400838066 /* CBCentralManager+Reactive.swift in Sources */, @@ -6078,7 +6087,6 @@ 1EC1F1F8260CEA5D00508552 /* SILGATT_4_1TestCase.swift in Sources */, 1EFC76A226AEDFA40035594E /* SILGattConfiguratorDescriptorCellViewModel.swift in Sources */, 20513289270365A800C27B92 /* ThunderBoardSettings.swift in Sources */, - 1E29C33F29D315CD00D239C4 /* QRScannerViewModel.swift in Sources */, 0C2FCB621F9A542300F4F259 /* SILDebugSpacerTableViewCell.m in Sources */, 1E26EC98255019E0002FFAAB /* SILAdvertisingDataTitleCellView.swift in Sources */, 1E26EC90255019E0002FFAAB /* SILDropDown.swift in Sources */, @@ -6684,11 +6692,13 @@ CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/SiliconLabsApp/SupportingFiles/BlueGecko/Entitlements.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_RESOURCE_RULES_PATH = ""; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 52444FG85C; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 52444FG85C; DISPLAY_NAME = "EFR Connect"; ENABLE_BITCODE = NO; GCC_PREFIX_HEADER = "$(SRCROOT)/SiliconLabsApp/SupportingFiles/BlueGecko/BlueGecko.pch"; @@ -6703,6 +6713,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.silabs.BlueGeckoDemoApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "BlueGeckoDemoApp Distribution"; SWIFT_OBJC_BRIDGING_HEADER = "SiliconLabsApp-Bridging-Header.h"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/SiliconLabsApp/Categories/UITabBarController+Hide.swift b/SiliconLabsApp/Categories/UITabBarController+Hide.swift index 463397ad..c10e16a2 100644 --- a/SiliconLabsApp/Categories/UITabBarController+Hide.swift +++ b/SiliconLabsApp/Categories/UITabBarController+Hide.swift @@ -25,4 +25,27 @@ extension UITabBarController { height: view.frame.height - tabBar.frame.size.height) tabBar.layoutIfNeeded() } + + @objc func setTabBarVisible(visible: Bool, animated: Bool, controllerHeight: NSLayoutConstraint?) { + if (tabBarIsVisible() == visible) { + return + } + + let height = self.tabBar.frame.size.height + let offsetY = (visible ? -height : height) + + let duration = (animated ? 0.5 : 0.0) + controllerHeight?.constant = visible ? 0 : -48 + + UIView.animate(withDuration: duration, animations: { + let frame = self.tabBar.frame + self.tabBar.frame = frame.offsetBy(dx: 0, dy: offsetY) + self.view.setNeedsDisplay() + self.view.layoutIfNeeded() + }) + } + + private func tabBarIsVisible() -> Bool { + return self.tabBar.frame.origin.y < view.frame.maxY + } } diff --git a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m index aaa7d41c..a0afcbe2 100644 --- a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m +++ b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m @@ -19,6 +19,7 @@ @interface SILBitRowModel() @property (strong, nonatomic, readwrite) SILBluetoothBitModel *bit; @property (strong, nonatomic, readwrite) SILBluetoothFieldModel *fieldModel; @property (strong, nonatomic) NSString *toggleValue; +@property (strong, nonatomic) NSArray *binaryArray; @end @@ -44,7 +45,27 @@ - (NSString *)primaryTitle { return nil; } - return ((SILBluetoothEnumerationModel *)self.bit.enumerations[[self.toggleState intValue]]).value; + NSMutableString *description = [[NSMutableString alloc] init]; + BOOL firstAppend = YES; + + for (int i = 0; i < self.bit.enumerations.count; i++) { + NSNumber *binaryValue = self.binaryArray[i]; + if ([binaryValue intValue] == 1) { + if (!firstAppend) { + [description appendString:@"\n"]; + } else { + firstAppend = NO; + } + + [description appendString:((SILBluetoothEnumerationModel *)self.bit.enumerations[i]).value]; + } + } + + if ([description isEqualToString:@""]) { + [description appendString:((SILBluetoothEnumerationModel *)self.bit.enumerations[0]).value]; + } + + return [description copy]; } - (NSString *)secondaryTitle { @@ -59,10 +80,10 @@ - (NSString *)toggleValue { //@discussion current implementation has this called by SILBitFieldFieldModel, which handles correct length - (NSInteger)consumeValue:(NSData *)value fromIndex:(NSInteger)index { value = [self reverseDataIfNeeded:value]; - NSArray *binaryArray = [[SILCharacteristicFieldValueResolver sharedResolver] binaryArrayFromValue:value forFormat:self.fieldModel.format]; + self.binaryArray = [[SILCharacteristicFieldValueResolver sharedResolver] binaryArrayFromValue:value forFormat:self.fieldModel.format]; - if (self.bit.index < binaryArray.count) { - NSNumber *binaryValue = binaryArray[self.bit.index]; + if (self.bit.index < self.binaryArray.count) { + NSNumber *binaryValue = self.binaryArray[self.bit.index]; for (SILBluetoothEnumerationModel *enumerationModel in self.bit.enumerations) { if (enumerationModel.key == [binaryValue integerValue]) { self.toggleState = binaryValue; diff --git a/SiliconLabsApp/Redesign/MainNavigationView.swift b/SiliconLabsApp/Redesign/MainNavigationView.swift index 4fad6e95..2acf694a 100644 --- a/SiliconLabsApp/Redesign/MainNavigationView.swift +++ b/SiliconLabsApp/Redesign/MainNavigationView.swift @@ -6,7 +6,6 @@ // import SwiftUI -import CoreData struct MainNavigationView: View { @State var pickedTag = 2 @@ -54,18 +53,3 @@ struct MainNavigationView_Previews: PreviewProvider { MainNavigationView() } } - - - - - - - - - - - - - - - diff --git a/SiliconLabsApp/Redesign/PickerTabView.swift b/SiliconLabsApp/Redesign/PickerTabView.swift index 313d192a..d884de7d 100644 --- a/SiliconLabsApp/Redesign/PickerTabView.swift +++ b/SiliconLabsApp/Redesign/PickerTabView.swift @@ -8,6 +8,7 @@ import SwiftUI import Combine +import Introspect struct PickerTabView: View { @State var pickerTagChosen = 0 @@ -54,8 +55,11 @@ struct PickerTabView: View { } } } - - }) + }).introspectTabBarController { uiTabBarController in + uiTabBarController.setTabBarVisible(visible: floatingButtonSetting.isPresented, + animated: true, + controllerHeight: floatingButtonSetting.controllerHeight) + } } } @@ -77,6 +81,7 @@ protocol PickerTabSubview : View { var text: String = "" var isPresented: Bool = false var color : UIColor = .sil_regularBlue() + @IBOutlet weak var controllerHeight: NSLayoutConstraint? @objc func setButtonText(_ text: String) { if text != self.text { diff --git a/SiliconLabsApp/Storyboards/DevelopApps/SILAppAdvertiser.storyboard b/SiliconLabsApp/Storyboards/DevelopApps/SILAppAdvertiser.storyboard index 3d8f8dd8..9a14d051 100644 --- a/SiliconLabsApp/Storyboards/DevelopApps/SILAppAdvertiser.storyboard +++ b/SiliconLabsApp/Storyboards/DevelopApps/SILAppAdvertiser.storyboard @@ -1,9 +1,9 @@ - + - + @@ -21,19 +21,19 @@ - + - + - + - + @@ -208,7 +208,7 @@ - + @@ -248,7 +248,7 @@ - + @@ -256,6 +256,7 @@ + diff --git a/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard b/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard index 48107dc8..08d134e2 100644 --- a/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard +++ b/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard @@ -31,25 +31,25 @@ - + - + - + - + - + - + - + @@ -424,7 +424,7 @@ - + @@ -499,16 +499,17 @@ - - - - + + + + + @@ -573,7 +574,7 @@ - + @@ -610,7 +611,7 @@ - + @@ -620,6 +621,7 @@ + diff --git a/SiliconLabsApp/Storyboards/DevelopApps/SILAppGATTConfigurator.storyboard b/SiliconLabsApp/Storyboards/DevelopApps/SILAppGATTConfigurator.storyboard index 73e4b38e..38f7430b 100644 --- a/SiliconLabsApp/Storyboards/DevelopApps/SILAppGATTConfigurator.storyboard +++ b/SiliconLabsApp/Storyboards/DevelopApps/SILAppGATTConfigurator.storyboard @@ -1,9 +1,9 @@ - + - + @@ -30,13 +30,13 @@ - + - + - + @@ -230,7 +230,7 @@ - + @@ -295,7 +295,7 @@ - + @@ -318,7 +318,7 @@ - + @@ -386,7 +386,7 @@ - + @@ -394,6 +394,7 @@ + diff --git a/SiliconLabsApp/ViewControllers/Advertiser/Home/SILAdvertiserHomeViewController.swift b/SiliconLabsApp/ViewControllers/Advertiser/Home/SILAdvertiserHomeViewController.swift index 7a21577a..a3416df0 100644 --- a/SiliconLabsApp/ViewControllers/Advertiser/Home/SILAdvertiserHomeViewController.swift +++ b/SiliconLabsApp/ViewControllers/Advertiser/Home/SILAdvertiserHomeViewController.swift @@ -12,6 +12,7 @@ class SILAdvertiserHomeViewController: UIViewController, SILAdvertiserHomeViewDe @IBOutlet weak var allSpace: UIStackView! @IBOutlet weak var tableView: UITableView! @IBOutlet weak var noAdvertisersView: UIView! + @IBOutlet weak var controllerHeight: NSLayoutConstraint! var viewModel: SILAdvertiserHomeViewModel! var dataSource: [SILAdvertiserCellViewModel] = [] @@ -21,12 +22,10 @@ class SILAdvertiserHomeViewController: UIViewController, SILAdvertiserHomeViewDe guard let self = self else { return } self.floatingButtonSettings?.setPresented(false) self.viewModel.isActiveScrollingUp = true - self.navigationController?.tabBarController?.hideTabBarAndUpdateFrames() }, onShowUIElements: { [weak self] in guard let self = self else { return } self.floatingButtonSettings?.setPresented(true) self.viewModel.isActiveScrollingUp = false - self.navigationController?.tabBarController?.showTabBarAndUpdateFrames() }) override func viewDidLoad() { @@ -39,8 +38,8 @@ class SILAdvertiserHomeViewController: UIViewController, SILAdvertiserHomeViewDe override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.floatingButtonSettings?.setPresented(true) + self.floatingButtonSettings?.controllerHeight = self.controllerHeight self.viewModel.isActiveScrollingUp = false - self.navigationController?.tabBarController?.showTabBarAndUpdateFrames() } fileprivate func setupTableView() { diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Connections/SILBrowserConnectionsViewController.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Connections/SILBrowserConnectionsViewController.m index 92cf35cc..16440b81 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Connections/SILBrowserConnectionsViewController.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Connections/SILBrowserConnectionsViewController.m @@ -17,6 +17,7 @@ @interface SILBrowserConnectionsViewController () @property (weak, nonatomic) IBOutlet UITableView *connectionsTableView; @property (weak, nonatomic) IBOutlet UIView *emptyView; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *controllerHeight; @property (strong, nonatomic) SILBrowserConnectionsViewModel* viewModel; @property (nonatomic, weak) FloatingButtonSettings *floatingButtonSettings; @property (nonatomic, strong) SILUIScrollViewDelegate *uiScrollViewDelegate; @@ -38,7 +39,6 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.floatingButtonSettings setPresented:YES]; self.viewModel.isActiveScrollingUp = NO; - [self.navigationController.tabBarController showTabBarAndUpdateFrames]; } - (void)disconnectAllTapped { @@ -62,11 +62,9 @@ - (void)setupScrollViewBehaviour { self.uiScrollViewDelegate = [[SILUIScrollViewDelegate alloc] initOnHideUIElements:^(void) { [weakSelf.floatingButtonSettings setPresented:NO]; weakSelf.viewModel.isActiveScrollingUp = YES; - [weakSelf.navigationController.tabBarController hideTabBarAndUpdateFrames]; } onShowUIElements:^(void) { [weakSelf.floatingButtonSettings setPresented:YES]; weakSelf.viewModel.isActiveScrollingUp = NO; - [weakSelf.navigationController.tabBarController showTabBarAndUpdateFrames]; }]; } @@ -146,6 +144,7 @@ - (void)presentDetailsViewControllerWithPeripheral:(CBPeripheral *)peripheral { - (void)setupFloatingButtonSettings:(FloatingButtonSettings *)settings { self.floatingButtonSettings = settings; + self.floatingButtonSettings.controllerHeight = self.controllerHeight; [self.floatingButtonSettings setButtonText:@"Disconnect All"]; [self.floatingButtonSettings setPresented:!self.viewModel.isActiveScrollingUp]; [self.floatingButtonSettings setColor:[UIColor sil_regularBlueColor]]; diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m index 218ce656..caf6d871 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m @@ -26,6 +26,7 @@ @interface SILBluetoothBrowserViewController () @property (weak, nonatomic) IBOutlet UIImageView *noDevicesFoundImageView; @property (weak, nonatomic) IBOutlet UIStackView *noDevicesFoundStackView; @property (weak, nonatomic) IBOutlet UILabel *noDevicesFoundLabel; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *controllerHeight; @property (strong, nonatomic) SILBrowserViewModel *browserViewModel; @property (nonatomic, weak) FloatingButtonSettings *floatingButtonSettings; @@ -95,11 +96,9 @@ - (void)setupViewModelAndTableManagers { SILUIScrollViewDelegate *uiScrollViewDelegate = [[SILUIScrollViewDelegate alloc] initOnHideUIElements:^(void) { [weakSelf.floatingButtonSettings setPresented:NO]; weakSelf.browserViewModel.isActiveScrollingUp = YES; - [weakSelf.navigationController.tabBarController hideTabBarAndUpdateFrames]; } onShowUIElements:^(void) { [weakSelf.floatingButtonSettings setPresented:YES]; weakSelf.browserViewModel.isActiveScrollingUp = NO; - [weakSelf.navigationController.tabBarController showTabBarAndUpdateFrames]; }]; self.tableDelegate = [SILBrowserTableViewDelegate.alloc initWithBrowserViewModel:self.browserViewModel @@ -213,6 +212,7 @@ - (void)clearAndReloadTable { - (void)setupFloatingButtonSettings:(FloatingButtonSettings *)settings { self.floatingButtonSettings = settings; + self.floatingButtonSettings.controllerHeight = self.controllerHeight; [self setScanningAppearance]; } diff --git a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m index 3b9d9a44..11677c41 100644 --- a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m +++ b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m @@ -383,6 +383,17 @@ - (CGFloat)heightForRowAtIndexPath:(NSIndexPath *)indexPath { if ([model isKindOfClass:[SILEncodingPseudoFieldRowModel class]]) { return 132.0; } + if ([model isKindOfClass:[SILBitRowModel class]]) { + SILBitRowModel* modelCharacteristic = (SILBitRowModel*)model; + CGFloat tableHeight = 0.0; + + CGSize size = CGSizeMake(self.tableView.bounds.size.width - 120, CGFLOAT_MAX); + CGRect rect = [[modelCharacteristic primaryTitle] boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil]; + tableHeight += ceil(rect.size.height); + + return 60.0 + tableHeight; + } + return 81.0; } } diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/Model/Commands/SILESLCommandConnect.swift b/SiliconLabsApp/ViewControllers/ESLDemo/Model/Commands/SILESLCommandConnect.swift index 67847c2e..a625d818 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/Model/Commands/SILESLCommandConnect.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/Model/Commands/SILESLCommandConnect.swift @@ -15,29 +15,44 @@ class SILESLCommandConnect: SILESLCommand { let name = "connect" let opcode: UInt8 = 0 - private let address: SILAddress - private let passcode: String? + private let address: SILAddress? + private let qrData: [UInt8]? + + var dataToSend: [UInt8] { + get { + if let qrData = qrData { + return qrData + } else { + let command = getFullCommand() + return command.bytes + } + } + } - init(address: SILAddress, passcode: String? = nil) { + init(qrData: [UInt8]) { + self.qrData = qrData + self.address = nil + } + + init(address: SILAddress) { self.address = address - self.passcode = passcode + self.qrData = nil } func getFullCommand() -> String { + guard let address = address else { + return "" + } + var command = name command.append(" ") command.append(address.rawValue) - + if case .btAddress(let address) = address, address.addressType != .public { command.append(" ") command.append(address.addressType.rawValue) } - - if let passcode = passcode { - command.append(" ") - command.append(passcode) - } - + return command } } diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/Model/Processes/SILESLProvisioningTag.swift b/SiliconLabsApp/ViewControllers/ESLDemo/Model/Processes/SILESLProvisioningTag.swift index b900a5b2..f75b23d2 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/Model/Processes/SILESLProvisioningTag.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/Model/Processes/SILESLProvisioningTag.swift @@ -19,33 +19,29 @@ class SILESLProvisioningTag: NSObject, SILESLCommandRunner { private let peripheral: CBPeripheral private var peripheralReferences: SILESLPeripheralGATTReferences private let commandRunnerFactory: SILESLCommandRunnerFactory - private let address: SILBluetoothAddress - private var passcode: String? + private let qrData: [UInt8] private var timeout: TimeInterval! = 0.0 private var currentRunningCommand: (any SILESLCommandRunner)? var commandResult: PublishRelay> = PublishRelay() private var disposeBag = DisposeBag() - private var eslAddress: SILESLIdAddress? + var eslAddress: SILESLIdAddress? private var imageIndex: UInt? init(peripheral: CBPeripheral, peripheralReferences: SILESLPeripheralGATTReferences, commandRunnerFactory: SILESLCommandRunnerFactory, - address: SILBluetoothAddress, - passcode: String? = nil) { + qrData: [UInt8]) { self.peripheral = peripheral self.peripheralReferences = peripheralReferences self.commandRunnerFactory = commandRunnerFactory - self.address = address - self.passcode = passcode + self.qrData = qrData super.init() } func perform(timeout: TimeInterval) { let connect = commandRunnerFactory.createCommandConnectRunner(peripheral: peripheral, peripheralReferences: peripheralReferences, - address: .btAddress(address), - passcode: passcode) + qrData: qrData) currentRunningCommand = connect self.timeout = timeout connect.commandResult.asObservable().subscribe(onNext: { [weak self] result in @@ -95,7 +91,6 @@ class SILESLProvisioningTag: NSObject, SILESLCommandRunner { imageIndex: imageIndex, imageFile: imageFile) currentRunningCommand = imageUpdate - self.eslAddress = address imageUpdate.commandResult.asObservable().subscribe(onNext: { [weak self] result in @@ -107,7 +102,7 @@ class SILESLProvisioningTag: NSObject, SILESLCommandRunner { case .success: if let imageUpdateCommand = imageUpdateCommand { let requestData = imageUpdateCommand.getRequestData() - self.imageIndex = imageUpdateCommand.getRequestData().imageIndex + self.imageIndex = requestData.imageIndex self.commandResult.accept(.success(.processInProgressDisplayImage(address: address, imageIndex: Int(requestData.imageIndex), imageFile: requestData.imageFile))) self.disconnectConnectedTag(showImageAfterUpdate: showImageAfterUpdate) } diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/Model/SILESLCommandRunnerFactory.swift b/SiliconLabsApp/ViewControllers/ESLDemo/Model/SILESLCommandRunnerFactory.swift index c71a9065..1d0944c1 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/Model/SILESLCommandRunnerFactory.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/Model/SILESLCommandRunnerFactory.swift @@ -13,13 +13,11 @@ class SILESLCommandRunnerFactory { func createCommandProvisioning(peripheral: CBPeripheral, peripheralReferences: SILESLPeripheralGATTReferences, commandRunnerFactory: SILESLCommandRunnerFactory, - address: SILBluetoothAddress, - passcode: String? = nil) -> SILESLProvisioningTag { + qrData: [UInt8]) -> SILESLProvisioningTag { return SILESLProvisioningTag(peripheral: peripheral, peripheralReferences: peripheralReferences, commandRunnerFactory: commandRunnerFactory, - address: address, - passcode: passcode) + qrData: qrData) } func createCommandImageUpdate(peripheral: CBPeripheral, @@ -40,13 +38,19 @@ class SILESLCommandRunnerFactory { func createCommandConnectRunner(peripheral: CBPeripheral, peripheralReferences: SILESLPeripheralGATTReferences, - address: SILAddress, - passcode: String? = nil) -> SILESLCommandConnectRunner { - let connectCommand = SILESLCommandConnect(address: address, - passcode: passcode) - return SILESLCommandConnectRunner(peripheral: peripheral, - peripheralReferences: peripheralReferences, - command: connectCommand) + qrData: [UInt8]? = nil, + address: SILAddress? = nil) -> SILESLCommandConnectRunner { + if let qrData = qrData { + let connectCommand = SILESLCommandConnect(qrData: qrData) + return SILESLCommandConnectRunner(peripheral: peripheral, + peripheralReferences: peripheralReferences, + command: connectCommand) + } else { + let connectCommand = SILESLCommandConnect(address: address!) + return SILESLCommandConnectRunner(peripheral: peripheral, + peripheralReferences: peripheralReferences, + command: connectCommand) + } } func createCommandDisconnectRunner(peripheral: CBPeripheral, diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/UI/QRScannerViewController.swift b/SiliconLabsApp/ViewControllers/ESLDemo/UI/QRScannerViewController.swift index 46624f08..33a6cb1a 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/UI/QRScannerViewController.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/UI/QRScannerViewController.swift @@ -121,13 +121,12 @@ extension QRScannerViewController: AVCaptureMetadataOutputObjectsDelegate { if let barCodeObject = videoPreviewLayer.transformedMetadataObject(for: metadataObj) { qrCodeFrameView?.frame = barCodeObject.bounds } - - if let metadata = metadataObj.stringValue { - let qrData = viewModel.readQR(metadata: metadata) - delegate?.setQRData(qrData) - navigationController?.popViewController(animated: true) - dismiss(animated: true, completion: nil) - } + if let metadata = metadataObj.stringValue { + let qrData = viewModel.readQR(metadata: metadata) + delegate?.setQRData(qrData) + navigationController?.popViewController(animated: true) + dismiss(animated: true, completion: nil) + } } } } diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/UI/SILESLDemoViewController.swift b/SiliconLabsApp/ViewControllers/ESLDemo/UI/SILESLDemoViewController.swift index f9175e63..783c6fbe 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/UI/SILESLDemoViewController.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/UI/SILESLDemoViewController.swift @@ -14,7 +14,7 @@ import SVProgressHUD import WYPopoverController protocol QRMetadataDelegate: class { - func setQRData(_ qrData: ESLQRData?) + func setQRData(_ data: ESLQRData?) } class SILESLDemoViewController: UIViewController, UIGestureRecognizerDelegate, UITableViewDelegate, UITableViewDataSource, QRMetadataDelegate, UIDocumentPickerDelegate, WYPopoverControllerDelegate { @@ -79,10 +79,10 @@ class SILESLDemoViewController: UIViewController, UIGestureRecognizerDelegate, U } } - func setQRData(_ qrData: ESLQRData?) { - if let qrData = qrData { + func setQRData(_ data: ESLQRData?) { + if let qrData = data { if !viewModel.tagWithAddressIsProvisioned(qrData.bluetoothAddress) { - viewModel.provisionTag(with: qrData.bluetoothAddress, passcode: qrData.passcode) + viewModel.provisionTag(with: qrData.rawData) } else { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.alertWithOKButton(title: "Error", message: "Tag is already provisioned") diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/QRScannerViewModel.swift b/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/QRScannerViewModel.swift index 8ee6971c..1ba21795 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/QRScannerViewModel.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/QRScannerViewModel.swift @@ -10,28 +10,23 @@ import Foundation struct ESLQRData { let bluetoothAddress: SILBluetoothAddress - let passcode: String? + let rawData: [UInt8] } class QRScannerViewModel { func readQR(metadata: String) -> ESLQRData? { let words = split(metadata: metadata) - guard words.count <= 4 && words.count >= 2 else { + guard let btAddress = words.first(where: { word in word.count == 17 }) else { return nil } - - guard startedFromConnect(words[0]) else { + + let bluetoothAddress = SILBluetoothAddress(address: btAddress, addressType: .public) + guard bluetoothAddress.isValid else { return nil } - if words.count == 2 { - return decodeWords(words, addressType: .public, passcode: nil) - } else if words.count == 3 { - return decodeWords(words, passcode: nil) - } else { - return decodeWords(words) - } + return ESLQRData(bluetoothAddress: bluetoothAddress, rawData: metadata.bytes) } private func split(metadata: String) -> [String] { @@ -44,32 +39,4 @@ class QRScannerViewModel { return strings } - - private func startedFromConnect(_ word: String) -> Bool { - return word == "connect" - } - - private func decodeWords(_ words: [String], - addressType: SILBluetoothAddressType, - passcode: String?) -> ESLQRData? { - let btAddress = SILBluetoothAddress(address: words[1], addressType: addressType) - - return btAddress.isValid ? ESLQRData(bluetoothAddress: btAddress, passcode: passcode) : nil - } - - private func decodeWords(_ words: [String], - passcode: String?) -> ESLQRData? { - let btAddressType = SILBluetoothAddressType(rawValue: words[2]) - - guard let btAddressType = btAddressType else { - return nil - } - - return decodeWords(words, addressType: btAddressType, passcode: passcode) - } - - private func decodeWords(_ words: [String]) -> ESLQRData? { - let passcode = words[3] - return decodeWords(words, passcode: passcode) - } } diff --git a/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/SILESLDemoViewModel.swift b/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/SILESLDemoViewModel.swift index 47419b1a..e39a0e79 100644 --- a/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/SILESLDemoViewModel.swift +++ b/SiliconLabsApp/ViewControllers/ESLDemo/ViewModel/SILESLDemoViewModel.swift @@ -62,12 +62,11 @@ class SILESLDemoViewModel { } //MARK: Provisioning - func provisionTag(with address: SILBluetoothAddress, passcode: String? = nil) { + func provisionTag(with qrData: [UInt8]) { let provisioningTag = commandRunnerFactory.createCommandProvisioning(peripheral: peripheral, peripheralReferences: peripheralReferences, commandRunnerFactory: commandRunnerFactory, - address: address, - passcode: passcode) + qrData: qrData) currentRunningCommand = provisioningTag provisioningTag.commandResult.asObservable().subscribe(onNext: { [weak self] result in diff --git a/SiliconLabsApp/ViewControllers/GattConfigurator/Home/SILGattConfiguratorHomeViewController.swift b/SiliconLabsApp/ViewControllers/GattConfigurator/Home/SILGattConfiguratorHomeViewController.swift index b9b5588a..d85bd651 100644 --- a/SiliconLabsApp/ViewControllers/GattConfigurator/Home/SILGattConfiguratorHomeViewController.swift +++ b/SiliconLabsApp/ViewControllers/GattConfigurator/Home/SILGattConfiguratorHomeViewController.swift @@ -21,6 +21,7 @@ class SILGattConfiguratorHomeViewController: UIViewController, UITableViewDataSo @IBOutlet weak var exportCheckBoxTableViewWidthConstraint: NSLayoutConstraint! @IBOutlet weak var exportButton: SILPrimaryButton! @IBOutlet weak var cancelExportButton: SILPrimaryButton! + @IBOutlet weak var controllerHeight: NSLayoutConstraint! var viewModel: SILGattConfiguratorHomeViewModel! var dataSource: [SILGattConfiguratorCellViewModel] = [] @@ -33,12 +34,10 @@ class SILGattConfiguratorHomeViewController: UIViewController, UITableViewDataSo guard let self = self else { return } self.floatingButtonSettings?.setPresented(false) self.viewModel.isActiveScrollingUp = true - self.navigationController?.tabBarController?.hideTabBarAndUpdateFrames() }, onShowUIElements: { [weak self] in guard let self = self else { return } self.floatingButtonSettings?.setPresented(true) self.viewModel.isActiveScrollingUp = false - self.navigationController?.tabBarController?.showTabBarAndUpdateFrames() }) override func viewDidLoad() { @@ -54,7 +53,6 @@ class SILGattConfiguratorHomeViewController: UIViewController, UITableViewDataSo super.viewWillAppear(animated) self.floatingButtonSettings?.setPresented(true) self.viewModel.isActiveScrollingUp = false - self.navigationController?.tabBarController?.showTabBarAndUpdateFrames() } override func viewDidDisappear(_ animated: Bool) { @@ -70,6 +68,7 @@ class SILGattConfiguratorHomeViewController: UIViewController, UITableViewDataSo func setupFloatingButton(_ settings: FloatingButtonSettings) { floatingButtonSettings = settings + floatingButtonSettings?.controllerHeight = controllerHeight floatingButtonSettings?.setButtonText("Create New") floatingButtonSettings?.setPresented(!viewModel.isExportModeTurnOn && !viewModel.isActiveScrollingUp) } diff --git a/SiliconLabsApp/ViewControllers/SILDebugCharacteristicToggleFieldTableViewCell.xib b/SiliconLabsApp/ViewControllers/SILDebugCharacteristicToggleFieldTableViewCell.xib index bc5c7701..2b09091d 100644 --- a/SiliconLabsApp/ViewControllers/SILDebugCharacteristicToggleFieldTableViewCell.xib +++ b/SiliconLabsApp/ViewControllers/SILDebugCharacteristicToggleFieldTableViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -23,8 +23,8 @@ -