Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intents newfeature #900

Merged
merged 5 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
}
}