297 lines
9.8 KiB
Swift
297 lines
9.8 KiB
Swift
//
|
|
// AppIntentHandlers.swift
|
|
// Runner
|
|
//
|
|
// Created by LittleSheep on 2026/1/16.
|
|
//
|
|
|
|
import AppIntents
|
|
import UIKit
|
|
|
|
@available(iOS 16.0, *)
|
|
struct OpenChatIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_open_chat_title"
|
|
static var description = IntentDescription("intent_open_chat_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = true
|
|
|
|
@Parameter(title: "Channel ID")
|
|
var channelId: String?
|
|
|
|
func perform() async throws -> some IntentResult & OpensIntent {
|
|
guard let channelId = channelId, !channelId.isEmpty else {
|
|
throw AppIntentError.requiredParameter("Channel ID")
|
|
}
|
|
|
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://chat/\(channelId)")!)
|
|
|
|
return .result(value: "Opening chat \(channelId)")
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct OpenPostIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_open_post_title"
|
|
static var description = IntentDescription("intent_open_post_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = true
|
|
|
|
@Parameter(title: "Post ID")
|
|
var postId: String?
|
|
|
|
func perform() async throws -> some IntentResult & OpensIntent {
|
|
guard let postId = postId, !postId.isEmpty else {
|
|
throw AppIntentError.requiredParameter("Post ID")
|
|
}
|
|
|
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://posts/\(postId)")!)
|
|
|
|
return .result(value: "Opening post \(postId)")
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct OpenComposeIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_open_compose_title"
|
|
static var description = IntentDescription("intent_open_compose_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = true
|
|
|
|
func perform() async throws -> some IntentResult & OpensIntent {
|
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://compose")!)
|
|
|
|
return .result(value: "Opening compose screen")
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct ComposePostIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_compose_post_title"
|
|
static var description = IntentDescription("intent_compose_post_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = true
|
|
|
|
func perform() async throws -> some IntentResult & OpensIntent {
|
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://compose")!)
|
|
|
|
return .result(value: "Opening compose screen")
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct SearchContentIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_search_title"
|
|
static var description = IntentDescription("intent_search_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = true
|
|
|
|
@Parameter(title: "Search Query")
|
|
var query: String?
|
|
|
|
func perform() async throws -> some IntentResult & OpensIntent {
|
|
guard let query = query, !query.isEmpty else {
|
|
throw AppIntentError.requiredParameter("Search Query")
|
|
}
|
|
|
|
let encodedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? query
|
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://search?q=\(encodedQuery)")!)
|
|
|
|
return .result(value: "Searching for \"\(query)\"")
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct ViewNotificationsIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_notifications_title"
|
|
static var description = IntentDescription("intent_notifications_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = true
|
|
|
|
func perform() async throws -> some IntentResult & OpensIntent {
|
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://notifications")!)
|
|
|
|
return .result(value: "Opening notifications")
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct CheckNotificationsIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_check_notifications_title"
|
|
static var description = IntentDescription("intent_check_notifications_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = false
|
|
|
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
|
do {
|
|
let count = try await NetworkService.shared.getNotificationCount()
|
|
|
|
let message: String
|
|
if count == 0 {
|
|
message = "You have no new notifications"
|
|
} else if count == 1 {
|
|
message = "You have 1 new notification"
|
|
} else {
|
|
message = "You have \(count) new notifications"
|
|
}
|
|
|
|
return .result(
|
|
value: message,
|
|
dialog: "\(message)"
|
|
)
|
|
} catch {
|
|
throw AppIntentError.networkError("Failed to check notifications: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct SendMessageIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_send_message_title"
|
|
static var description = IntentDescription("intent_send_message_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = false
|
|
|
|
@Parameter(title: "Channel ID")
|
|
var channelId: String?
|
|
|
|
@Parameter(title: "Message Content")
|
|
var content: String?
|
|
|
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
|
guard let channelId = channelId, !channelId.isEmpty else {
|
|
throw AppIntentError.requiredParameter("Channel ID")
|
|
}
|
|
|
|
guard let content = content, !content.isEmpty else {
|
|
throw AppIntentError.requiredParameter("Message Content")
|
|
}
|
|
|
|
do {
|
|
try await NetworkService.shared.sendMessage(channelId: channelId, content: content)
|
|
|
|
return .result(
|
|
value: "Message sent to channel \(channelId)",
|
|
dialog: "Message sent successfully"
|
|
)
|
|
} catch {
|
|
throw AppIntentError.networkError("Failed to send message: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct ReadMessagesIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_read_messages_title"
|
|
static var description = IntentDescription("intent_read_messages_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = false
|
|
|
|
@Parameter(title: "Channel ID")
|
|
var channelId: String?
|
|
|
|
@Parameter(title: "Number of Messages", default: "5")
|
|
var limit: String?
|
|
|
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
|
guard let channelId = channelId, !channelId.isEmpty else {
|
|
throw AppIntentError.requiredParameter("Channel ID")
|
|
}
|
|
|
|
let limitValue = Int(limit ?? "5") ?? 5
|
|
let safeLimit = max(1, min(20, limitValue))
|
|
|
|
do {
|
|
let messages = try await NetworkService.shared.getMessages(
|
|
channelId: channelId,
|
|
offset: 0,
|
|
take: safeLimit
|
|
)
|
|
|
|
if messages.isEmpty {
|
|
return .result(
|
|
value: "No messages found in channel \(channelId)",
|
|
dialog: "No messages found"
|
|
)
|
|
}
|
|
|
|
let formattedMessages = messages.compactMap { message -> String? in
|
|
let senderName = message.sender?.account?.name ?? "Unknown"
|
|
let content = message.content ?? ""
|
|
return "\(senderName): \(content)"
|
|
}.joined(separator: "\n")
|
|
|
|
return .result(
|
|
value: formattedMessages,
|
|
dialog: "Found \(messages.count) messages"
|
|
)
|
|
} catch {
|
|
throw AppIntentError.networkError("Failed to read messages: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct CheckUnreadChatsIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_unread_chats_title"
|
|
static var description = IntentDescription("intent_unread_chats_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = false
|
|
|
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
|
do {
|
|
let count = try await NetworkService.shared.getUnreadChatsCount()
|
|
|
|
let message: String
|
|
if count == 0 {
|
|
message = "You have no unread messages"
|
|
} else if count == 1 {
|
|
message = "You have 1 unread message"
|
|
} else {
|
|
message = "You have \(count) unread messages"
|
|
}
|
|
|
|
return .result(
|
|
value: message,
|
|
dialog: "\(message)"
|
|
)
|
|
} catch {
|
|
throw AppIntentError.networkError("Failed to check unread chats: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.0, *)
|
|
struct MarkNotificationsReadIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "intent_mark_read_title"
|
|
static var description = IntentDescription("intent_mark_read_desc")
|
|
static var isDiscoverable = true
|
|
static var openAppWhenRun = false
|
|
|
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
|
do {
|
|
try await NetworkService.shared.markNotificationsRead()
|
|
|
|
return .result(
|
|
value: "All notifications marked as read",
|
|
dialog: "All notifications marked as read"
|
|
)
|
|
} catch {
|
|
throw AppIntentError.networkError("Failed to mark notifications: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
}
|
|
|
|
enum AppIntentError: Error, CustomLocalizedStringResourceConvertible {
|
|
case requiredParameter(String)
|
|
case networkError(String)
|
|
|
|
var localizedStringResource: LocalizedStringResource {
|
|
switch self {
|
|
case .requiredParameter(let param):
|
|
return "\(param) is required"
|
|
case .networkError(let message):
|
|
return "Network error: \(message)"
|
|
}
|
|
}
|
|
}
|