Skip to content

Commit

Permalink
Merge pull request #900 from meshtastic/intents-newfeature
Browse files Browse the repository at this point in the history
Intents newfeature
  • Loading branch information
garthvh authored Aug 28, 2024
2 parents 51b4189 + eec7f59 commit 98512e8
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 6 deletions.
31 changes: 29 additions & 2 deletions Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,9 @@
},
"Are you sure you want to delete this message?" : {

},
"Are you sure you want to factory reset the node?" : {

},
"are.you.sure" : {
"localizations" : {
Expand Down Expand Up @@ -8161,6 +8164,9 @@
}
}
}
},
"Group Message" : {

},
"Gusts %@" : {

Expand Down Expand Up @@ -16339,6 +16345,9 @@
}
}
}
},
"Perform a factory reset on the node you are connected to" : {

},
"phone.gps" : {
"localizations" : {
Expand Down Expand Up @@ -17044,6 +17053,9 @@
}
}
}
},
"Reboot Node?" : {

},
"reboot.node" : {
"localizations" : {
Expand Down Expand Up @@ -17412,6 +17424,12 @@
},
"Reset NodeDB" : {

},
"Restart" : {

},
"Restart to the node you are connected to" : {

},
"restore" : {

Expand Down Expand Up @@ -19154,13 +19172,16 @@
"Send" : {

},
"Send a channel message" : {
"Send a Group Message" : {

},
"Send a message to a certain meshtastic channel" : {

},
"Send a waypoint" : {
"Send a shutdown to the node you are connected to" : {

},
"Send a Waypoint" : {

},
"Send ASCII bell with alert message. Useful for triggering external notification on bell." : {
Expand Down Expand Up @@ -19899,6 +19920,12 @@
},
"Show Weather" : {

},
"Shut Down" : {

},
"Shut Down Node?" : {

},
"Shutdown Node?" : {

Expand Down
16 changes: 16 additions & 0 deletions Meshtastic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
BCB613832C672A2600485544 /* MessageChannelIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613822C672A2600485544 /* MessageChannelIntent.swift */; };
BCB613852C68703800485544 /* NodePositionIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613842C68703800485544 /* NodePositionIntent.swift */; };
BCB613872C69A0FB00485544 /* AppIntentErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613862C69A0FB00485544 /* AppIntentErrors.swift */; };
BCE2D3C32C7ADF42008E6199 /* ShutDownNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C22C7ADF42008E6199 /* ShutDownNodeIntent.swift */; };
BCE2D3C52C7AE369008E6199 /* RestartNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C42C7AE369008E6199 /* RestartNodeIntent.swift */; };
BCE2D3C72C7B0D0A008E6199 /* ShortcutsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */; };
BCE2D3C92C7C377F008E6199 /* FactoryResetNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C82C7C377F008E6199 /* FactoryResetNodeIntent.swift */; };
C9697FA527933B8C00250207 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = C9697FA427933B8C00250207 /* SQLite */; };
D93068D32B8129510066FBC8 /* MessageContextMenuItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93068D22B8129510066FBC8 /* MessageContextMenuItems.swift */; };
D93068D52B812B700066FBC8 /* MessageDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93068D42B812B700066FBC8 /* MessageDestination.swift */; };
Expand Down Expand Up @@ -275,6 +279,10 @@
BCB613822C672A2600485544 /* MessageChannelIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageChannelIntent.swift; sourceTree = "<group>"; };
BCB613842C68703800485544 /* NodePositionIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodePositionIntent.swift; sourceTree = "<group>"; };
BCB613862C69A0FB00485544 /* AppIntentErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentErrors.swift; sourceTree = "<group>"; };
BCE2D3C22C7ADF42008E6199 /* ShutDownNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShutDownNodeIntent.swift; sourceTree = "<group>"; };
BCE2D3C42C7AE369008E6199 /* RestartNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestartNodeIntent.swift; sourceTree = "<group>"; };
BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsProvider.swift; sourceTree = "<group>"; };
BCE2D3C82C7C377F008E6199 /* FactoryResetNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FactoryResetNodeIntent.swift; sourceTree = "<group>"; };
D93068D22B8129510066FBC8 /* MessageContextMenuItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContextMenuItems.swift; sourceTree = "<group>"; };
D93068D42B812B700066FBC8 /* MessageDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageDestination.swift; sourceTree = "<group>"; };
D93068D62B8146690066FBC8 /* MessageText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageText.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -574,6 +582,10 @@
BCB613822C672A2600485544 /* MessageChannelIntent.swift */,
BCB613842C68703800485544 /* NodePositionIntent.swift */,
BCB613862C69A0FB00485544 /* AppIntentErrors.swift */,
BCE2D3C22C7ADF42008E6199 /* ShutDownNodeIntent.swift */,
BCE2D3C42C7AE369008E6199 /* RestartNodeIntent.swift */,
BCE2D3C82C7C377F008E6199 /* FactoryResetNodeIntent.swift */,
BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */,
);
path = AppIntents;
sourceTree = "<group>";
Expand Down Expand Up @@ -1258,6 +1270,7 @@
25F26B1F2C2F611300C9CD9D /* AppData.swift in Sources */,
25F26B1E2C2F610D00C9CD9D /* Logger.swift in Sources */,
259792252C2F114500AD1659 /* ChannelEntityExtension.swift in Sources */,
BCE2D3C52C7AE369008E6199 /* RestartNodeIntent.swift in Sources */,
259792262C2F114500AD1659 /* PositionEntityExtension.swift in Sources */,
259792272C2F114500AD1659 /* TraceRouteEntityExtension.swift in Sources */,
DDDB444829F8A9C900EE2349 /* String.swift in Sources */,
Expand Down Expand Up @@ -1362,6 +1375,7 @@
D93068D32B8129510066FBC8 /* MessageContextMenuItems.swift in Sources */,
DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */,
DD964FC42974767D007C176F /* MapViewFitExtension.swift in Sources */,
BCE2D3C72C7B0D0A008E6199 /* ShortcutsProvider.swift in Sources */,
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */,
DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */,
DD2553572855B02500E55709 /* LoRaConfig.swift in Sources */,
Expand Down Expand Up @@ -1422,6 +1436,7 @@
BCB613872C69A0FB00485544 /* AppIntentErrors.swift in Sources */,
DD73FD1128750779000852D6 /* PositionLog.swift in Sources */,
DD15E4F52B8BFC8E00654F61 /* PaxCounterLog.swift in Sources */,
BCE2D3C32C7ADF42008E6199 /* ShutDownNodeIntent.swift in Sources */,
25F5D5C22C3F6E4B008036E3 /* AppState.swift in Sources */,
DD3CC6C028E7A60700FA9159 /* MessagingEnums.swift in Sources */,
DD6F657B2C6EC2900053C113 /* LockLegend.swift in Sources */,
Expand All @@ -1437,6 +1452,7 @@
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */,
DD77093F2AA1B146007A8BF0 /* UIColor.swift in Sources */,
DDF6B2482A9AEBF500BA6931 /* StoreForwardConfig.swift in Sources */,
BCE2D3C92C7C377F008E6199 /* FactoryResetNodeIntent.swift in Sources */,
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */,
DD93800B2BA3F968008BEC06 /* NodeMapContent.swift in Sources */,
DD41582A28585C32009B0E59 /* RangeTestConfig.swift in Sources */,
Expand Down
9 changes: 7 additions & 2 deletions Meshtastic/AppIntents/AppIntentErrors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import OSLog

class AppIntentErrors {
enum AppIntentError: Swift.Error, CustomLocalizedStringResourceConvertible {
Expand All @@ -14,8 +15,12 @@ class AppIntentErrors {

var localizedStringResource: LocalizedStringResource {
switch self {
case let .message(message): return "Error: \(message)"
case .notConnected: return "No Connected Node"
case let .message(message):
Logger.services.error("App Intent: \(message)")
return "Error: \(message)"
case .notConnected:
Logger.services.error("App Intent: No Connected Node")
return "No Connected Node"
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions Meshtastic/AppIntents/FactoryResetNodeIntent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// FactoryResetNodeIntent.swift
// Meshtastic
//
// Created by Benjamin Faershtein on 8/25/24.
//

import Foundation
import AppIntents

struct FactoryResetNodeIntent: AppIntent {
static var title: LocalizedStringResource = "Factory Reset"
static var description: IntentDescription = "Perform a factory reset on the node you are connected to"

func perform() async throws -> some IntentResult {
// Request user confirmation before performing the factory reset
try await requestConfirmation(result: .result(dialog: "Are you sure you want to factory reset the node?"),confirmationActionName: ConfirmationActionName
.custom(acceptLabel: "Factory Reset", acceptAlternatives: [], denyLabel: "Cancel", denyAlternatives: [], destructive: true))

// Ensure the node is connected
if !BLEManager.shared.isConnected {
throw AppIntentErrors.AppIntentError.notConnected
}

// Safely unwrap the connected node information
if let connectedPeripheralNum = BLEManager.shared.connectedPeripheral?.num,
let connectedNode = getNodeInfo(id: connectedPeripheralNum, context: PersistenceController.shared.container.viewContext),
let fromUser = connectedNode.user,
let toUser = connectedNode.user {

// Attempt to send a factory reset command, throw an error if it fails
if !BLEManager.shared.sendFactoryReset(fromUser: fromUser, toUser: toUser) {
throw AppIntentErrors.AppIntentError.message("Failed to perform factory reset")
}
} else {
throw AppIntentErrors.AppIntentError.message("Failed to retrieve connected node or required data")
}
//
return .result()
}
}
2 changes: 1 addition & 1 deletion Meshtastic/AppIntents/MessageChannelIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
import AppIntents

struct MessageChannelIntent: AppIntent {
static var title: LocalizedStringResource = "Send a channel message"
static var title: LocalizedStringResource = "Send a Group Message"

static var description: IntentDescription = "Send a message to a certain meshtastic channel"

Expand Down
1 change: 1 addition & 0 deletions Meshtastic/AppIntents/NodePositionIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct NodePositionIntent: AppIntent {
}

let nodeInfo = fetchedNode[0]
nodeInfo.latestEnvironmentMetrics?.batteryLevel
if let latitude = nodeInfo.latestPosition?.coordinate.latitude,
let longitude = nodeInfo.latestPosition?.coordinate.longitude {
let nodeLocation = CLLocation(latitude: latitude, longitude: longitude)
Expand Down
39 changes: 39 additions & 0 deletions Meshtastic/AppIntents/RestartNodeIntent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// RestartNodeIntent.swift
// Meshtastic
//
// Created by Benjamin Faershtein on 8/24/24.
//

import Foundation
import AppIntents

struct RestartNodeIntent: AppIntent {
static var title: LocalizedStringResource = "Restart"

static var description: IntentDescription = "Restart to the node you are connected to"

func perform() async throws -> some IntentResult {

try await requestConfirmation(result: .result(dialog: "Reboot Node?"))

if !BLEManager.shared.isConnected {
throw AppIntentErrors.AppIntentError.notConnected
}
// Safely unwrap the connectedNode using if let
if let connectedPeripheralNum = BLEManager.shared.connectedPeripheral?.num,
let connectedNode = getNodeInfo(id: connectedPeripheralNum, context: PersistenceController.shared.container.viewContext),
let fromUser = connectedNode.user,
let toUser = connectedNode.user,
let adminIndex = connectedNode.myInfo?.adminIndex {

// Attempt to send shutdown, throw an error if it fails
if !BLEManager.shared.sendReboot(fromUser: fromUser, toUser: toUser, adminIndex: adminIndex) {
throw AppIntentErrors.AppIntentError.message("Failed to restart")
}
} else {
throw AppIntentErrors.AppIntentError.message("Failed to retrieve connected node or required data")
}
return .result()
}
}
2 changes: 1 addition & 1 deletion Meshtastic/AppIntents/SendWaypointIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import MeshtasticProtobufs

struct SendWaypointIntent: AppIntent {

static var title = LocalizedStringResource("Send a waypoint")
static var title = LocalizedStringResource("Send a Waypoint")

@Parameter(title: "Name", default: "Dropped Pin")
var nameParameter: String?
Expand Down
36 changes: 36 additions & 0 deletions Meshtastic/AppIntents/ShortcutsProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// ShortcutsProvider.swift
// Meshtastic
//
// Created by Benjamin Faershtein on 8/24/24.
//

import Foundation
import AppIntents

struct ShortcutsProvider: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(intent: ShutDownNodeIntent(),
phrases: ["Shut down \(.applicationName) node",
"Shut down my \(.applicationName) node",
"Turn off \(.applicationName) node",
"Power down \(.applicationName) node",
"Deactivate \(.applicationName) node"],
shortTitle: "Shut Down",
systemImageName: "power")

AppShortcut(intent: RestartNodeIntent(),
phrases: ["Restart \(.applicationName) node",
"Restart my \(.applicationName) node",
"Reboot \(.applicationName) node",
"Reboot my \(.applicationName) node"],
shortTitle: "Restart",
systemImageName: "arrow.circlepath")

AppShortcut(intent: MessageChannelIntent(),
phrases: ["Message a \(.applicationName) channel",
"Send a \(.applicationName) group message"],
shortTitle: "Group Message",
systemImageName: "message")
}
}
39 changes: 39 additions & 0 deletions Meshtastic/AppIntents/ShutDownNodeIntent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// ShutDownNodeIntent.swift
// Meshtastic
//
// Created by Benjamin Faershtein on 8/24/24.
//

import Foundation
import AppIntents

struct ShutDownNodeIntent: AppIntent {
static var title: LocalizedStringResource = "Shut Down"

static var description: IntentDescription = "Send a shutdown to the node you are connected to"

func perform() async throws -> some IntentResult {
try await requestConfirmation(result: .result(dialog: "Shut Down Node?"))

if !BLEManager.shared.isConnected {
throw AppIntentErrors.AppIntentError.notConnected
}

// Safely unwrap the connectedNode using if let
if let connectedPeripheralNum = BLEManager.shared.connectedPeripheral?.num,
let connectedNode = getNodeInfo(id: connectedPeripheralNum, context: PersistenceController.shared.container.viewContext),
let fromUser = connectedNode.user,
let toUser = connectedNode.user,
let adminIndex = connectedNode.myInfo?.adminIndex {

// Attempt to send shutdown, throw an error if it fails
if !BLEManager.shared.sendShutdown(fromUser: fromUser, toUser: toUser, adminIndex: adminIndex) {
throw AppIntentErrors.AppIntentError.message("Failed to shut down")
}
} else {
throw AppIntentErrors.AppIntentError.message("Failed to retrieve connected node or required data")
}
return .result()
}
}

0 comments on commit 98512e8

Please sign in to comment.