diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 4c41ced3..3ed32241 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -19131,12 +19131,21 @@ }, "Send ${messageContent} to ${channelNumber}" : { + }, + "Send ${messageContent} to ${nodeNumber}" : { + + }, + "Send a Direct Message" : { + }, "Send a Group Message" : { }, "Send a message to a certain meshtastic channel" : { + }, + "Send a message to a certain meshtastic node" : { + }, "Send a position on the primary channel when the user button is triple clicked." : { @@ -19158,6 +19167,9 @@ }, "Sender Interval" : { + }, + "Sensor" : { + }, "Sensor Metrics" : { @@ -21100,13 +21112,12 @@ }, "The state of the LED (on/off)" : { - }, - "The URL for the channel settings" : { - }, "The tertiary public key authorized to send admin messages to this node." : { - + }, + "The URL for the channel settings" : { + }, "There has been no response to a request for device metadata over the admin channel for this node." : { @@ -21885,6 +21896,9 @@ }, "Trace Route was rate limited. You can send a trace route a maximum of once every thirty seconds." : { + }, + "Tracker" : { + }, "Traffic" : { @@ -22719,4 +22733,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +} diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 5e28e9a3..1fafb26c 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -32,6 +32,8 @@ 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */; }; B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B399E8A32B6F486400E4488E /* RetryButton.swift */; }; B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E905B02B71F7F300654D07 /* TextMessageField.swift */; }; + BC47C2EF2CE0017D008245CA /* MessageNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */; }; + BC5EBA3C2D002A2000C442FF /* MessageNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5EBA3B2D002A2000C442FF /* MessageNodeIntent.swift */; }; BC6B45FF2CB2F98900723CEB /* SaveChannelSettingsIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.swift */; }; BCB613812C67290800485544 /* SendWaypointIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613802C67290800485544 /* SendWaypointIntent.swift */; }; BCB613832C672A2600485544 /* MessageChannelIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613822C672A2600485544 /* MessageChannelIntent.swift */; }; @@ -278,6 +280,8 @@ 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = ""; }; B399E8A32B6F486400E4488E /* RetryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryButton.swift; sourceTree = ""; }; B3E905B02B71F7F300654D07 /* TextMessageField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageField.swift; sourceTree = ""; }; + BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageNodeIntent.swift; sourceTree = ""; }; + BC5EBA3B2D002A2000C442FF /* MessageNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageNodeIntent.swift; sourceTree = ""; }; BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveChannelSettingsIntent.swift; sourceTree = ""; }; BCB613802C67290800485544 /* SendWaypointIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendWaypointIntent.swift; sourceTree = ""; }; BCB613822C672A2600485544 /* MessageChannelIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageChannelIntent.swift; sourceTree = ""; }; @@ -587,6 +591,7 @@ BCB6137F2C6728E700485544 /* AppIntents */ = { isa = PBXGroup; children = ( + BC5EBA3B2D002A2000C442FF /* MessageNodeIntent.swift */, BCB613802C67290800485544 /* SendWaypointIntent.swift */, BCB613822C672A2600485544 /* MessageChannelIntent.swift */, BCB613842C68703800485544 /* NodePositionIntent.swift */, @@ -596,6 +601,7 @@ BCE2D3C82C7C377F008E6199 /* FactoryResetNodeIntent.swift */, BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */, BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.swift */, + BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */, ); path = AppIntents; sourceTree = ""; @@ -1297,6 +1303,7 @@ DDFFA7472B3A7F3C004730DB /* Bundle.swift in Sources */, DD457188293C7E63000C49FB /* BLESignalStrengthIndicator.swift in Sources */, DDA9515C2BC6631200CEA535 /* TelemetryEnums.swift in Sources */, + BC47C2EF2CE0017D008245CA /* MessageNodeIntent.swift in Sources */, DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */, DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */, D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */, @@ -1413,6 +1420,7 @@ DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */, D9BC22DB2B7DE8E2006A37D5 /* TileDownloadStatus.swift in Sources */, DDD5BB092C285DDC007E03CA /* AppLog.swift in Sources */, + BC5EBA3C2D002A2000C442FF /* MessageNodeIntent.swift in Sources */, DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */, DDC1B81A2AB5377B00C71E39 /* MessagesTips.swift in Sources */, DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */, diff --git a/Meshtastic/AppIntents/MessageNodeIntent.swift b/Meshtastic/AppIntents/MessageNodeIntent.swift new file mode 100644 index 00000000..089530bf --- /dev/null +++ b/Meshtastic/AppIntents/MessageNodeIntent.swift @@ -0,0 +1,45 @@ +// +// MessageNodeIntent.swift +// Meshtastic +// +// Created by Benjamin Faershtein on 11/9/24. +// + +import Foundation +import AppIntents + +struct MessageNodeIntent: AppIntent { + static var title: LocalizedStringResource = "Send a Direct Message" + + static var description: IntentDescription = "Send a message to a certain meshtastic node" + + @Parameter(title: "Message") + var messageContent: String + + @Parameter(title: "Node Number") + var nodeNumber: Int + + static var parameterSummary: some ParameterSummary { + Summary("Send \(\.$messageContent) to \(\.$nodeNumber)") + } + func perform() async throws -> some IntentResult { + if !BLEManager.shared.isConnected { + throw AppIntentErrors.AppIntentError.notConnected + } + + // Convert messageContent to data and check its length + guard let messageData = messageContent.data(using: .utf8) else { + throw AppIntentErrors.AppIntentError.message("Failed to encode message content") + } + + if messageData.count > 200 { + throw $messageContent.needsValueError("Message content exceeds 200 bytes.") + } + + if !BLEManager.shared.sendMessage(message: messageContent, toUserNum: Int64(nodeNumber), channel: 0, isEmoji: false, replyID: 0) { + throw AppIntentErrors.AppIntentError.message("Failed to send message") + } + + return .result() + } +}