mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Mesh Activity
This commit is contained in:
parent
9a4de51281
commit
4ca3cf89ab
16 changed files with 845 additions and 330 deletions
|
|
@ -32,8 +32,6 @@
|
|||
DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD415827285859C4009B0E59 /* TelemetryConfig.swift */; };
|
||||
DD41582A28585C32009B0E59 /* RangeTestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41582928585C32009B0E59 /* RangeTestConfig.swift */; };
|
||||
DD41A61529AB0035003C5A37 /* NodeWeatherForecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41A61429AB0035003C5A37 /* NodeWeatherForecast.swift */; };
|
||||
DD41A61D29AE7E8F003C5A37 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41A61C29AE7E8E003C5A37 /* WidgetKit.framework */; };
|
||||
DD41A61F29AE7E8F003C5A37 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41A61E29AE7E8F003C5A37 /* SwiftUI.framework */; };
|
||||
DD457188293C7E63000C49FB /* SignalStrengthIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD457187293C7E63000C49FB /* SignalStrengthIndicator.swift */; };
|
||||
DD47E3CE26F103C600029299 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CD26F103C600029299 /* NodeList.swift */; };
|
||||
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D526F17ED900029299 /* CircleText.swift */; };
|
||||
|
|
@ -116,6 +114,16 @@
|
|||
DDD3BBD5292D763200D609B3 /* MeshtasticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD3BBD4292D763200D609B3 /* MeshtasticTests.swift */; };
|
||||
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */; };
|
||||
DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */; };
|
||||
DDDE59F529AF163D00490C6C /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41A61C29AE7E8E003C5A37 /* WidgetKit.framework */; };
|
||||
DDDE59F629AF163D00490C6C /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41A61E29AE7E8F003C5A37 /* SwiftUI.framework */; };
|
||||
DDDE59F929AF163D00490C6C /* WidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE59F829AF163D00490C6C /* WidgetsBundle.swift */; };
|
||||
DDDE59FB29AF163D00490C6C /* WidgetsLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE59FA29AF163D00490C6C /* WidgetsLiveActivity.swift */; };
|
||||
DDDE59FD29AF163D00490C6C /* Widgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE59FC29AF163D00490C6C /* Widgets.swift */; };
|
||||
DDDE5A0329AF163E00490C6C /* WidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
DDDE5A1029AFE69700490C6C /* MeshActivityAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */; };
|
||||
DDDE5A1129AFE69700490C6C /* MeshActivityAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */; };
|
||||
DDDE5A1329AFEAB900490C6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDDE5A1229AFEAB900490C6C /* Assets.xcassets */; };
|
||||
DDDE5A1429AFEAB900490C6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDDE5A1229AFEAB900490C6C /* Assets.xcassets */; };
|
||||
DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */; };
|
||||
DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF924C926FBB953009FE055 /* ConnectedDevice.swift */; };
|
||||
DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */; };
|
||||
|
|
@ -136,8 +144,29 @@
|
|||
remoteGlobalIDString = DDC2E15326CE248E0042C5E4;
|
||||
remoteInfo = MeshtasticClient;
|
||||
};
|
||||
DDDE5A0129AF163E00490C6C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DDC2E14C26CE248E0042C5E4 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = DDDE59F329AF163D00490C6C;
|
||||
remoteInfo = WidgetsExtension;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
DDDE5A0829AF163F00490C6C /* Embed Foundation Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
DDDE5A0329AF163E00490C6C /* WidgetsExtension.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 = "<group>"; };
|
||||
C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalMBTileOverlay.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -164,7 +193,6 @@
|
|||
DD415827285859C4009B0E59 /* TelemetryConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryConfig.swift; sourceTree = "<group>"; };
|
||||
DD41582928585C32009B0E59 /* RangeTestConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RangeTestConfig.swift; sourceTree = "<group>"; };
|
||||
DD41A61429AB0035003C5A37 /* NodeWeatherForecast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeWeatherForecast.swift; sourceTree = "<group>"; };
|
||||
DD41A61B29AE7E8E003C5A37 /* WidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DD41A61C29AE7E8E003C5A37 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||
DD41A61E29AE7E8F003C5A37 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||
DD457187293C7E63000C49FB /* SignalStrengthIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalStrengthIndicator.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -262,6 +290,14 @@
|
|||
DDD3BBD4292D763200D609B3 /* MeshtasticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeshtasticTests.swift; sourceTree = "<group>"; };
|
||||
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = "<group>"; };
|
||||
DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = "<group>"; };
|
||||
DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DDDE59F829AF163D00490C6C /* WidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetsBundle.swift; sourceTree = "<group>"; };
|
||||
DDDE59FA29AF163D00490C6C /* WidgetsLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetsLiveActivity.swift; sourceTree = "<group>"; };
|
||||
DDDE59FC29AF163D00490C6C /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = "<group>"; };
|
||||
DDDE5A0029AF163E00490C6C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
DDDE5A0429AF163E00490C6C /* WidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetsExtension.entitlements; sourceTree = "<group>"; };
|
||||
DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshActivityAttributes.swift; sourceTree = "<group>"; };
|
||||
DDDE5A1229AFEAB900490C6C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsEnums.swift; sourceTree = "<group>"; };
|
||||
DDEE03EC29544A1000FCAD57 /* MeshtasticDataModelV4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV4.xcdatamodel; sourceTree = "<group>"; };
|
||||
DDF924C926FBB953009FE055 /* ConnectedDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectedDevice.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -269,15 +305,6 @@
|
|||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
DD41A61829AE7E8E003C5A37 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DD41A61F29AE7E8F003C5A37 /* SwiftUI.framework in Frameworks */,
|
||||
DD41A61D29AE7E8F003C5A37 /* WidgetKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DDC2E15126CE248E0042C5E4 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -301,6 +328,15 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DDDE59F129AF163D00490C6C /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDDE59F629AF163D00490C6C /* SwiftUI.framework in Frameworks */,
|
||||
DDDE59F529AF163D00490C6C /* WidgetKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
|
|
@ -476,11 +512,13 @@
|
|||
DDC2E14B26CE248E0042C5E4 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDDE5A0429AF163E00490C6C /* WidgetsExtension.entitlements */,
|
||||
DDCDC6CD29481FCC004C1DDA /* Localizable.strings */,
|
||||
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */,
|
||||
DDC2E15626CE248E0042C5E4 /* Meshtastic */,
|
||||
DDC2E16D26CE248F0042C5E4 /* MeshtasticTests */,
|
||||
DDC2E17826CE248F0042C5E4 /* MeshtasticUITests */,
|
||||
DDDE59F729AF163D00490C6C /* Widgets */,
|
||||
DDC2E15526CE248E0042C5E4 /* Products */,
|
||||
DD8EDE9226F97A2B00A5A10B /* Frameworks */,
|
||||
);
|
||||
|
|
@ -493,7 +531,7 @@
|
|||
DDC2E15426CE248E0042C5E4 /* Meshtastic.app */,
|
||||
DDC2E16A26CE248F0042C5E4 /* MeshtasticTests.xctest */,
|
||||
DDC2E17526CE248F0042C5E4 /* MeshtasticUITests.xctest */,
|
||||
DD41A61B29AE7E8E003C5A37 /* WidgetsExtension.appex */,
|
||||
DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -629,26 +667,22 @@
|
|||
path = Persistence;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDDE59F729AF163D00490C6C /* Widgets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDDE5A1229AFEAB900490C6C /* Assets.xcassets */,
|
||||
DDDE59F829AF163D00490C6C /* WidgetsBundle.swift */,
|
||||
DDDE59FA29AF163D00490C6C /* WidgetsLiveActivity.swift */,
|
||||
DDDE59FC29AF163D00490C6C /* Widgets.swift */,
|
||||
DDDE5A0029AF163E00490C6C /* Info.plist */,
|
||||
DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */,
|
||||
);
|
||||
path = Widgets;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
DD41A61A29AE7E8E003C5A37 /* WidgetsExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DD41A62A29AE7E91003C5A37 /* Build configuration list for PBXNativeTarget "WidgetsExtension" */;
|
||||
buildPhases = (
|
||||
DD41A61729AE7E8E003C5A37 /* Sources */,
|
||||
DD41A61829AE7E8E003C5A37 /* Frameworks */,
|
||||
DD41A61929AE7E8E003C5A37 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = WidgetsExtension;
|
||||
productName = WidgetsExtension;
|
||||
productReference = DD41A61B29AE7E8E003C5A37 /* WidgetsExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
DDC2E15326CE248E0042C5E4 /* Meshtastic */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DDC2E17E26CE248F0042C5E4 /* Build configuration list for PBXNativeTarget "Meshtastic" */;
|
||||
|
|
@ -657,10 +691,12 @@
|
|||
DDC2E15126CE248E0042C5E4 /* Frameworks */,
|
||||
DDC2E15226CE248E0042C5E4 /* Resources */,
|
||||
BB450974275599CE00509624 /* ShellScript */,
|
||||
DDDE5A0829AF163F00490C6C /* Embed Foundation Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
DDDE5A0229AF163E00490C6C /* PBXTargetDependency */,
|
||||
);
|
||||
name = Meshtastic;
|
||||
packageProductDependencies = (
|
||||
|
|
@ -707,6 +743,23 @@
|
|||
productReference = DDC2E17526CE248F0042C5E4 /* MeshtasticUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
DDDE59F329AF163D00490C6C /* WidgetsExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DDDE5A0529AF163F00490C6C /* Build configuration list for PBXNativeTarget "WidgetsExtension" */;
|
||||
buildPhases = (
|
||||
DDDE59F029AF163D00490C6C /* Sources */,
|
||||
DDDE59F129AF163D00490C6C /* Frameworks */,
|
||||
DDDE59F229AF163D00490C6C /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = WidgetsExtension;
|
||||
productName = WidgetsExtension;
|
||||
productReference = DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
|
|
@ -716,9 +769,6 @@
|
|||
LastSwiftUpdateCheck = 1420;
|
||||
LastUpgradeCheck = 1250;
|
||||
TargetAttributes = {
|
||||
DD41A61A29AE7E8E003C5A37 = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
};
|
||||
DDC2E15326CE248E0042C5E4 = {
|
||||
CreatedOnToolsVersion = 12.5.1;
|
||||
LastSwiftMigration = 1340;
|
||||
|
|
@ -732,6 +782,9 @@
|
|||
CreatedOnToolsVersion = 12.5.1;
|
||||
TestTargetID = DDC2E15326CE248E0042C5E4;
|
||||
};
|
||||
DDDE59F329AF163D00490C6C = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = DDC2E14F26CE248E0042C5E4 /* Build configuration list for PBXProject "Meshtastic" */;
|
||||
|
|
@ -756,25 +809,19 @@
|
|||
DDC2E15326CE248E0042C5E4 /* Meshtastic */,
|
||||
DDC2E16926CE248F0042C5E4 /* MeshtasticTests */,
|
||||
DDC2E17426CE248F0042C5E4 /* MeshtasticUITests */,
|
||||
DD41A61A29AE7E8E003C5A37 /* WidgetsExtension */,
|
||||
DDDE59F329AF163D00490C6C /* WidgetsExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
DD41A61929AE7E8E003C5A37 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DDC2E15226CE248E0042C5E4 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDC2E15F26CE248F0042C5E4 /* Preview Assets.xcassets in Resources */,
|
||||
DDCDC6CB29481FCC004C1DDA /* Localizable.strings in Resources */,
|
||||
DDDE5A1329AFEAB900490C6C /* Assets.xcassets in Resources */,
|
||||
DDC2E15C26CE248F0042C5E4 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -793,6 +840,14 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DDDE59F229AF163D00490C6C /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDDE5A1429AFEAB900490C6C /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
|
|
@ -816,13 +871,6 @@
|
|||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
DD41A61729AE7E8E003C5A37 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DDC2E15026CE248E0042C5E4 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -899,6 +947,7 @@
|
|||
DD8ED9C52898D51F00B3B0AB /* NetworkConfig.swift in Sources */,
|
||||
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
|
||||
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */,
|
||||
DDDE5A1029AFE69700490C6C /* MeshActivityAttributes.swift in Sources */,
|
||||
DD1925B928CDA93900720036 /* SerialConfigEnums.swift in Sources */,
|
||||
DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */,
|
||||
DD86D40F2881BE4C00BAEB7A /* CsvDocument.swift in Sources */,
|
||||
|
|
@ -949,6 +998,17 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DDDE59F029AF163D00490C6C /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDDE5A1129AFE69700490C6C /* MeshActivityAttributes.swift in Sources */,
|
||||
DDDE59FB29AF163D00490C6C /* WidgetsLiveActivity.swift in Sources */,
|
||||
DDDE59FD29AF163D00490C6C /* Widgets.swift in Sources */,
|
||||
DDDE59F929AF163D00490C6C /* WidgetsBundle.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
|
|
@ -962,6 +1022,11 @@
|
|||
target = DDC2E15326CE248E0042C5E4 /* Meshtastic */;
|
||||
targetProxy = DDC2E17626CE248F0042C5E4 /* PBXContainerItemProxy */;
|
||||
};
|
||||
DDDE5A0229AF163E00490C6C /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DDDE59F329AF163D00490C6C /* WidgetsExtension */;
|
||||
targetProxy = DDDE5A0129AF163E00490C6C /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
|
|
@ -978,64 +1043,6 @@
|
|||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
DD41A62B29AE7E91003C5A37 /* 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_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = GCH7VS5Y9R;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Widgets/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widgets;
|
||||
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.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DD41A62C29AE7E91003C5A37 /* 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_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = GCH7VS5Y9R;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Widgets/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widgets;
|
||||
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.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
DDC2E17C26CE248F0042C5E4 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
|
@ -1088,7 +1095,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
|
@ -1144,7 +1151,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
|
@ -1159,6 +1166,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;
|
||||
|
|
@ -1192,6 +1200,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;
|
||||
|
|
@ -1310,18 +1319,71 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
DDDE5A0629AF163F00490C6C /* 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 = WidgetsExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = GCH7VS5Y9R;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Widgets/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widgets;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DDDE5A0729AF163F00490C6C /* 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 = WidgetsExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = GCH7VS5Y9R;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Widgets/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widgets;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
DD41A62A29AE7E91003C5A37 /* Build configuration list for PBXNativeTarget "WidgetsExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DD41A62B29AE7E91003C5A37 /* Debug */,
|
||||
DD41A62C29AE7E91003C5A37 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
DDC2E14F26CE248E0042C5E4 /* Build configuration list for PBXProject "Meshtastic" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
@ -1358,6 +1420,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
DDDE5A0529AF163F00490C6C /* Build configuration list for PBXNativeTarget "WidgetsExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DDDE5A0629AF163F00490C6C /* Debug */,
|
||||
DDDE5A0729AF163F00490C6C /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@ import MapKit
|
|||
import CoreData
|
||||
import CoreLocation
|
||||
import CoreBluetooth
|
||||
#if canImport(ActivityKit)
|
||||
import ActivityKit
|
||||
#endif
|
||||
|
||||
struct Connect: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
|
@ -21,177 +24,196 @@ struct Connect: View {
|
|||
@State var isPreferredRadio: Bool = false
|
||||
@State var isUnsetRegion = false
|
||||
@State var invalidFirmwareVersion = false
|
||||
|
||||
var body: some View {
|
||||
@State var liveActivityStarted = false
|
||||
|
||||
var body: some View {
|
||||
|
||||
NavigationStack {
|
||||
VStack {
|
||||
List {
|
||||
if bleManager.isSwitchedOn {
|
||||
Section(header: Text("connected.radio").font(.title)) {
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.green)
|
||||
.padding(.trailing)
|
||||
VStack(alignment: .leading) {
|
||||
if node != nil {
|
||||
Text(bleManager.connectedPeripheral.longName).font(.title2)
|
||||
}
|
||||
Text("ble.name").font(.caption)+Text(": \(bleManager.connectedPeripheral.peripheral.name ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
.font(.caption).foregroundColor(Color.gray)
|
||||
if node != nil {
|
||||
Text("firmware.version").font(.caption)+Text(": \(node?.myInfo?.firmwareVersion ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
.font(.caption).foregroundColor(Color.gray)
|
||||
}
|
||||
if bleManager.isSubscribed {
|
||||
Text("subscribed").font(.caption)
|
||||
.foregroundColor(.green)
|
||||
} else {
|
||||
Text("communicating").font(.caption)
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
VStack(alignment: .center) {
|
||||
Text("preferred.radio").font(.caption2)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(width: 75)
|
||||
Toggle("preferred.radio", isOn: $bleManager.preferredPeripheral)
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.labelsHidden()
|
||||
.onChange(of: bleManager.preferredPeripheral) { value in
|
||||
if value {
|
||||
if bleManager.connectedPeripheral != nil {
|
||||
userSettings.preferredPeripheralId = bleManager.connectedPeripheral!.peripheral.identifier.uuidString
|
||||
userSettings.preferredNodeNum = bleManager.connectedPeripheral!.num
|
||||
bleManager.preferredPeripheral = true
|
||||
isPreferredRadio = true
|
||||
}
|
||||
} else {
|
||||
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.identifier.uuidString == userSettings.preferredPeripheralId {
|
||||
|
||||
userSettings.preferredPeripheralId = ""
|
||||
userSettings.preferredNodeNum = 0
|
||||
bleManager.preferredPeripheral = false
|
||||
isPreferredRadio = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.font(.caption).foregroundColor(Color.gray)
|
||||
.padding([.top, .bottom])
|
||||
.swipeActions {
|
||||
|
||||
Button(role: .destructive) {
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
isPreferredRadio = false
|
||||
}
|
||||
} label: {
|
||||
Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash")
|
||||
}
|
||||
}
|
||||
.contextMenu{
|
||||
|
||||
if node != nil {
|
||||
|
||||
Text("Num: \(String(node!.num))")
|
||||
Text("Short Name: \(node?.user?.shortName ?? "????")")
|
||||
Text("Long Name: \(node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
Text("Max Channels: \(String(node?.myInfo?.maxChannels ?? 0))")
|
||||
Text("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))")
|
||||
Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)")
|
||||
|
||||
}
|
||||
}
|
||||
if isUnsetRegion {
|
||||
HStack {
|
||||
NavigationLink {
|
||||
LoRaConfig(node: node)
|
||||
} label: {
|
||||
Label("set.region", systemImage: "globe.americas.fill")
|
||||
.foregroundColor(.red)
|
||||
.font(.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if bleManager.isConnecting {
|
||||
|
||||
Section(header: Text("connected.radio").font(.title)) {
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.orange)
|
||||
.imageScale(.large).foregroundColor(.green)
|
||||
.padding(.trailing)
|
||||
if bleManager.timeoutTimerCount == 0 {
|
||||
Text("connecting")
|
||||
.font(.title3)
|
||||
.foregroundColor(.orange)
|
||||
} else {
|
||||
VStack {
|
||||
|
||||
Text("Connection Attempt \(bleManager.timeoutTimerCount) of 10")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
VStack(alignment: .leading) {
|
||||
if node != nil {
|
||||
Text(bleManager.connectedPeripheral.longName).font(.title2)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
} else {
|
||||
|
||||
if bleManager.lastConnectionError.count > 0 {
|
||||
Text(bleManager.lastConnectionError).font(.callout).foregroundColor(.red)
|
||||
}
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.red)
|
||||
.padding(.trailing)
|
||||
Text("not.connected").font(.title3)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
.textCase(nil)
|
||||
|
||||
if !self.bleManager.isConnected {
|
||||
Section(header: Text("available.radios").font(.title)) {
|
||||
ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.name > $1.name })) { peripheral in
|
||||
HStack {
|
||||
Image(systemName: "circle.fill")
|
||||
.imageScale(.large).foregroundColor(.gray)
|
||||
.padding(.trailing)
|
||||
Button(action: {
|
||||
self.bleManager.stopScanning()
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
|
||||
self.bleManager.disconnectPeripheral()
|
||||
Text("ble.name").font(.caption)+Text(": \(bleManager.connectedPeripheral.peripheral.name ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
.font(.caption).foregroundColor(Color.gray)
|
||||
if node != nil {
|
||||
Text("firmware.version").font(.caption)+Text(": \(node?.myInfo?.firmwareVersion ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
.font(.caption).foregroundColor(Color.gray)
|
||||
}
|
||||
self.bleManager.connectTo(peripheral: peripheral.peripheral)
|
||||
if userSettings.preferredPeripheralId == peripheral.peripheral.identifier.uuidString {
|
||||
|
||||
isPreferredRadio = true
|
||||
if bleManager.isSubscribed {
|
||||
Text("subscribed").font(.caption)
|
||||
.foregroundColor(.green)
|
||||
} else {
|
||||
|
||||
isPreferredRadio = false
|
||||
Text("communicating").font(.caption)
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
}) {
|
||||
Text(peripheral.name).font(.title3)
|
||||
}
|
||||
Spacer()
|
||||
VStack {
|
||||
SignalStrengthIndicator(signalStrength: peripheral.getSignalStrength())
|
||||
VStack(alignment: .center) {
|
||||
Text("preferred.radio").font(.caption2)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(width: 75)
|
||||
Toggle("preferred.radio", isOn: $bleManager.preferredPeripheral)
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.labelsHidden()
|
||||
.onChange(of: bleManager.preferredPeripheral) { value in
|
||||
if value {
|
||||
if bleManager.connectedPeripheral != nil {
|
||||
userSettings.preferredPeripheralId = bleManager.connectedPeripheral!.peripheral.identifier.uuidString
|
||||
userSettings.preferredNodeNum = bleManager.connectedPeripheral!.num
|
||||
bleManager.preferredPeripheral = true
|
||||
isPreferredRadio = true
|
||||
}
|
||||
} else {
|
||||
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.identifier.uuidString == userSettings.preferredPeripheralId {
|
||||
|
||||
userSettings.preferredPeripheralId = ""
|
||||
userSettings.preferredNodeNum = 0
|
||||
bleManager.preferredPeripheral = false
|
||||
isPreferredRadio = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.padding([.bottom, .top])
|
||||
}
|
||||
.font(.caption).foregroundColor(Color.gray)
|
||||
.padding([.top, .bottom])
|
||||
.swipeActions {
|
||||
|
||||
Button(role: .destructive) {
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
isPreferredRadio = false
|
||||
}
|
||||
} label: {
|
||||
Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash")
|
||||
}
|
||||
}
|
||||
.contextMenu{
|
||||
|
||||
if node != nil {
|
||||
|
||||
if #available(iOS 16.2, *) {
|
||||
Button {
|
||||
if !liveActivityStarted {
|
||||
#if canImport(ActivityKit)
|
||||
print("Start live activity.")
|
||||
startNodeActivity()
|
||||
#endif
|
||||
} else {
|
||||
#if canImport(ActivityKit)
|
||||
print("Stop live activity.")
|
||||
endActivity()
|
||||
#endif
|
||||
}
|
||||
} label: {
|
||||
Label("Mesh Live Activity", systemImage: liveActivityStarted ? "stop" : "play")
|
||||
}
|
||||
}
|
||||
Text("Num: \(String(node!.num))")
|
||||
Text("Short Name: \(node?.user?.shortName ?? "????")")
|
||||
Text("Long Name: \(node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
Text("Max Channels: \(String(node?.myInfo?.maxChannels ?? 0))")
|
||||
Text("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))")
|
||||
Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)")
|
||||
|
||||
}
|
||||
}
|
||||
if isUnsetRegion {
|
||||
HStack {
|
||||
NavigationLink {
|
||||
LoRaConfig(node: node)
|
||||
} label: {
|
||||
Label("set.region", systemImage: "globe.americas.fill")
|
||||
.foregroundColor(.red)
|
||||
.font(.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if bleManager.isConnecting {
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.orange)
|
||||
.padding(.trailing)
|
||||
if bleManager.timeoutTimerCount == 0 {
|
||||
Text("connecting")
|
||||
.font(.title3)
|
||||
.foregroundColor(.orange)
|
||||
} else {
|
||||
VStack {
|
||||
|
||||
Text("Connection Attempt \(bleManager.timeoutTimerCount) of 10")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
} else {
|
||||
|
||||
if bleManager.lastConnectionError.count > 0 {
|
||||
Text(bleManager.lastConnectionError).font(.callout).foregroundColor(.red)
|
||||
}
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.red)
|
||||
.padding(.trailing)
|
||||
Text("not.connected").font(.title3)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}.textCase(nil)
|
||||
}
|
||||
}
|
||||
.textCase(nil)
|
||||
|
||||
if !self.bleManager.isConnected {
|
||||
Section(header: Text("available.radios").font(.title)) {
|
||||
ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.name > $1.name })) { peripheral in
|
||||
HStack {
|
||||
Image(systemName: "circle.fill")
|
||||
.imageScale(.large).foregroundColor(.gray)
|
||||
.padding(.trailing)
|
||||
Button(action: {
|
||||
self.bleManager.stopScanning()
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
|
||||
self.bleManager.disconnectPeripheral()
|
||||
}
|
||||
self.bleManager.connectTo(peripheral: peripheral.peripheral)
|
||||
if userSettings.preferredPeripheralId == peripheral.peripheral.identifier.uuidString {
|
||||
|
||||
isPreferredRadio = true
|
||||
} else {
|
||||
|
||||
isPreferredRadio = false
|
||||
}
|
||||
}) {
|
||||
Text(peripheral.name).font(.title3)
|
||||
}
|
||||
Spacer()
|
||||
VStack {
|
||||
SignalStrengthIndicator(signalStrength: peripheral.getSignalStrength())
|
||||
}
|
||||
}.padding([.bottom, .top])
|
||||
}
|
||||
}.textCase(nil)
|
||||
}
|
||||
|
||||
} else {
|
||||
Text("bluetooth.off")
|
||||
|
|
@ -199,12 +221,12 @@ struct Connect: View {
|
|||
.font(.title)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
|
||||
if bleManager.connectedPeripheral != nil {
|
||||
|
||||
Button(role: .destructive, action: {
|
||||
|
|
@ -217,23 +239,23 @@ struct Connect: View {
|
|||
}) {
|
||||
|
||||
Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash")
|
||||
|
||||
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
}
|
||||
#endif
|
||||
Spacer()
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
#endif
|
||||
Spacer()
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
}
|
||||
.navigationTitle("bluetooth")
|
||||
.navigationBarItems(leading: MeshtasticLogo(), trailing:
|
||||
ZStack {
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
ZStack {
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
}
|
||||
.sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) {
|
||||
InvalidVersion(minimumVersion: self.bleManager.minimumVersion, version: self.bleManager.connectedVersion)
|
||||
|
|
@ -270,7 +292,7 @@ struct Connect: View {
|
|||
.onAppear(perform: {
|
||||
self.bleManager.context = context
|
||||
self.bleManager.userSettings = userSettings
|
||||
|
||||
|
||||
// Ask for notification permission
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
|
||||
if success {
|
||||
|
|
@ -286,6 +308,69 @@ struct Connect: View {
|
|||
}
|
||||
})
|
||||
}
|
||||
#if canImport(ActivityKit)
|
||||
func startNodeActivity() {
|
||||
if #available(iOS 16.2, *) {
|
||||
liveActivityStarted = true
|
||||
let timerSeconds = 300
|
||||
|
||||
let mostRecent = node?.telemetries?.lastObject as! TelemetryEntity
|
||||
|
||||
let activityAttributes = MeshActivityAttributes(nodeNum: Int(node?.num ?? 0), name: node?.user?.longName ?? "unknown", connected: true, channelUtilization: mostRecent.channelUtilization, airtime: mostRecent.airUtilTx, batteryLevel: UInt32(mostRecent.batteryLevel))
|
||||
|
||||
let future = Date(timeIntervalSinceNow: Double(timerSeconds))
|
||||
|
||||
let initialContentState = MeshActivityAttributes.ContentState(timerRange: Date.now...future)
|
||||
|
||||
let activityContent = ActivityContent(state: initialContentState, staleDate: Calendar.current.date(byAdding: .minute, value: 2, to: Date())!)
|
||||
|
||||
do {
|
||||
let myActivity = try Activity<MeshActivityAttributes>.request(attributes: activityAttributes, content: activityContent,
|
||||
pushType: nil)
|
||||
print(" Requested MyActivity live activity. ID: \(myActivity.id)")
|
||||
postNotification()
|
||||
} catch let error {
|
||||
print("Error requesting live activity: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func endActivity() {
|
||||
Task {
|
||||
if #available(iOS 16.2, *) {
|
||||
for activity in Activity<MeshActivityAttributes>.activities {
|
||||
// Check if this is the activity associated with this order.
|
||||
if activity.attributes.nodeNum == node?.num ?? 0 {
|
||||
await activity.end(nil, dismissalPolicy: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
func postNotification() {
|
||||
let timerSeconds = 300
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = "Mesh Live Activity Over"
|
||||
content.body = "Your timed mesh live activity is over."
|
||||
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(timerSeconds), repeats: false)
|
||||
let uuidString = UUID().uuidString
|
||||
let request = UNNotificationRequest(identifier: uuidString,
|
||||
content: content, trigger: trigger)
|
||||
let notificationCenter = UNUserNotificationCenter.current()
|
||||
notificationCenter.add(request) { (error) in
|
||||
if error != nil {
|
||||
// Handle any errors.
|
||||
print("Error posting local notification: \(error?.localizedDescription ?? "no description")")
|
||||
} else {
|
||||
print("Posted local notification.")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
func didDismissSheet() {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.420",
|
||||
"green" : "0.470",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
20
Widgets/Assets.xcassets/LightIndigo.colorset/Contents.json
Normal file
20
Widgets/Assets.xcassets/LightIndigo.colorset/Contents.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.56",
|
||||
"green" : "0.96",
|
||||
"red" : "0.32"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.56",
|
||||
"green" : "0.96",
|
||||
"red" : "0.32"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.420",
|
||||
"green" : "0.470",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
23
Widgets/Assets.xcassets/logo-black.imageset/Contents.json
vendored
Normal file
23
Widgets/Assets.xcassets/logo-black.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Mesh_Logo_Black_Small.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Mesh_Logo_Black.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Mesh_Logo_Black_Large.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
12
Widgets/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black.svg
vendored
Normal file
12
Widgets/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black.svg
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 100 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
|
||||
<g transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)">
|
||||
<path d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z"/>
|
||||
</g>
|
||||
<g transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)">
|
||||
<path d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
12
Widgets/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Large.svg
vendored
Normal file
12
Widgets/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Large.svg
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 100 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(0.353462,0,0,0.202442,-296.058,-23.2047)">
|
||||
<g transform="matrix(1.40256,0,0,2.44636,669.626,-634.831)">
|
||||
<path d="M250.905,326.97L191.589,413.957L182.475,407.742L246.339,314.085C247.365,312.58 249.069,311.678 250.891,311.677C252.713,311.675 254.418,312.573 255.447,314.077L319.459,407.587L310.356,413.818L250.905,326.97Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1.39424,0,0,2.43184,733.087,-1033.78)">
|
||||
<path d="M86.181,580.402L153.296,481.981L144.099,475.709L76.984,574.13L86.181,580.402Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
12
Widgets/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Small.svg
vendored
Normal file
12
Widgets/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Small.svg
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 50 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1.10116,0,0,0.631321,-207.228,-202.833)">
|
||||
<g transform="matrix(0.201804,0,0,0.351989,167.289,216.061)">
|
||||
<path d="M250.912,334.664L195.175,416.403L178.889,405.297L242.753,311.64C244.587,308.95 247.631,307.339 250.887,307.336C254.143,307.333 257.19,308.938 259.029,311.625L323.04,405.135L306.774,416.27L250.912,334.664Z"/>
|
||||
</g>
|
||||
<g transform="matrix(0.205009,0,0,0.357578,174.224,154.227)">
|
||||
<path d="M89.878,582.923L156.993,484.502L140.402,473.188L73.287,571.609L89.878,582.923Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
23
Widgets/Assets.xcassets/logo-white.imageset/Contents.json
vendored
Normal file
23
Widgets/Assets.xcassets/logo-white.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Mesh_Logo_White_Small.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Mesh_Logo_White.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Mesh_Logo_White_Large.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
12
Widgets/Assets.xcassets/logo-white.imageset/Mesh_Logo_White.svg
vendored
Normal file
12
Widgets/Assets.xcassets/logo-white.imageset/Mesh_Logo_White.svg
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 100 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
|
||||
<g transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)">
|
||||
<path d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)">
|
||||
<path d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z" style="fill:white;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
12
Widgets/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Large.svg
vendored
Normal file
12
Widgets/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Large.svg
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 100 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(0.353462,0,0,0.202442,-296.058,-23.2047)">
|
||||
<g transform="matrix(1.40256,0,0,2.44636,669.626,-634.831)">
|
||||
<path d="M250.905,326.97L191.589,413.957L182.475,407.742L246.339,314.085C247.365,312.58 249.069,311.678 250.891,311.677C252.713,311.675 254.418,312.573 255.447,314.077L319.459,407.587L310.356,413.818L250.905,326.97Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.39424,0,0,2.43184,733.087,-1033.78)">
|
||||
<path d="M86.181,580.402L153.296,481.981L144.099,475.709L76.984,574.13L86.181,580.402Z" style="fill:white;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
12
Widgets/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Small.svg
vendored
Normal file
12
Widgets/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Small.svg
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 50 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1.10116,0,0,0.631321,-207.228,-202.833)">
|
||||
<g transform="matrix(0.201804,0,0,0.351989,167.289,216.061)">
|
||||
<path d="M250.912,334.664L195.175,416.403L178.889,405.297L242.753,311.64C244.587,308.95 247.631,307.339 250.887,307.336C254.143,307.333 257.19,308.938 259.029,311.625L323.04,405.135L306.774,416.27L250.912,334.664Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.205009,0,0,0.357578,174.224,154.227)">
|
||||
<path d="M89.878,582.923L156.993,484.502L140.402,473.188L73.287,571.609L89.878,582.923Z" style="fill:white;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
29
Widgets/MeshActivityAttributes.swift
Normal file
29
Widgets/MeshActivityAttributes.swift
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// MeshActivityAttributes.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Garth Vander Houwen on 3/1/23.
|
||||
//
|
||||
|
||||
#if canImport(ActivityKit)
|
||||
|
||||
import ActivityKit
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct MeshActivityAttributes: ActivityAttributes {
|
||||
public typealias MyActivityStatus = ContentState
|
||||
public struct ContentState: Codable, Hashable {
|
||||
// Dynamic stateful properties about your activity go here!
|
||||
var timerRange: ClosedRange<Date>
|
||||
}
|
||||
|
||||
// Fixed non-changing properties about your activity go here!
|
||||
var nodeNum: Int
|
||||
var name: String
|
||||
var connected: Bool
|
||||
var channelUtilization: Float
|
||||
var airtime: Float
|
||||
var batteryLevel: UInt32
|
||||
}
|
||||
#endif
|
||||
|
|
@ -4,74 +4,198 @@
|
|||
//
|
||||
// Created by Garth Vander Houwen on 2/28/23.
|
||||
//
|
||||
|
||||
#if canImport(ActivityKit)
|
||||
import ActivityKit
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct WidgetsAttributes: 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
|
||||
}
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
struct WidgetsLiveActivity: Widget {
|
||||
var body: some WidgetConfiguration {
|
||||
ActivityConfiguration(for: WidgetsAttributes.self) { context in
|
||||
// Lock screen/banner UI goes here
|
||||
VStack {
|
||||
Text("Hello")
|
||||
}
|
||||
.activityBackgroundTint(Color.cyan)
|
||||
.activitySystemActionForegroundColor(Color.black)
|
||||
|
||||
ActivityConfiguration(for: MeshActivityAttributes.self) { context in
|
||||
LiveActivityView(nodeName: context.attributes.name, connected: context.attributes.connected, channelUtilization: context.attributes.channelUtilization, airtime: context.attributes.airtime, batteryLevel: context.attributes.batteryLevel, timerRange: context.state.timerRange)
|
||||
.widgetURL(URL(string: "meshtastic://node/\(context.attributes.name)"))
|
||||
|
||||
} dynamicIsland: { context in
|
||||
DynamicIsland {
|
||||
DynamicIslandExpandedRegion(.leading) {
|
||||
NodeInfoView(nodeName: context.attributes.name, connected: context.attributes.connected, channelUtilization: context.attributes.channelUtilization, airtime: context.attributes.airtime, batteryLevel: context.attributes.batteryLevel)
|
||||
.tint(Color("LightIndigo"))
|
||||
.padding(.top)
|
||||
}
|
||||
// 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
|
||||
}
|
||||
DynamicIslandExpandedRegion(.trailing, priority: 1) {
|
||||
HStack(alignment: .lastTextBaseline) {
|
||||
|
||||
Spacer()
|
||||
TimerView(timerRange: context.state.timerRange)
|
||||
.tint(Color("LightIndigo"))
|
||||
}
|
||||
.padding(.top)
|
||||
|
||||
}
|
||||
|
||||
} compactLeading: {
|
||||
Text("L")
|
||||
Image("logo-black")
|
||||
.resizable()
|
||||
.frame(width: 30.0)
|
||||
.padding(4)
|
||||
.background(.green.gradient, in: ContainerRelativeShape())
|
||||
} compactTrailing: {
|
||||
Text("T")
|
||||
Text(timerInterval: context.state.timerRange, countsDown: true)
|
||||
.monospacedDigit()
|
||||
.foregroundColor(Color("LightIndigo"))
|
||||
.frame(width: 40)
|
||||
} minimal: {
|
||||
Text("Min")
|
||||
Image("logo-black")
|
||||
.resizable()
|
||||
.frame(width: 24.0)
|
||||
.padding(4)
|
||||
.background(.green.gradient, in: ContainerRelativeShape())
|
||||
}
|
||||
.widgetURL(URL(string: "http://www.apple.com"))
|
||||
.keylineTint(Color.red)
|
||||
.contentMargins(.trailing, 32, for: .expanded)
|
||||
.contentMargins([.leading, .top, .bottom], 6, for: .compactLeading)
|
||||
.contentMargins(.all, 6, for: .minimal)
|
||||
.widgetURL(URL(string: "meshtastic://node/\(context.attributes.name)"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
struct WidgetsLiveActivity_Previews: PreviewProvider {
|
||||
static let attributes = WidgetsAttributes(name: "Me")
|
||||
static let contentState = WidgetsAttributes.ContentState(value: 3)
|
||||
static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "Meshtastic 8E6G", connected: true, channelUtilization: 0.24, airtime: 0.87, batteryLevel: 39)
|
||||
static let state = MeshActivityAttributes.ContentState(
|
||||
timerRange: Date.now...Date(timeIntervalSinceNow: 3600))
|
||||
|
||||
static var previews: some View {
|
||||
attributes
|
||||
.previewContext(contentState, viewKind: .dynamicIsland(.compact))
|
||||
.previewDisplayName("Island Compact")
|
||||
.previewContext(state, viewKind: .dynamicIsland(.compact))
|
||||
.previewDisplayName("Compact")
|
||||
attributes
|
||||
.previewContext(state, viewKind: .dynamicIsland(.minimal))
|
||||
.previewDisplayName("Minimal")
|
||||
attributes
|
||||
.previewContext(contentState, viewKind: .dynamicIsland(.expanded))
|
||||
.previewDisplayName("Island Expanded")
|
||||
attributes
|
||||
.previewContext(contentState, viewKind: .dynamicIsland(.minimal))
|
||||
.previewDisplayName("Minimal")
|
||||
attributes
|
||||
.previewContext(contentState, viewKind: .content)
|
||||
.previewDisplayName("Notification")
|
||||
.previewContext(state, viewKind: .dynamicIsland(.expanded))
|
||||
.previewDisplayName("Expanded")
|
||||
attributes
|
||||
.previewContext(state, viewKind: .content)
|
||||
.previewDisplayName("Notification")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
struct LiveActivityView: View {
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@Environment(\.isLuminanceReduced) var isLuminanceReduced
|
||||
|
||||
var nodeName: String
|
||||
var connected: Bool
|
||||
var channelUtilization: Float
|
||||
var airtime: Float
|
||||
var batteryLevel: UInt32
|
||||
var timerRange: ClosedRange<Date>
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Image(colorScheme == .light ? "logo-black" : "logo-white")
|
||||
.clipShape(ContainerRelativeShape())
|
||||
.opacity(isLuminanceReduced ? 0.5 : 1.0)
|
||||
NodeInfoView(nodeName: nodeName, connected: connected, channelUtilization: channelUtilization, airtime: airtime, batteryLevel: batteryLevel)
|
||||
Spacer()
|
||||
TimerView(timerRange: timerRange)
|
||||
}
|
||||
.tint(.primary)
|
||||
.padding([.leading, .top, .bottom])
|
||||
.padding(.trailing, 32)
|
||||
.activityBackgroundTint(colorScheme == .light ? Color("LiveActivityBackground") : Color("AccentColorDimmed"))
|
||||
.activitySystemActionForegroundColor(.primary)
|
||||
}
|
||||
}
|
||||
|
||||
struct NodeInfoView: View {
|
||||
@Environment(\.isLuminanceReduced) var isLuminanceReduced
|
||||
|
||||
var nodeName: String
|
||||
var connected: Bool
|
||||
var channelUtilization: Float
|
||||
var airtime: Float
|
||||
var batteryLevel: UInt32
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(nodeName)
|
||||
.font(.title3)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.tint)
|
||||
.fixedSize()
|
||||
Text(connected ? "Connected" : "Not Connected")
|
||||
.font(.callout)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.tint)
|
||||
.fixedSize()
|
||||
Text("\(String(format: "Ch. Util: %.2f", channelUtilization))%")
|
||||
.font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.5 : 1.0)
|
||||
.fixedSize()
|
||||
Text("\(String(format: "Airtime: %.2f", airtime))%")
|
||||
.font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.5 : 1.0)
|
||||
.fixedSize()
|
||||
Text("Battery Level: \(batteryLevel)%")
|
||||
.font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.5 : 1.0)
|
||||
.fixedSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TimerView: View {
|
||||
@Environment(\.isLuminanceReduced) var isLuminanceReduced
|
||||
|
||||
var timerRange: ClosedRange<Date>
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .trailing) {
|
||||
Text(timerInterval: timerRange, countsDown: true)
|
||||
.monospacedDigit()
|
||||
.multilineTextAlignment(.trailing)
|
||||
.frame(width: 80)
|
||||
.font(.title3)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.tint)
|
||||
Image(systemName: "timer")
|
||||
.resizable()
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(width: 30, height: 30)
|
||||
.padding(.trailing)
|
||||
.opacity(isLuminanceReduced ? 0.5 : 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ExpandedTrailingView: View {
|
||||
var nodeName: String
|
||||
var connected: Bool
|
||||
var channelUtilization: Float
|
||||
var airtime: Float
|
||||
var batteryLevel: UInt32
|
||||
var timerInterval: ClosedRange<Date>
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .lastTextBaseline) {
|
||||
|
||||
Spacer()
|
||||
TimerView(timerRange: timerInterval)
|
||||
}
|
||||
.tint(Color("LightIndigo"))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
10
WidgetsExtension.entitlements
Normal file
10
WidgetsExtension.entitlements
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
Loading…
Add table
Add a link
Reference in a new issue