From 57268576c482e77746bb59319279b60f38500057 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 24 Feb 2023 08:46:26 -0800 Subject: [PATCH] New protos, widget scaffolding --- Meshtastic.xcodeproj/project.pbxproj | 190 +++++++++++++++++- Meshtastic/Helpers/BLEManager.swift | 16 +- .../Protobufs/meshtastic/config.pb.swift | 9 + Meshtastic/Protobufs/meshtastic/mesh.pb.swift | 12 ++ .../meshtastic/module_config.pb.swift | 21 ++ .../Views/Map/Custom/MapViewSwiftUI.swift | 10 + Meshtastic/Views/Settings/AppSettings.swift | 6 +- .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 ++ .../Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + MeshtasticWidgets/Info.plist | 11 + .../MeshtasticWidgets.intentdefinition | 59 ++++++ MeshtasticWidgets/MeshtasticWidgets.swift | 68 +++++++ .../MeshtasticWidgetsBundle.swift | 17 ++ .../MeshtasticWidgetsLiveActivity.swift | 77 +++++++ MeshtasticWidgetsExtension.entitlements | 10 + 17 files changed, 537 insertions(+), 10 deletions(-) create mode 100644 MeshtasticWidgets/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 MeshtasticWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 MeshtasticWidgets/Assets.xcassets/Contents.json create mode 100644 MeshtasticWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 MeshtasticWidgets/Info.plist create mode 100644 MeshtasticWidgets/MeshtasticWidgets.intentdefinition create mode 100644 MeshtasticWidgets/MeshtasticWidgets.swift create mode 100644 MeshtasticWidgets/MeshtasticWidgetsBundle.swift create mode 100644 MeshtasticWidgets/MeshtasticWidgetsLiveActivity.swift create mode 100644 MeshtasticWidgetsExtension.entitlements diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 2a4d8eb4..cf6091d0 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -35,6 +35,15 @@ DD47E3CE26F103C600029299 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CD26F103C600029299 /* NodeList.swift */; }; DD47E3D626F17ED900029299 /* CircleText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D526F17ED900029299 /* CircleText.swift */; }; DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911D2708C65400501B7E /* AppSettings.swift */; }; + DD4C0EFA29A8735400D3316C /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD4C0EF929A8735400D3316C /* WidgetKit.framework */; }; + DD4C0EFC29A8735400D3316C /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD4C0EFB29A8735400D3316C /* SwiftUI.framework */; }; + DD4C0EFF29A8735400D3316C /* MeshtasticWidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4C0EFE29A8735400D3316C /* MeshtasticWidgetsBundle.swift */; }; + DD4C0F0129A8735400D3316C /* MeshtasticWidgetsLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4C0F0029A8735400D3316C /* MeshtasticWidgetsLiveActivity.swift */; }; + DD4C0F0329A8735400D3316C /* MeshtasticWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4C0F0229A8735400D3316C /* MeshtasticWidgets.swift */; }; + DD4C0F0629A8735500D3316C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DD4C0F0529A8735500D3316C /* Assets.xcassets */; }; + DD4C0F0829A8735500D3316C /* MeshtasticWidgets.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DD4C0F0429A8735400D3316C /* MeshtasticWidgets.intentdefinition */; }; + DD4C0F0929A8735500D3316C /* MeshtasticWidgets.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DD4C0F0429A8735400D3316C /* MeshtasticWidgets.intentdefinition */; }; + DD4C0F0C29A8735500D3316C /* MeshtasticWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DD4C0EF829A8735400D3316C /* MeshtasticWidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; DD4F23CD28779A3C001D37CB /* EnvironmentMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */; }; DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; }; DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; }; @@ -119,6 +128,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + DD4C0F0A29A8735500D3316C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDC2E14C26CE248E0042C5E4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DD4C0EF729A8735400D3316C; + remoteInfo = MeshtasticWidgetsExtension; + }; DDC2E16B26CE248F0042C5E4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DDC2E14C26CE248E0042C5E4 /* Project object */; @@ -135,6 +151,20 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + DD4C0F1129A8735600D3316C /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + DD4C0F0C29A8735500D3316C /* MeshtasticWidgetsExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ A65FA974296876BF00A97686 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalMBTileOverlay.swift; sourceTree = ""; }; @@ -165,6 +195,16 @@ DD47E3CD26F103C600029299 /* NodeList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeList.swift; sourceTree = ""; }; DD47E3D526F17ED900029299 /* CircleText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleText.swift; sourceTree = ""; }; DD4A911D2708C65400501B7E /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = ""; }; + DD4C0EF829A8735400D3316C /* MeshtasticWidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = MeshtasticWidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + DD4C0EF929A8735400D3316C /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + DD4C0EFB29A8735400D3316C /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + DD4C0EFE29A8735400D3316C /* MeshtasticWidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticWidgetsBundle.swift; sourceTree = ""; }; + DD4C0F0029A8735400D3316C /* MeshtasticWidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticWidgetsLiveActivity.swift; sourceTree = ""; }; + DD4C0F0229A8735400D3316C /* MeshtasticWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticWidgets.swift; sourceTree = ""; }; + DD4C0F0429A8735400D3316C /* MeshtasticWidgets.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = MeshtasticWidgets.intentdefinition; sourceTree = ""; }; + DD4C0F0529A8735500D3316C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + DD4C0F0729A8735500D3316C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DD4C0F0D29A8735500D3316C /* MeshtasticWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MeshtasticWidgetsExtension.entitlements; sourceTree = ""; }; DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentMetricsLog.swift; sourceTree = ""; }; DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = ""; }; DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelEntityExtension.swift; sourceTree = ""; }; @@ -262,6 +302,15 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + DD4C0EF529A8735400D3316C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DD4C0EFC29A8735400D3316C /* SwiftUI.framework in Frameworks */, + DD4C0EFA29A8735400D3316C /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DDC2E15126CE248E0042C5E4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -348,6 +397,19 @@ path = Settings; sourceTree = ""; }; + DD4C0EFD29A8735400D3316C /* MeshtasticWidgets */ = { + isa = PBXGroup; + children = ( + DD4C0EFE29A8735400D3316C /* MeshtasticWidgetsBundle.swift */, + DD4C0F0029A8735400D3316C /* MeshtasticWidgetsLiveActivity.swift */, + DD4C0F0229A8735400D3316C /* MeshtasticWidgets.swift */, + DD4C0F0429A8735400D3316C /* MeshtasticWidgets.intentdefinition */, + DD4C0F0529A8735500D3316C /* Assets.xcassets */, + DD4C0F0729A8735500D3316C /* Info.plist */, + ); + path = MeshtasticWidgets; + sourceTree = ""; + }; DD5E51EF298EE33B00D21B61 /* meshtastic */ = { isa = PBXGroup; children = ( @@ -442,6 +504,8 @@ DD8EDE9226F97A2B00A5A10B /* Frameworks */ = { isa = PBXGroup; children = ( + DD4C0EF929A8735400D3316C /* WidgetKit.framework */, + DD4C0EFB29A8735400D3316C /* SwiftUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -457,11 +521,13 @@ DDC2E14B26CE248E0042C5E4 = { isa = PBXGroup; children = ( + DD4C0F0D29A8735500D3316C /* MeshtasticWidgetsExtension.entitlements */, DDCDC6CD29481FCC004C1DDA /* Localizable.strings */, DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */, DDC2E15626CE248E0042C5E4 /* Meshtastic */, DDC2E16D26CE248F0042C5E4 /* MeshtasticTests */, DDC2E17826CE248F0042C5E4 /* MeshtasticUITests */, + DD4C0EFD29A8735400D3316C /* MeshtasticWidgets */, DDC2E15526CE248E0042C5E4 /* Products */, DD8EDE9226F97A2B00A5A10B /* Frameworks */, ); @@ -474,6 +540,7 @@ DDC2E15426CE248E0042C5E4 /* Meshtastic.app */, DDC2E16A26CE248F0042C5E4 /* MeshtasticTests.xctest */, DDC2E17526CE248F0042C5E4 /* MeshtasticUITests.xctest */, + DD4C0EF829A8735400D3316C /* MeshtasticWidgetsExtension.appex */, ); name = Products; sourceTree = ""; @@ -612,6 +679,23 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + DD4C0EF729A8735400D3316C /* MeshtasticWidgetsExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = DD4C0F0E29A8735600D3316C /* Build configuration list for PBXNativeTarget "MeshtasticWidgetsExtension" */; + buildPhases = ( + DD4C0EF429A8735400D3316C /* Sources */, + DD4C0EF529A8735400D3316C /* Frameworks */, + DD4C0EF629A8735400D3316C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MeshtasticWidgetsExtension; + productName = MeshtasticWidgetsExtension; + productReference = DD4C0EF829A8735400D3316C /* MeshtasticWidgetsExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; DDC2E15326CE248E0042C5E4 /* Meshtastic */ = { isa = PBXNativeTarget; buildConfigurationList = DDC2E17E26CE248F0042C5E4 /* Build configuration list for PBXNativeTarget "Meshtastic" */; @@ -620,10 +704,12 @@ DDC2E15126CE248E0042C5E4 /* Frameworks */, DDC2E15226CE248E0042C5E4 /* Resources */, BB450974275599CE00509624 /* ShellScript */, + DD4C0F1129A8735600D3316C /* Embed Foundation Extensions */, ); buildRules = ( ); dependencies = ( + DD4C0F0B29A8735500D3316C /* PBXTargetDependency */, ); name = Meshtastic; packageProductDependencies = ( @@ -676,9 +762,12 @@ DDC2E14C26CE248E0042C5E4 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1250; + LastSwiftUpdateCheck = 1420; LastUpgradeCheck = 1250; TargetAttributes = { + DD4C0EF729A8735400D3316C = { + CreatedOnToolsVersion = 14.2; + }; DDC2E15326CE248E0042C5E4 = { CreatedOnToolsVersion = 12.5.1; LastSwiftMigration = 1340; @@ -716,11 +805,20 @@ DDC2E15326CE248E0042C5E4 /* Meshtastic */, DDC2E16926CE248F0042C5E4 /* MeshtasticTests */, DDC2E17426CE248F0042C5E4 /* MeshtasticUITests */, + DD4C0EF729A8735400D3316C /* MeshtasticWidgetsExtension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + DD4C0EF629A8735400D3316C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DD4C0F0629A8735500D3316C /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DDC2E15226CE248E0042C5E4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -768,6 +866,17 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + DD4C0EF429A8735400D3316C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DD4C0EFF29A8735400D3316C /* MeshtasticWidgetsBundle.swift in Sources */, + DD4C0F0129A8735400D3316C /* MeshtasticWidgetsLiveActivity.swift in Sources */, + DD4C0F0329A8735400D3316C /* MeshtasticWidgets.swift in Sources */, + DD4C0F0829A8735500D3316C /* MeshtasticWidgets.intentdefinition in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DDC2E15026CE248E0042C5E4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -780,6 +889,7 @@ DD5E523F298F5A9E00D21B61 /* AirQualityIndexCompact.swift in Sources */, DD964FBF296E76EF007C176F /* WaypointFormView.swift in Sources */, DD3501892852FC3B000FC853 /* Settings.swift in Sources */, + DD4C0F0929A8735500D3316C /* MeshtasticWidgets.intentdefinition in Sources */, DD5D0A9C2931B9F200F7EA61 /* EthernetModes.swift in Sources */, DD5E5203298EE33B00D21B61 /* config.pb.swift in Sources */, DD798B072915928D005217CD /* ChannelMessageList.swift in Sources */, @@ -896,6 +1006,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + DD4C0F0B29A8735500D3316C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DD4C0EF729A8735400D3316C /* MeshtasticWidgetsExtension */; + targetProxy = DD4C0F0A29A8735500D3316C /* PBXContainerItemProxy */; + }; DDC2E16C26CE248F0042C5E4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DDC2E15326CE248E0042C5E4 /* Meshtastic */; @@ -922,6 +1037,68 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + DD4C0F0F29A8735600D3316C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = MeshtasticWidgetsExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GCH7VS5Y9R; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = MeshtasticWidgets/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = MeshtasticWidgets; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.MeshtasticWidgets; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + DD4C0F1029A8735600D3316C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = MeshtasticWidgetsExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = GCH7VS5Y9R; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = MeshtasticWidgets/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = MeshtasticWidgets; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.MeshtasticWidgets; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; DDC2E17C26CE248F0042C5E4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1045,6 +1222,7 @@ DDC2E17F26CE248F0042C5E4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; @@ -1078,6 +1256,7 @@ DDC2E18026CE248F0042C5E4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; @@ -1199,6 +1378,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + DD4C0F0E29A8735600D3316C /* Build configuration list for PBXNativeTarget "MeshtasticWidgetsExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DD4C0F0F29A8735600D3316C /* Debug */, + DD4C0F1029A8735600D3316C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DDC2E14F26CE248E0042C5E4 /* Build configuration list for PBXProject "Meshtastic" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 1082a22b..3e03a89f 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -62,8 +62,8 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { self.lastConnectionError = "" self.connectedVersion = "0.0.0" super.init() - centralManager = CBCentralManager(delegate: self, queue: nil) - //centralManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionRestoreIdentifierKey: restoreKey]) + //centralManager = CBCentralManager(delegate: self, queue: nil) + centralManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionRestoreIdentifierKey: restoreKey]) } // MARK: Scanning for BLE Devices @@ -2016,14 +2016,14 @@ extension BLEManager: CBCentralManagerDelegate { guard let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] else { return } - print(peripherals) + if peripherals.count > 0 { //connectedPeripheral.peripheral = peripherals[0] // 5 //connectedPeripheral.peripheral.delegate = self - + for peripheral in peripherals { - + print(peripheral) switch peripheral.state { case .connecting: // I've only seen this happen when // re-launching attached to Xcode. @@ -2031,6 +2031,12 @@ extension BLEManager: CBCentralManagerDelegate { case .connected: // Store for connection / requesting // notifications when BT starts. + disconnectPeripheral(reconnect: true) + if connectedPeripheral?.peripheral != nil { + self.sendWantConfig() + } else { + disconnectPeripheral(reconnect: true) + } print("Actual restore") //centralManager.connect(peripheral) default: break diff --git a/Meshtastic/Protobufs/meshtastic/config.pb.swift b/Meshtastic/Protobufs/meshtastic/config.pb.swift index c6bfb474..580fd84e 100644 --- a/Meshtastic/Protobufs/meshtastic/config.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/config.pb.swift @@ -215,6 +215,11 @@ struct Config { /// Tracker device role /// Position Mesh packets will be prioritized higher and sent more frequently by default. case tracker // = 5 + + /// + /// Sensor device role + /// Telemetry Mesh packets will be prioritized higher and sent more frequently by default. + case sensor // = 6 case UNRECOGNIZED(Int) init() { @@ -229,6 +234,7 @@ struct Config { case 3: self = .routerClient case 4: self = .repeater case 5: self = .tracker + case 6: self = .sensor default: self = .UNRECOGNIZED(rawValue) } } @@ -241,6 +247,7 @@ struct Config { case .routerClient: return 3 case .repeater: return 4 case .tracker: return 5 + case .sensor: return 6 case .UNRECOGNIZED(let i): return i } } @@ -1245,6 +1252,7 @@ extension Config.DeviceConfig.Role: CaseIterable { .routerClient, .repeater, .tracker, + .sensor, ] } @@ -1633,6 +1641,7 @@ extension Config.DeviceConfig.Role: SwiftProtobuf._ProtoNameProviding { 3: .same(proto: "ROUTER_CLIENT"), 4: .same(proto: "REPEATER"), 5: .same(proto: "TRACKER"), + 6: .same(proto: "SENSOR"), ] } diff --git a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift index 12b53077..7fa22878 100644 --- a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift @@ -98,12 +98,18 @@ enum HardwareModel: SwiftProtobuf.Enum { /// TODO: REPLACE case tloraT3S3 // = 16 + /// + /// B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer + case nanoG1Explorer // = 17 + /// /// B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station case stationG1 // = 25 /// + /// --------------------------------------------------------------------------- /// Less common/prototype boards listed here (needs one more byte over the air) + /// --------------------------------------------------------------------------- case loraRelayV1 // = 32 /// @@ -163,7 +169,9 @@ enum HardwareModel: SwiftProtobuf.Enum { case betafpv900NanoTx // = 46 /// + /// ------------------------------------------------------------------------------------------------------------------------------------------ /// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. + /// ------------------------------------------------------------------------------------------------------------------------------------------ case privateHw // = 255 case UNRECOGNIZED(Int) @@ -190,6 +198,7 @@ enum HardwareModel: SwiftProtobuf.Enum { case 14: self = .nanoG1 case 15: self = .tloraV211P8 case 16: self = .tloraT3S3 + case 17: self = .nanoG1Explorer case 25: self = .stationG1 case 32: self = .loraRelayV1 case 33: self = .nrf52840Dk @@ -230,6 +239,7 @@ enum HardwareModel: SwiftProtobuf.Enum { case .nanoG1: return 14 case .tloraV211P8: return 15 case .tloraT3S3: return 16 + case .nanoG1Explorer: return 17 case .stationG1: return 25 case .loraRelayV1: return 32 case .nrf52840Dk: return 33 @@ -275,6 +285,7 @@ extension HardwareModel: CaseIterable { .nanoG1, .tloraV211P8, .tloraT3S3, + .nanoG1Explorer, .stationG1, .loraRelayV1, .nrf52840Dk, @@ -2318,6 +2329,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 14: .same(proto: "NANO_G1"), 15: .same(proto: "TLORA_V2_1_1P8"), 16: .same(proto: "TLORA_T3_S3"), + 17: .same(proto: "NANO_G1_EXPLORER"), 25: .same(proto: "STATION_G1"), 32: .same(proto: "LORA_RELAY_V1"), 33: .same(proto: "NRF52840DK"), diff --git a/Meshtastic/Protobufs/meshtastic/module_config.pb.swift b/Meshtastic/Protobufs/meshtastic/module_config.pb.swift index 9d5c41e1..914b5f9f 100644 --- a/Meshtastic/Protobufs/meshtastic/module_config.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/module_config.pb.swift @@ -669,6 +669,15 @@ struct ModuleConfig { /// display the results in Fahrenheit as a "user preference". var environmentDisplayFahrenheit: Bool = false + /// + /// Enable/Disable the air quality metrics + var airQualityEnabled: Bool = false + + /// + /// Interval in seconds of how often we should try to send our + /// air quality metrics to the mesh + var airQualityInterval: UInt32 = 0 + var unknownFields = SwiftProtobuf.UnknownStorage() init() {} @@ -1584,6 +1593,8 @@ extension ModuleConfig.TelemetryConfig: SwiftProtobuf.Message, SwiftProtobuf._Me 3: .standard(proto: "environment_measurement_enabled"), 4: .standard(proto: "environment_screen_enabled"), 5: .standard(proto: "environment_display_fahrenheit"), + 6: .standard(proto: "air_quality_enabled"), + 7: .standard(proto: "air_quality_interval"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1597,6 +1608,8 @@ extension ModuleConfig.TelemetryConfig: SwiftProtobuf.Message, SwiftProtobuf._Me case 3: try { try decoder.decodeSingularBoolField(value: &self.environmentMeasurementEnabled) }() case 4: try { try decoder.decodeSingularBoolField(value: &self.environmentScreenEnabled) }() case 5: try { try decoder.decodeSingularBoolField(value: &self.environmentDisplayFahrenheit) }() + case 6: try { try decoder.decodeSingularBoolField(value: &self.airQualityEnabled) }() + case 7: try { try decoder.decodeSingularUInt32Field(value: &self.airQualityInterval) }() default: break } } @@ -1618,6 +1631,12 @@ extension ModuleConfig.TelemetryConfig: SwiftProtobuf.Message, SwiftProtobuf._Me if self.environmentDisplayFahrenheit != false { try visitor.visitSingularBoolField(value: self.environmentDisplayFahrenheit, fieldNumber: 5) } + if self.airQualityEnabled != false { + try visitor.visitSingularBoolField(value: self.airQualityEnabled, fieldNumber: 6) + } + if self.airQualityInterval != 0 { + try visitor.visitSingularUInt32Field(value: self.airQualityInterval, fieldNumber: 7) + } try unknownFields.traverse(visitor: &visitor) } @@ -1627,6 +1646,8 @@ extension ModuleConfig.TelemetryConfig: SwiftProtobuf.Message, SwiftProtobuf._Me if lhs.environmentMeasurementEnabled != rhs.environmentMeasurementEnabled {return false} if lhs.environmentScreenEnabled != rhs.environmentScreenEnabled {return false} if lhs.environmentDisplayFahrenheit != rhs.environmentDisplayFahrenheit {return false} + if lhs.airQualityEnabled != rhs.airQualityEnabled {return false} + if lhs.airQualityInterval != rhs.airQualityInterval {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift index 55f707a2..6c1060e5 100644 --- a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift +++ b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift @@ -80,6 +80,7 @@ struct MapViewSwiftUI: UIViewRepresentable { compassButton.translatesAutoresizingMaskIntoConstraints = false compassButton.trailingAnchor.constraint(equalTo: mapView.trailingAnchor, constant: -5).isActive = true compassButton.bottomAnchor.constraint(equalTo: mapView.bottomAnchor, constant: -25).isActive = true + #endif #endif mapView.delegate = context.coordinator @@ -132,6 +133,15 @@ struct MapViewSwiftUI: UIViewRepresentable { mapView.showsUserLocation = true mapView.setUserTrackingMode(.followWithHeading, animated: true) if recenter { + // create a 3D Camera + let mapCamera = MKMapCamera() + mapCamera.centerCoordinate = LocationHelper.currentLocation + mapCamera.pitch = 45 + mapCamera.altitude = 500 // example altitude + mapCamera.heading = 45 + + // set the camera property + mapView.camera = mapCamera mapView.centerCoordinate = LocationHelper.currentLocation } } diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index 6802a1ff..4605eda1 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -60,7 +60,7 @@ struct AppSettings: View { } } - Section(header: Text("global map options")) { + Section(header: Text("map options")) { Picker("map.type", selection: $userSettings.meshMapType) { ForEach(MeshMapType.allCases) { map in @@ -68,9 +68,7 @@ struct AppSettings: View { } } .pickerStyle(DefaultPickerStyle()) - } - - Section(header: Text("mesh map options")) { + Picker("map.centering", selection: $userSettings.meshMapCenteringMode) { ForEach(CenteringMode.allCases) { cm in Text(cm.description) diff --git a/MeshtasticWidgets/Assets.xcassets/AccentColor.colorset/Contents.json b/MeshtasticWidgets/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/MeshtasticWidgets/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MeshtasticWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json b/MeshtasticWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..13613e3e --- /dev/null +++ b/MeshtasticWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MeshtasticWidgets/Assets.xcassets/Contents.json b/MeshtasticWidgets/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/MeshtasticWidgets/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MeshtasticWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json b/MeshtasticWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/MeshtasticWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MeshtasticWidgets/Info.plist b/MeshtasticWidgets/Info.plist new file mode 100644 index 00000000..0f118fb7 --- /dev/null +++ b/MeshtasticWidgets/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/MeshtasticWidgets/MeshtasticWidgets.intentdefinition b/MeshtasticWidgets/MeshtasticWidgets.intentdefinition new file mode 100644 index 00000000..bdb40455 --- /dev/null +++ b/MeshtasticWidgets/MeshtasticWidgets.intentdefinition @@ -0,0 +1,59 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + 88xZPY + INIntentDefinitionSystemVersion + 20A294 + INIntentDefinitionToolsBuildVersion + 12A6144 + INIntentDefinitionToolsVersion + 12.0 + INIntents + + + INIntentCategory + information + INIntentDescriptionID + tVvJ9c + INIntentEligibleForWidgets + + INIntentIneligibleForSuggestions + + INIntentName + Configuration + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + + INIntentTitle + Configuration + INIntentTitleID + gpCwrM + INIntentType + Custom + INIntentVerb + View + + + INTypes + + + diff --git a/MeshtasticWidgets/MeshtasticWidgets.swift b/MeshtasticWidgets/MeshtasticWidgets.swift new file mode 100644 index 00000000..4cc715ba --- /dev/null +++ b/MeshtasticWidgets/MeshtasticWidgets.swift @@ -0,0 +1,68 @@ +// +// MeshtasticWidgets.swift +// MeshtasticWidgets +// +// Created by Garth Vander Houwen on 2/23/23. +// + +import WidgetKit +import SwiftUI +import Intents + +struct Provider: IntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationIntent()) + } + + func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date(), configuration: configuration) + completion(entry) + } + + func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline) -> ()) { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate, configuration: configuration) + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationIntent +} + +struct MeshtasticWidgetsEntryView : View { + var entry: Provider.Entry + + var body: some View { + Text(entry.date, style: .time) + } +} + +struct MeshtasticWidgets: Widget { + let kind: String = "MeshtasticWidgets" + + var body: some WidgetConfiguration { + IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in + MeshtasticWidgetsEntryView(entry: entry) + } + .configurationDisplayName("My Widget") + .description("This is an example widget.") + } +} + +struct MeshtasticWidgets_Previews: PreviewProvider { + static var previews: some View { + MeshtasticWidgetsEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent())) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + } +} diff --git a/MeshtasticWidgets/MeshtasticWidgetsBundle.swift b/MeshtasticWidgets/MeshtasticWidgetsBundle.swift new file mode 100644 index 00000000..4fbfbb9e --- /dev/null +++ b/MeshtasticWidgets/MeshtasticWidgetsBundle.swift @@ -0,0 +1,17 @@ +// +// MeshtasticWidgetsBundle.swift +// MeshtasticWidgets +// +// Created by Garth Vander Houwen on 2/23/23. +// + +import WidgetKit +import SwiftUI + +@main +struct MeshtasticWidgetsBundle: WidgetBundle { + var body: some Widget { + MeshtasticWidgets() + MeshtasticWidgetsLiveActivity() + } +} diff --git a/MeshtasticWidgets/MeshtasticWidgetsLiveActivity.swift b/MeshtasticWidgets/MeshtasticWidgetsLiveActivity.swift new file mode 100644 index 00000000..f871023d --- /dev/null +++ b/MeshtasticWidgets/MeshtasticWidgetsLiveActivity.swift @@ -0,0 +1,77 @@ +// +// MeshtasticWidgetsLiveActivity.swift +// MeshtasticWidgets +// +// Created by Garth Vander Houwen on 2/23/23. +// + +import ActivityKit +import WidgetKit +import SwiftUI + +struct MeshtasticWidgetsAttributes: ActivityAttributes { + public struct ContentState: Codable, Hashable { + // Dynamic stateful properties about your activity go here! + var value: Int + } + + // Fixed non-changing properties about your activity go here! + var name: String +} + +struct MeshtasticWidgetsLiveActivity: Widget { + var body: some WidgetConfiguration { + ActivityConfiguration(for: MeshtasticWidgetsAttributes.self) { context in + // Lock screen/banner UI goes here + VStack { + Text("Hello") + } + .activityBackgroundTint(Color.cyan) + .activitySystemActionForegroundColor(Color.black) + + } dynamicIsland: { context in + DynamicIsland { + // Expanded UI goes here. Compose the expanded UI through + // various regions, like leading/trailing/center/bottom + DynamicIslandExpandedRegion(.leading) { + Text("Leading") + } + DynamicIslandExpandedRegion(.trailing) { + Text("Trailing") + } + DynamicIslandExpandedRegion(.bottom) { + Text("Bottom") + // more content + } + } compactLeading: { + Text("L") + } compactTrailing: { + Text("T") + } minimal: { + Text("Min") + } + .widgetURL(URL(string: "http://www.apple.com")) + .keylineTint(Color.red) + } + } +} + +struct MeshtasticWidgetsLiveActivity_Previews: PreviewProvider { + static let attributes = MeshtasticWidgetsAttributes(name: "Me") + static let contentState = MeshtasticWidgetsAttributes.ContentState(value: 3) + + static var previews: some View { + attributes + .previewContext(contentState, viewKind: .dynamicIsland(.compact)) + .previewDisplayName("Island Compact") + attributes + .previewContext(contentState, viewKind: .dynamicIsland(.expanded)) + .previewDisplayName("Island Expanded") + attributes + .previewContext(contentState, viewKind: .dynamicIsland(.minimal)) + .previewDisplayName("Minimal") + attributes + .previewContext(contentState, viewKind: .content) + .previewDisplayName("Notification") + } +} diff --git a/MeshtasticWidgetsExtension.entitlements b/MeshtasticWidgetsExtension.entitlements new file mode 100644 index 00000000..ee95ab7e --- /dev/null +++ b/MeshtasticWidgetsExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + +