mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Implement SiriKit intents for CarPlay messaging (#1664)
* Add SiriKit intent handlers for CarPlay messaging (INSendMessageIntent, INSearchForMessagesIntent, INSetMessageAttributeIntent) Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/8ef2a78b-83ee-4d9f-82b9-17b766c96312 Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com> * Address code review: consolidate intent routing, support multiple recipients, improve error for long messages Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/8ef2a78b-83ee-4d9f-82b9-17b766c96312 Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com> * Fix unnecessary nil-coalescing in conversationIdentifier Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/8ef2a78b-83ee-4d9f-82b9-17b766c96312 Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com> * Restrict INSendMessageIntent to single recipient (channel or direct message, not both) Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/1798a03a-53b3-4a97-94e1-8281b552217a Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com> * Fix Mac Catalyst build errors in SiriKit intent handlers - SendMessageIntentHandler: guard `.noHandlesForValue` with #if targetEnvironment(macCatalyst) since the reason enum is iOS-only - IntentMessageConverters: use .text instead of .tapback; INMessageType.tapback is unavailable on Mac Catalyst - SearchForMessagesIntentHandler: replace .startDate/.endDate (iOS-only) with .startDateComponents/.endDateComponents + Calendar.date(from:) which work on all platforms Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/9b61aad5-652c-4330-83b3-2303f10e4f12 Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com> * Add Siri authorization request at startup and NSSiriUsageDescription in Info.plist Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/be245ecb-2f0a-48d4-b931-4df889a6b6cc Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>
This commit is contained in:
parent
27b59fbb72
commit
1ae2b4bfef
8 changed files with 494 additions and 1 deletions
85
Meshtastic/Intents/SetMessageAttributeIntentHandler.swift
Normal file
85
Meshtastic/Intents/SetMessageAttributeIntentHandler.swift
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// SetMessageAttributeIntentHandler.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Handles INSetMessageAttributeIntent for CarPlay and Siri.
|
||||
// Marks messages as read or unread in Core Data.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
import Intents
|
||||
import OSLog
|
||||
|
||||
final class SetMessageAttributeIntentHandler: NSObject, INSetMessageAttributeIntentHandling {
|
||||
|
||||
// MARK: - Resolution
|
||||
|
||||
func resolveAttribute(for intent: INSetMessageAttributeIntent) async -> INMessageAttributeResolutionResult {
|
||||
let attribute = intent.attribute
|
||||
guard attribute != .unknown else {
|
||||
return .needsValue()
|
||||
}
|
||||
return .success(with: attribute)
|
||||
}
|
||||
|
||||
// MARK: - Confirmation
|
||||
|
||||
func confirm(intent: INSetMessageAttributeIntent) async -> INSetMessageAttributeIntentResponse {
|
||||
guard let identifiers = intent.identifiers, !identifiers.isEmpty else {
|
||||
return INSetMessageAttributeIntentResponse(code: .failure, userActivity: nil)
|
||||
}
|
||||
return INSetMessageAttributeIntentResponse(code: .ready, userActivity: nil)
|
||||
}
|
||||
|
||||
// MARK: - Handling
|
||||
|
||||
func handle(intent: INSetMessageAttributeIntent) async -> INSetMessageAttributeIntentResponse {
|
||||
guard let identifiers = intent.identifiers, !identifiers.isEmpty else {
|
||||
return INSetMessageAttributeIntentResponse(code: .failure, userActivity: nil)
|
||||
}
|
||||
|
||||
let attribute = intent.attribute
|
||||
let context = PersistenceController.shared.container.viewContext
|
||||
|
||||
let success: Bool = await MainActor.run {
|
||||
let messageIds = identifiers.compactMap { Int64($0) }
|
||||
guard !messageIds.isEmpty else { return false }
|
||||
|
||||
let fetchRequest: NSFetchRequest<MessageEntity> = MessageEntity.fetchRequest()
|
||||
fetchRequest.predicate = NSPredicate(format: "messageId IN %@", messageIds)
|
||||
|
||||
do {
|
||||
let messages = try context.fetch(fetchRequest)
|
||||
guard !messages.isEmpty else { return false }
|
||||
|
||||
for message in messages {
|
||||
switch attribute {
|
||||
case .read:
|
||||
message.read = true
|
||||
case .unread:
|
||||
message.read = false
|
||||
case .flagged, .unflagged:
|
||||
// Meshtastic does not support message flagging
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if context.hasChanges {
|
||||
try context.save()
|
||||
}
|
||||
Logger.services.info("CarPlay/Siri: Updated \(messages.count) message(s) to \(String(describing: attribute))")
|
||||
return true
|
||||
} catch {
|
||||
Logger.services.error("CarPlay/Siri: Failed to update message attributes: \(error.localizedDescription)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return INSetMessageAttributeIntentResponse(
|
||||
code: success ? .success : .failure,
|
||||
userActivity: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue