mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-01-31 00:45:24 +01:00
* chore(ios): consolidate optional argument standard mark all optional iOS arguments as `var <name>: Type?`, following the pattern described in the documentation: https://v2.tauri.app/develop/plugins/develop-mobile/#ios * chore: add missing Info.plist to example
286 lines
7.3 KiB
Swift
286 lines
7.3 KiB
Swift
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import SwiftRs
|
|
import Tauri
|
|
import UIKit
|
|
import UserNotifications
|
|
import WebKit
|
|
|
|
enum ShowNotificationError: LocalizedError {
|
|
case make(Error)
|
|
case create(Error)
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .make(let error):
|
|
return "Unable to make notification: \(error)"
|
|
case .create(let error):
|
|
return "Unable to create notification: \(error)"
|
|
}
|
|
}
|
|
}
|
|
|
|
enum ScheduleEveryKind: String, Decodable {
|
|
case year
|
|
case month
|
|
case twoWeeks
|
|
case week
|
|
case day
|
|
case hour
|
|
case minute
|
|
case second
|
|
}
|
|
|
|
struct ScheduleInterval: Decodable {
|
|
var year: Int?
|
|
var month: Int?
|
|
var day: Int?
|
|
var weekday: Int?
|
|
var hour: Int?
|
|
var minute: Int?
|
|
var second: Int?
|
|
}
|
|
|
|
enum NotificationSchedule: Decodable {
|
|
case at(date: String, repeating: Bool)
|
|
case interval(interval: ScheduleInterval)
|
|
case every(interval: ScheduleEveryKind, count: Int)
|
|
}
|
|
|
|
struct NotificationAttachmentOptions: Codable {
|
|
let iosUNNotificationAttachmentOptionsTypeHintKey: String?
|
|
let iosUNNotificationAttachmentOptionsThumbnailHiddenKey: String?
|
|
let iosUNNotificationAttachmentOptionsThumbnailClippingRectKey: String?
|
|
let iosUNNotificationAttachmentOptionsThumbnailTimeKey: String?
|
|
}
|
|
|
|
struct NotificationAttachment: Codable {
|
|
let id: String
|
|
let url: String
|
|
let options: NotificationAttachmentOptions?
|
|
}
|
|
|
|
struct Notification: Decodable {
|
|
let id: Int
|
|
var title: String
|
|
var body: String?
|
|
var extra: [String: String]?
|
|
var schedule: NotificationSchedule?
|
|
var attachments: [NotificationAttachment]?
|
|
var sound: String?
|
|
var group: String?
|
|
var actionTypeId: String?
|
|
var summary: String?
|
|
var silent: Bool?
|
|
}
|
|
|
|
struct RemoveActiveNotification: Decodable {
|
|
let id: Int
|
|
}
|
|
|
|
struct RemoveActiveArgs: Decodable {
|
|
let notifications: [RemoveActiveNotification]
|
|
}
|
|
|
|
func showNotification(invoke: Invoke, notification: Notification)
|
|
throws -> UNNotificationRequest
|
|
{
|
|
var content: UNNotificationContent
|
|
do {
|
|
content = try makeNotificationContent(notification)
|
|
} catch {
|
|
throw ShowNotificationError.make(error)
|
|
}
|
|
|
|
var trigger: UNNotificationTrigger?
|
|
|
|
do {
|
|
if let schedule = notification.schedule {
|
|
try trigger = handleScheduledNotification(schedule)
|
|
}
|
|
} catch {
|
|
throw ShowNotificationError.create(error)
|
|
}
|
|
|
|
// Schedule the request.
|
|
let request = UNNotificationRequest(
|
|
identifier: "\(notification.id)", content: content, trigger: trigger
|
|
)
|
|
|
|
let center = UNUserNotificationCenter.current()
|
|
center.add(request) { (error: Error?) in
|
|
if let theError = error {
|
|
invoke.reject(theError.localizedDescription)
|
|
}
|
|
}
|
|
|
|
return request
|
|
}
|
|
|
|
struct CancelArgs: Decodable {
|
|
let notifications: [Int]
|
|
}
|
|
|
|
struct Action: Decodable {
|
|
let id: String
|
|
let title: String
|
|
var requiresAuthentication: Bool?
|
|
var foreground: Bool?
|
|
var destructive: Bool?
|
|
var input: Bool?
|
|
var inputButtonTitle: String?
|
|
var inputPlaceholder: String?
|
|
}
|
|
|
|
struct ActionType: Decodable {
|
|
let id: String
|
|
let actions: [Action]
|
|
var hiddenPreviewsBodyPlaceholder: String?
|
|
var customDismissAction: Bool?
|
|
var allowInCarPlay: Bool?
|
|
var hiddenPreviewsShowTitle: Bool?
|
|
var hiddenPreviewsShowSubtitle: Bool?
|
|
var hiddenBodyPlaceholder: String?
|
|
}
|
|
|
|
struct RegisterActionTypesArgs: Decodable {
|
|
let types: [ActionType]
|
|
}
|
|
|
|
struct BatchArgs: Decodable {
|
|
let notifications: [Notification]
|
|
}
|
|
|
|
class NotificationPlugin: Plugin {
|
|
let notificationHandler = NotificationHandler()
|
|
let notificationManager = NotificationManager()
|
|
|
|
override init() {
|
|
super.init()
|
|
notificationManager.notificationHandler = notificationHandler
|
|
notificationHandler.plugin = self
|
|
}
|
|
|
|
@objc public func show(_ invoke: Invoke) throws {
|
|
let notification = try invoke.parseArgs(Notification.self)
|
|
|
|
let request = try showNotification(invoke: invoke, notification: notification)
|
|
notificationHandler.saveNotification(request.identifier, notification)
|
|
invoke.resolve(Int(request.identifier) ?? -1)
|
|
}
|
|
|
|
@objc public func batch(_ invoke: Invoke) throws {
|
|
let args = try invoke.parseArgs(BatchArgs.self)
|
|
var ids = [Int]()
|
|
|
|
for notification in args.notifications {
|
|
let request = try showNotification(invoke: invoke, notification: notification)
|
|
notificationHandler.saveNotification(request.identifier, notification)
|
|
ids.append(Int(request.identifier) ?? -1)
|
|
}
|
|
|
|
invoke.resolve(ids)
|
|
}
|
|
|
|
@objc public override func requestPermissions(_ invoke: Invoke) {
|
|
notificationHandler.requestPermissions { granted, error in
|
|
guard error == nil else {
|
|
invoke.reject(error!.localizedDescription)
|
|
return
|
|
}
|
|
invoke.resolve(["permissionState": granted ? "granted" : "denied"])
|
|
}
|
|
}
|
|
|
|
@objc public override func checkPermissions(_ invoke: Invoke) {
|
|
notificationHandler.checkPermissions { status in
|
|
let permission: String
|
|
|
|
switch status {
|
|
case .authorized, .ephemeral, .provisional:
|
|
permission = "granted"
|
|
case .denied:
|
|
permission = "denied"
|
|
case .notDetermined:
|
|
permission = "prompt"
|
|
@unknown default:
|
|
permission = "prompt"
|
|
}
|
|
|
|
invoke.resolve(["permissionState": permission])
|
|
}
|
|
}
|
|
|
|
@objc func cancel(_ invoke: Invoke) throws {
|
|
let args = try invoke.parseArgs(CancelArgs.self)
|
|
|
|
UNUserNotificationCenter.current().removePendingNotificationRequests(
|
|
withIdentifiers: args.notifications.map { String($0) }
|
|
)
|
|
invoke.resolve()
|
|
}
|
|
|
|
@objc func getPending(_ invoke: Invoke) {
|
|
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: {
|
|
(notifications) in
|
|
let ret = notifications.compactMap({ [weak self] (notification) -> PendingNotification? in
|
|
return self?.notificationHandler.toPendingNotification(notification)
|
|
})
|
|
|
|
invoke.resolve(ret)
|
|
})
|
|
}
|
|
|
|
@objc func registerActionTypes(_ invoke: Invoke) throws {
|
|
let args = try invoke.parseArgs(RegisterActionTypesArgs.self)
|
|
makeCategories(args.types)
|
|
invoke.resolve()
|
|
}
|
|
|
|
@objc func removeActive(_ invoke: Invoke) {
|
|
do {
|
|
let args = try invoke.parseArgs(RemoveActiveArgs.self)
|
|
UNUserNotificationCenter.current().removeDeliveredNotifications(
|
|
withIdentifiers: args.notifications.map { String($0.id) })
|
|
invoke.resolve()
|
|
} catch {
|
|
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
|
|
DispatchQueue.main.async(execute: {
|
|
UIApplication.shared.applicationIconBadgeNumber = 0
|
|
})
|
|
invoke.resolve()
|
|
}
|
|
}
|
|
|
|
@objc func getActive(_ invoke: Invoke) {
|
|
UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: {
|
|
(notifications) in
|
|
let ret = notifications.map({ (notification) -> ActiveNotification in
|
|
return self.notificationHandler.toActiveNotification(
|
|
notification.request)
|
|
})
|
|
invoke.resolve(ret)
|
|
})
|
|
}
|
|
|
|
@objc func createChannel(_ invoke: Invoke) {
|
|
invoke.reject("not implemented")
|
|
}
|
|
|
|
@objc func deleteChannel(_ invoke: Invoke) {
|
|
invoke.reject("not implemented")
|
|
}
|
|
|
|
@objc func listChannels(_ invoke: Invoke) {
|
|
invoke.reject("not implemented")
|
|
}
|
|
|
|
}
|
|
|
|
@_cdecl("init_plugin_notification")
|
|
func initPlugin() -> Plugin {
|
|
return NotificationPlugin()
|
|
}
|