From be8577a6100fd99903c4994d12fea585bd33ff4c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 19 Apr 2022 22:56:59 -0700 Subject: [PATCH] Kill the CarBode! --- Meshtastic Client.xcodeproj/project.pbxproj | 29 +--- .../xcshareddata/swiftpm/Package.resolved | 17 +-- MeshtasticClient/Helpers/BLEManager.swift | 17 +-- MeshtasticClient/Info.plist | 2 + .../contents | 16 +-- MeshtasticClient/Protobufs/mesh.pb.swift | 78 +++++++++- MeshtasticClient/Views/Helpers/QRCamera.swift | 133 ------------------ MeshtasticClient/Views/Nodes/NodeDetail.swift | 3 +- .../Views/Settings/ShareChannel.swift | 95 ++++++++----- 9 files changed, 158 insertions(+), 232 deletions(-) delete mode 100644 MeshtasticClient/Views/Helpers/QRCamera.swift diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index eaeaeda9..bc7af150 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -25,9 +25,7 @@ DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; }; DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; }; DD539502276DAA6A00AD86B1 /* MapLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD539501276DAA6A00AD86B1 /* MapLocation.swift */; }; - DD6B85A62800915B000ACD6B /* CarBode in Frameworks */ = {isa = PBXBuildFile; productRef = DD6B85A52800915B000ACD6B /* CarBode */; }; DD6B85A828009258000ACD6B /* ShareChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B85A728009258000ACD6B /* ShareChannel.swift */; }; - DD6B85AA2800DFE5000ACD6B /* QRCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B85A92800DFE5000ACD6B /* QRCamera.swift */; }; DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */; }; DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */; }; DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FE272476C700F4AB02 /* LogDocument.swift */; }; @@ -95,7 +93,6 @@ DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = ""; }; DD539501276DAA6A00AD86B1 /* MapLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLocation.swift; sourceTree = ""; }; DD6B85A728009258000ACD6B /* ShareChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareChannel.swift; sourceTree = ""; }; - DD6B85A92800DFE5000ACD6B /* QRCamera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCamera.swift; sourceTree = ""; }; DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLogger.swift; sourceTree = ""; }; DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = ""; }; DD8169FE272476C700F4AB02 /* LogDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDocument.swift; sourceTree = ""; }; @@ -140,7 +137,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DD6B85A62800915B000ACD6B /* CarBode in Frameworks */, C9697FA527933B8C00250207 /* SQLite in Frameworks */, DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */, ); @@ -350,7 +346,6 @@ DD47E3D826F3093800029299 /* MessageBubble.swift */, DD90860B26F684AF00DC5189 /* BatteryIcon.swift */, DDF924C926FBB953009FE055 /* ConnectedDevice.swift */, - DD6B85A92800DFE5000ACD6B /* QRCamera.swift */, ); path = Helpers; sourceTree = ""; @@ -396,7 +391,6 @@ packageProductDependencies = ( DD5394FB276993AD00AD86B1 /* SwiftProtobuf */, C9697FA427933B8C00250207 /* SQLite */, - DD6B85A52800915B000ACD6B /* CarBode */, ); productName = MeshtasticClient; productReference = DDC2E15426CE248E0042C5E4 /* MeshtasticClient.app */; @@ -473,7 +467,6 @@ packageReferences = ( DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */, C9697FA327933B8C00250207 /* XCRemoteSwiftPackageReference "SQLite.swift" */, - DD6B85A42800915B000ACD6B /* XCRemoteSwiftPackageReference "CarBode-Barcode-Scanner-For-SwiftUI" */, ); productRefGroup = DDC2E15526CE248E0042C5E4 /* Products */; projectDirPath = ""; @@ -539,7 +532,6 @@ files = ( DD4DED9027AD2975004BA27E /* cannedmessages.pb.swift in Sources */, DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */, - DD6B85AA2800DFE5000ACD6B /* QRCamera.swift in Sources */, DDAF8C6E26ED19040058C060 /* Extensions.swift in Sources */, DDC2E1A726CEB3400042C5E4 /* LocationHelper.swift in Sources */, DDAF8C5F26ED09B50058C060 /* radioconfig.pb.swift in Sources */, @@ -743,7 +735,7 @@ CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\""; DEVELOPMENT_TEAM = GCH7VS5Y9R; ENABLE_PREVIEWS = YES; @@ -754,7 +746,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.53; + MARKETING_VERSION = 1.3.1; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -775,7 +767,7 @@ CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\""; DEVELOPMENT_TEAM = GCH7VS5Y9R; ENABLE_PREVIEWS = YES; @@ -786,7 +778,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.53; + MARKETING_VERSION = 1.3.1; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -940,14 +932,6 @@ minimumVersion = 1.0.0; }; }; - DD6B85A42800915B000ACD6B /* XCRemoteSwiftPackageReference "CarBode-Barcode-Scanner-For-SwiftUI" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/heart/CarBode-Barcode-Scanner-For-SwiftUI"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -961,11 +945,6 @@ package = DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */; productName = SwiftProtobuf; }; - DD6B85A52800915B000ACD6B /* CarBode */ = { - isa = XCSwiftPackageProductDependency; - package = DD6B85A42800915B000ACD6B /* XCRemoteSwiftPackageReference "CarBode-Barcode-Scanner-For-SwiftUI" */; - productName = CarBode; - }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/Meshtastic Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Meshtastic Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 94cdf5f2..55b7b56c 100644 --- a/Meshtastic Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Meshtastic Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,22 +1,13 @@ { "object": { "pins": [ - { - "package": "CarBode", - "repositoryURL": "https://github.com/heart/CarBode-Barcode-Scanner-For-SwiftUI", - "state": { - "branch": null, - "revision": "6167624ec47174900434f1c03dfa0b2dd5d19c0d", - "version": "2.2.3" - } - }, { "package": "SQLite.swift", "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git", "state": { "branch": null, - "revision": "60a65015f6402b7c34b9a924f755ca0a73afeeaa", - "version": "0.13.1" + "revision": "4d543d811ee644fa4cc4bfa0be996b4dd6ba0f54", + "version": "0.13.3" } }, { @@ -24,8 +15,8 @@ "repositoryURL": "https://github.com/apple/swift-protobuf.git", "state": { "branch": null, - "revision": "7e2c5f3cbbeea68e004915e3a8961e20bd11d824", - "version": "1.18.0" + "revision": "e1499bc69b9040b29184f7f2996f7bab467c1639", + "version": "1.19.0" } } ] diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 7d21920f..29e471d2 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -523,11 +523,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if decodedInfo.nodeInfo.hasDeviceMetrics { - newNode.batteryLevel = Int32(decodedInfo.nodeInfo.deviceMetrics.batteryLevel) - newNode.voltage = decodedInfo.nodeInfo.deviceMetrics.voltage - newNode.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization - self.connectedPeripheral.channelUtilization = newNode.channelUtilization - newNode.airUtilTx = decodedInfo.nodeInfo.deviceMetrics.airUtilTx + let newTelemetry = TelemetryEntity(context: context!) + + newTelemetry.batteryLevel = Int32(decodedInfo.nodeInfo.deviceMetrics.batteryLevel) + newTelemetry.voltage = decodedInfo.nodeInfo.deviceMetrics.voltage + newTelemetry.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization + self.connectedPeripheral.channelUtilization = newTelemetry.channelUtilization + newTelemetry.airUtilTx = decodedInfo.nodeInfo.deviceMetrics.airUtilTx self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx } @@ -988,7 +990,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if let telemetryMessage = try? Telemetry(serializedData: decodedInfo.packet.decoded.payload) { let telemetry = TelemetryEntity(context: context!) - telemetry.num = Int64(decodedInfo.packet.from) print(decodedInfo.packet.decoded.requestID) print(telemetryMessage) } @@ -1178,6 +1179,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph do { let fetchedNode = try context?.fetch(fetchNode) as! [NodeInfoEntity] + if fetchedNode.count == 1 { @@ -1207,10 +1209,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph print("📍 Sent a Position Packet from the phone to the device for node: \(fromNodeNum)") if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { + connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) - success = true - } } diff --git a/MeshtasticClient/Info.plist b/MeshtasticClient/Info.plist index 1a7b3ab5..ea9d0da6 100644 --- a/MeshtasticClient/Info.plist +++ b/MeshtasticClient/Info.plist @@ -45,6 +45,8 @@ We use bluetooth to connect to nearby Meshtastic Devices NSBluetoothPeripheralUsageDescription Bluetooth is used to connect an iPhone to a user's meshtastic device to allow text messaging and location data for the mesh network. + NSCameraUsageDescription + We use the camera to share channels using a QR Code NSLocationUsageDescription We use your location to display it on the mesh map as well as to have GPS coordinatess to send to the connected device. NSLocationWhenInUseUsageDescription diff --git a/MeshtasticClient/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents b/MeshtasticClient/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents index 6205af2a..a5ab71a8 100644 --- a/MeshtasticClient/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents +++ b/MeshtasticClient/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents @@ -24,6 +24,7 @@ + @@ -31,6 +32,7 @@ + @@ -39,15 +41,11 @@ - - - - @@ -67,10 +65,12 @@ + + + - @@ -94,10 +94,10 @@ - - + + - + \ No newline at end of file diff --git a/MeshtasticClient/Protobufs/mesh.pb.swift b/MeshtasticClient/Protobufs/mesh.pb.swift index ed36b55d..7876eb12 100644 --- a/MeshtasticClient/Protobufs/mesh.pb.swift +++ b/MeshtasticClient/Protobufs/mesh.pb.swift @@ -1171,9 +1171,27 @@ struct DataMessage { /// Formerly named typ and of type Type var portnum: PortNum = .unknownApp + var payloadVariant: DataMessage.OneOf_PayloadVariant? = nil + /// /// TODO: REPLACE - var payload: Data = Data() + var payload: Data { + get { + if case .payload(let v)? = payloadVariant {return v} + return Data() + } + set {payloadVariant = .payload(newValue)} + } + + /// + /// TODO: REPLACE + var payloadCompressed: Data { + get { + if case .payloadCompressed(let v)? = payloadVariant {return v} + return Data() + } + set {payloadVariant = .payloadCompressed(newValue)} + } /// /// Not normally used, but for testing a sender can request that recipient @@ -1222,6 +1240,34 @@ struct DataMessage { var unknownFields = SwiftProtobuf.UnknownStorage() + enum OneOf_PayloadVariant: Equatable { + /// + /// TODO: REPLACE + case payload(Data) + /// + /// TODO: REPLACE + case payloadCompressed(Data) + + #if !swift(>=4.1) + static func ==(lhs: DataMessage.OneOf_PayloadVariant, rhs: DataMessage.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.payload, .payload): return { + guard case .payload(let l) = lhs, case .payload(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.payloadCompressed, .payloadCompressed): return { + guard case .payloadCompressed(let l) = lhs, case .payloadCompressed(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif + } + init() {} fileprivate var _location: Location? = nil @@ -2266,6 +2312,7 @@ extension Routing: @unchecked Sendable {} extension Routing.OneOf_Variant: @unchecked Sendable {} extension Routing.Error: @unchecked Sendable {} extension DataMessage: @unchecked Sendable {} +extension DataMessage.OneOf_PayloadVariant: @unchecked Sendable {} extension Location: @unchecked Sendable {} extension MeshPacket: @unchecked Sendable {} extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} @@ -2830,6 +2877,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "portnum"), 2: .same(proto: "payload"), + 10: .standard(proto: "payload_compressed"), 3: .standard(proto: "want_response"), 4: .same(proto: "dest"), 5: .same(proto: "source"), @@ -2846,7 +2894,14 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.portnum) }() - case 2: try { try decoder.decodeSingularBytesField(value: &self.payload) }() + case 2: try { + var v: Data? + try decoder.decodeSingularBytesField(value: &v) + if let v = v { + if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} + self.payloadVariant = .payload(v) + } + }() case 3: try { try decoder.decodeSingularBoolField(value: &self.wantResponse) }() case 4: try { try decoder.decodeSingularFixed32Field(value: &self.dest) }() case 5: try { try decoder.decodeSingularFixed32Field(value: &self.source) }() @@ -2854,6 +2909,14 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati case 7: try { try decoder.decodeSingularFixed32Field(value: &self.replyID) }() case 8: try { try decoder.decodeSingularFixed32Field(value: &self.emoji) }() case 9: try { try decoder.decodeSingularMessageField(value: &self._location) }() + case 10: try { + var v: Data? + try decoder.decodeSingularBytesField(value: &v) + if let v = v { + if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} + self.payloadVariant = .payloadCompressed(v) + } + }() default: break } } @@ -2867,9 +2930,9 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if self.portnum != .unknownApp { try visitor.visitSingularEnumField(value: self.portnum, fieldNumber: 1) } - if !self.payload.isEmpty { - try visitor.visitSingularBytesField(value: self.payload, fieldNumber: 2) - } + try { if case .payload(let v)? = self.payloadVariant { + try visitor.visitSingularBytesField(value: v, fieldNumber: 2) + } }() if self.wantResponse != false { try visitor.visitSingularBoolField(value: self.wantResponse, fieldNumber: 3) } @@ -2891,12 +2954,15 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati try { if let v = self._location { try visitor.visitSingularMessageField(value: v, fieldNumber: 9) } }() + try { if case .payloadCompressed(let v)? = self.payloadVariant { + try visitor.visitSingularBytesField(value: v, fieldNumber: 10) + } }() try unknownFields.traverse(visitor: &visitor) } static func ==(lhs: DataMessage, rhs: DataMessage) -> Bool { if lhs.portnum != rhs.portnum {return false} - if lhs.payload != rhs.payload {return false} + if lhs.payloadVariant != rhs.payloadVariant {return false} if lhs.wantResponse != rhs.wantResponse {return false} if lhs.dest != rhs.dest {return false} if lhs.source != rhs.source {return false} diff --git a/MeshtasticClient/Views/Helpers/QRCamera.swift b/MeshtasticClient/Views/Helpers/QRCamera.swift deleted file mode 100644 index 050a5d10..00000000 --- a/MeshtasticClient/Views/Helpers/QRCamera.swift +++ /dev/null @@ -1,133 +0,0 @@ -// -// QRCamera.swift -// MeshtasticClient -// -// Created by Garth Vander Houwen on 4/8/22. -// - -import SwiftUI -import CarBode -import AVFoundation - -struct cameraFrame: Shape { - func path(in rect: CGRect) -> Path { - Path { path in - let width = rect.width - let height = rect.height - - path.addLines( [ - - CGPoint(x: 0, y: height * 0.25), - CGPoint(x: 0, y: 0), - CGPoint(x:width * 0.25, y:0) - ]) - - path.addLines( [ - - CGPoint(x: width * 0.75, y: 0), - CGPoint(x: width, y: 0), - CGPoint(x:width, y:height * 0.25) - ]) - - path.addLines( [ - - CGPoint(x: width, y: height * 0.75), - CGPoint(x: width, y: height), - CGPoint(x:width * 0.75, y: height) - ]) - - path.addLines( [ - - CGPoint(x:width * 0.25, y: height), - CGPoint(x:0, y: height), - CGPoint(x:0, y:height * 0.75) - - ]) - - } - } -} - -struct QRCamera: View { - @State var barcodeValue = "" - @State var torchIsOn = false - @State var showingAlert = false - @State var cameraPosition = AVCaptureDevice.Position.back - - var body: some View { - VStack { - Text("QRCode Scanner") - - Spacer() - - if cameraPosition == .back{ - Text("Using back camera") - }else{ - Text("Using front camera") - } - - Button(action: { - if cameraPosition == .back { - cameraPosition = .front - }else{ - cameraPosition = .back - } - }) { - if cameraPosition == .back{ - Text("Switch Camera to Front") - }else{ - Text("Switch Camera to Back") - } - } - - - Button(action: { - self.torchIsOn.toggle() - }) { - Text("Toggle Torch Light") - } - - Spacer() - - CBScanner( - supportBarcode: .constant([.qr, .code128]), - torchLightIsOn: $torchIsOn, - cameraPosition: $cameraPosition, - mockBarCode: .constant(BarcodeData(value:"My Test Data", type: .qr)) - ){ - print("BarCodeType =",$0.type.rawValue, "Value =",$0.value) - barcodeValue = $0.value - } - onDraw: { - print("Preview View Size = \($0.cameraPreviewView.bounds)") - print("Barcode Corners = \($0.corners)") - - let lineColor = UIColor.green - let fillColor = UIColor(red: 0, green: 1, blue: 0.2, alpha: 0.4) - //Draw Barcode corner - $0.draw(lineWidth: 1, lineColor: lineColor, fillColor: fillColor) - - }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 400, maxHeight: 400, alignment: .topLeading) - .overlay(cameraFrame() - .stroke(lineWidth: 5) - .frame(width: 500, height: 250) - .foregroundColor(.blue)) - - Spacer() - - Text(barcodeValue) - - Spacer() - - }.alert(isPresented: $showingAlert) { - Alert(title: Text("Found Barcode"), message: Text("\(barcodeValue)"), dismissButton: .default(Text("Close"))) - } - } -} - -struct ModalScannerView_Previews: PreviewProvider { - static var previews: some View { - QRCamera() - } -} - diff --git a/MeshtasticClient/Views/Nodes/NodeDetail.swift b/MeshtasticClient/Views/Nodes/NodeDetail.swift index a6d96931..6bd11342 100644 --- a/MeshtasticClient/Views/Nodes/NodeDetail.swift +++ b/MeshtasticClient/Views/Nodes/NodeDetail.swift @@ -104,7 +104,8 @@ struct NodeDetail: View { } } .padding(5) - + + if node.snr > 0 { Divider() VStack(alignment: .center) { diff --git a/MeshtasticClient/Views/Settings/ShareChannel.swift b/MeshtasticClient/Views/Settings/ShareChannel.swift index e734b454..352ab6af 100644 --- a/MeshtasticClient/Views/Settings/ShareChannel.swift +++ b/MeshtasticClient/Views/Settings/ShareChannel.swift @@ -6,69 +6,88 @@ // import SwiftUI import CoreData -import CarBode +import CoreImage.CIFilterBuiltins +struct QrCodeImage { + let context = CIContext() + + func generateQRCode(from text: String) -> UIImage { + var qrImage = UIImage(systemName: "xmark.circle") ?? UIImage() + let data = Data(text.utf8) + let filter = CIFilter.qrCodeGenerator() + filter.setValue(data, forKey: "inputMessage") + + let transform = CGAffineTransform(scaleX: 15, y: 15) + if let outputImage = filter.outputImage?.transformed(by: transform) { + if let image = context.createCGImage( + outputImage, + from: outputImage.extent) { + qrImage = UIImage(cgImage: image) + } + } + return qrImage + } +} + struct ShareChannel: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager @EnvironmentObject var userSettings: UserSettings - - - @State var dataString = "Hello Carbode" - @State var barcodeType = CBBarcodeView.BarcodeType.qrCode - @State var rotate = CBBarcodeView.Orientation.up - - @State var barcodeImage: UIImage? - + + @State private var text = "meshtastic.org" + var qrCodeImage = QrCodeImage() + var body: some View { - - HStack { + + VStack { GeometryReader { bounds in + let smallest = min(bounds.size.width, bounds.size.height) + ScrollView { - - VStack { - - let smallest = min(bounds.size.width, bounds.size.height) - Text("Channel Name").font(.largeTitle) - CBBarcodeView(data: $dataString, - barcodeType: $barcodeType, - orientation: $rotate) - { image in - self.barcodeImage = image - }.frame( + VStack { + Text("Scan the QR code below with the Apple or Android device you would like to share with your channel settings with.") + .fixedSize(horizontal: false, vertical: true) + .font(.callout) + .padding() + Spacer() + + let image = qrCodeImage.generateQRCode(from: text) + Image(uiImage: image) + .resizable() + .scaledToFit() + .frame( minWidth: smallest * 0.9, maxWidth: smallest * 0.9, minHeight: smallest * 0.9, maxHeight: smallest * 0.9, - alignment: .topLeading + alignment: .center ) - .padding(.bottom) - Text("Channel Details").font(.title) - - Text("Some helpful text about how this whole thing works goes here, also could add a share sheet icon and pass the link around.") Spacer() - Text("Some helpful text about how this whole thing works goes here, also could add a share sheet icon and pass the link around.") + Text("Channel Name (Long/Slow)").font(.title) + Spacer() } + .frame(width: bounds.size.width, height: bounds.size.height) } - }.padding() - } - .navigationTitle("Share Channel") - .navigationBarTitleDisplayMode(.inline) - .navigationBarItems(trailing: + } + .navigationTitle("Share Channel") + .navigationBarTitleDisplayMode(.automatic) + .navigationBarItems(trailing: - ZStack { + ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") - }) - .onAppear { + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") + }) + .onAppear { - self.bleManager.context = context + self.bleManager.context = context + } + } .navigationViewStyle(StackNavigationViewStyle()) }