@capawesome/capacitor-alarm 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapawesomeCapacitorAlarm.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +449 -0
- package/android/build.gradle +58 -0
- package/android/src/main/AndroidManifest.xml +9 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/Alarm.java +85 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/AlarmPlugin.java +154 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/classes/CustomException.java +20 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/classes/CustomExceptions.java +16 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/classes/options/CreateAlarmOptions.java +124 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/classes/options/CreateTimerOptions.java +48 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/classes/results/CreateAlarmResult.java +25 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/classes/results/IsAvailableResult.java +22 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/interfaces/Callback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/interfaces/EmptyCallback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/interfaces/NonEmptyResultCallback.java +7 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/alarm/interfaces/Result.java +7 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +743 -0
- package/dist/esm/definitions.d.ts +349 -0
- package/dist/esm/definitions.js +55 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +12 -0
- package/dist/esm/web.js +28 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +97 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +100 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/Alarm.swift +148 -0
- package/ios/Plugin/AlarmPlugin.swift +147 -0
- package/ios/Plugin/Classes/Options/CancelAlarmOptions.swift +20 -0
- package/ios/Plugin/Classes/Options/CreateAlarmOptions.swift +70 -0
- package/ios/Plugin/Classes/Results/CreateAlarmResult.swift +16 -0
- package/ios/Plugin/Classes/Results/GetAlarmsResult.swift +49 -0
- package/ios/Plugin/Classes/Results/IsAvailableResult.swift +16 -0
- package/ios/Plugin/Classes/Results/PermissionStatusResult.swift +16 -0
- package/ios/Plugin/Enums/CustomError.swift +47 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Protocols/Result.swift +6 -0
- package/package.json +95 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * @since 0.1.0\n */\nexport var ErrorCode;\n(function (ErrorCode) {\n /**\n * No app that can handle alarms was found on the device.\n *\n * @since 0.1.0\n */\n ErrorCode[\"NoClockApp\"] = \"NO_CLOCK_APP\";\n /**\n * The permission to schedule alarms was denied.\n *\n * @since 0.1.0\n */\n ErrorCode[\"PermissionDenied\"] = \"PERMISSION_DENIED\";\n})(ErrorCode || (ErrorCode = {}));\n/**\n * The days of the week.\n *\n * @since 0.1.0\n */\nexport var Weekday;\n(function (Weekday) {\n /**\n * @since 0.1.0\n */\n Weekday[\"Friday\"] = \"FRIDAY\";\n /**\n * @since 0.1.0\n */\n Weekday[\"Monday\"] = \"MONDAY\";\n /**\n * @since 0.1.0\n */\n Weekday[\"Saturday\"] = \"SATURDAY\";\n /**\n * @since 0.1.0\n */\n Weekday[\"Sunday\"] = \"SUNDAY\";\n /**\n * @since 0.1.0\n */\n Weekday[\"Thursday\"] = \"THURSDAY\";\n /**\n * @since 0.1.0\n */\n Weekday[\"Tuesday\"] = \"TUESDAY\";\n /**\n * @since 0.1.0\n */\n Weekday[\"Wednesday\"] = \"WEDNESDAY\";\n})(Weekday || (Weekday = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst Alarm = registerPlugin('Alarm', {\n web: () => import('./web').then(m => new m.AlarmWeb()),\n});\nexport * from './definitions';\nexport { Alarm };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class AlarmWeb extends WebPlugin {\n async cancelAlarm(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async checkPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n async createAlarm(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async createTimer(_options) {\n throw this.unimplemented('Not implemented on web.');\n }\n async getAlarms() {\n throw this.unimplemented('Not implemented on web.');\n }\n async isAvailable() {\n throw this.unimplemented('Not implemented on web.');\n }\n async openAlarms() {\n throw this.unimplemented('Not implemented on web.');\n }\n async requestPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["ErrorCode","Weekday","registerPlugin","WebPlugin"],"mappings":";;;IAAA;IACA;IACA;AACWA;IACX,CAAC,UAAU,SAAS,EAAE;IACtB;IACA;IACA;IACA;IACA;IACA,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,cAAc;IAC5C;IACA;IACA;IACA;IACA;IACA,IAAI,SAAS,CAAC,kBAAkB,CAAC,GAAG,mBAAmB;IACvD,CAAC,EAAEA,iBAAS,KAAKA,iBAAS,GAAG,EAAE,CAAC,CAAC;IACjC;IACA;IACA;IACA;IACA;AACWC;IACX,CAAC,UAAU,OAAO,EAAE;IACpB;IACA;IACA;IACA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ;IAChC;IACA;IACA;IACA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ;IAChC;IACA;IACA;IACA,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU;IACpC;IACA;IACA;IACA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ;IAChC;IACA;IACA;IACA,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU;IACpC;IACA;IACA;IACA,IAAI,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS;IAClC;IACA;IACA;IACA,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW;IACtC,CAAC,EAAEA,eAAO,KAAKA,eAAO,GAAG,EAAE,CAAC,CAAC;;ACpDxB,UAAC,KAAK,GAAGC,mBAAc,CAAC,OAAO,EAAE;IACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC;;ICFM,MAAM,QAAQ,SAASC,cAAS,CAAC;IACxC,IAAI,MAAM,WAAW,CAAC,QAAQ,EAAE;IAChC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,QAAQ,EAAE;IAChC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,QAAQ,EAAE;IAChC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,SAAS,GAAG;IACtB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,WAAW,GAAG;IACxB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import AlarmKit
|
|
4
|
+
import SwiftUI
|
|
5
|
+
|
|
6
|
+
@available(iOS 26.0, *)
|
|
7
|
+
@objc public class Alarm: NSObject {
|
|
8
|
+
private struct EmptyMetadata: AlarmMetadata {}
|
|
9
|
+
|
|
10
|
+
private let labelsUserDefaultsKey = "capawesome_capacitor_alarm_labels"
|
|
11
|
+
private let manager = AlarmKit.AlarmManager.shared
|
|
12
|
+
private let plugin: AlarmPlugin
|
|
13
|
+
|
|
14
|
+
init(plugin: AlarmPlugin) {
|
|
15
|
+
self.plugin = plugin
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@objc public func cancelAlarm(_ options: CancelAlarmOptions, completion: @escaping (Error?) -> Void) {
|
|
19
|
+
do {
|
|
20
|
+
try manager.cancel(id: options.id)
|
|
21
|
+
removeLabel(for: options.id)
|
|
22
|
+
completion(nil)
|
|
23
|
+
} catch {
|
|
24
|
+
completion(error)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@objc public func checkPermissions(completion: @escaping (PermissionStatusResult) -> Void) {
|
|
29
|
+
completion(PermissionStatusResult(alarms: getPermissionState(from: manager.authorizationState)))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@objc public func createAlarm(_ options: CreateAlarmOptions, completion: @escaping (CreateAlarmResult?, Error?) -> Void) {
|
|
33
|
+
Task {
|
|
34
|
+
do {
|
|
35
|
+
try await requestAuthorizationIfNeeded()
|
|
36
|
+
let id = UUID()
|
|
37
|
+
let attributes = AlarmAttributes<EmptyMetadata>(presentation: makePresentation(label: options.label), tintColor: .accentColor)
|
|
38
|
+
let schedule = makeSchedule(hour: options.hour, minute: options.minute, days: options.days)
|
|
39
|
+
let configuration = AlarmKit.AlarmManager.AlarmConfiguration.alarm(schedule: schedule, attributes: attributes)
|
|
40
|
+
_ = try await manager.schedule(id: id, configuration: configuration)
|
|
41
|
+
setLabel(options.label, for: id)
|
|
42
|
+
completion(CreateAlarmResult(id: id.uuidString), nil)
|
|
43
|
+
} catch {
|
|
44
|
+
completion(nil, error)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@objc public func getAlarms(completion: @escaping (GetAlarmsResult?, Error?) -> Void) {
|
|
50
|
+
do {
|
|
51
|
+
let alarms = try manager.alarms
|
|
52
|
+
completion(GetAlarmsResult(alarms: alarms, labels: getLabels()), nil)
|
|
53
|
+
} catch {
|
|
54
|
+
completion(nil, error)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@objc public func isAvailable(completion: @escaping (IsAvailableResult) -> Void) {
|
|
59
|
+
completion(IsAvailableResult(available: true))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@objc public func requestPermissions(completion: @escaping (PermissionStatusResult?, Error?) -> Void) {
|
|
63
|
+
Task {
|
|
64
|
+
do {
|
|
65
|
+
try ensureUsageDescription()
|
|
66
|
+
let state = try await manager.requestAuthorization()
|
|
67
|
+
completion(PermissionStatusResult(alarms: getPermissionState(from: state)), nil)
|
|
68
|
+
} catch {
|
|
69
|
+
completion(nil, error)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private func ensureUsageDescription() throws {
|
|
75
|
+
guard Bundle.main.object(forInfoDictionaryKey: "NSAlarmKitUsageDescription") is String else {
|
|
76
|
+
throw CustomError.privacyDescriptionsMissing
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private func getLabels() -> [String: String] {
|
|
81
|
+
return UserDefaults.standard.dictionary(forKey: labelsUserDefaultsKey) as? [String: String] ?? [:]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private func getPermissionState(from state: AlarmKit.AlarmManager.AuthorizationState) -> String {
|
|
85
|
+
switch state {
|
|
86
|
+
case .authorized:
|
|
87
|
+
return "granted"
|
|
88
|
+
case .denied:
|
|
89
|
+
return "denied"
|
|
90
|
+
case .notDetermined:
|
|
91
|
+
return "prompt"
|
|
92
|
+
@unknown default:
|
|
93
|
+
return "prompt"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private func makePresentation(label: String?) -> AlarmPresentation {
|
|
98
|
+
let title = LocalizedStringResource("\(label ?? "Alarm")")
|
|
99
|
+
let alert: AlarmPresentation.Alert
|
|
100
|
+
if #available(iOS 26.1, *) {
|
|
101
|
+
alert = AlarmPresentation.Alert(title: title)
|
|
102
|
+
} else {
|
|
103
|
+
alert = AlarmPresentation.Alert(title: title, stopButton: AlarmButton(text: "Stop", textColor: .white, systemImageName: "stop.circle"))
|
|
104
|
+
}
|
|
105
|
+
return AlarmPresentation(alert: alert)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private func makeSchedule(hour: Int, minute: Int, days: [Locale.Weekday]?) -> AlarmKit.Alarm.Schedule {
|
|
109
|
+
let time = AlarmKit.Alarm.Schedule.Relative.Time(hour: hour, minute: minute)
|
|
110
|
+
var recurrence = AlarmKit.Alarm.Schedule.Relative.Recurrence.never
|
|
111
|
+
if let days = days, !days.isEmpty {
|
|
112
|
+
recurrence = .weekly(days)
|
|
113
|
+
}
|
|
114
|
+
return .relative(AlarmKit.Alarm.Schedule.Relative(time: time, repeats: recurrence))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private func removeLabel(for id: UUID) {
|
|
118
|
+
var labels = getLabels()
|
|
119
|
+
labels.removeValue(forKey: id.uuidString)
|
|
120
|
+
UserDefaults.standard.set(labels, forKey: labelsUserDefaultsKey)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private func requestAuthorizationIfNeeded() async throws {
|
|
124
|
+
switch manager.authorizationState {
|
|
125
|
+
case .authorized:
|
|
126
|
+
return
|
|
127
|
+
case .denied:
|
|
128
|
+
throw CustomError.permissionDenied
|
|
129
|
+
case .notDetermined:
|
|
130
|
+
try ensureUsageDescription()
|
|
131
|
+
let state = try await manager.requestAuthorization()
|
|
132
|
+
guard state == .authorized else {
|
|
133
|
+
throw CustomError.permissionDenied
|
|
134
|
+
}
|
|
135
|
+
@unknown default:
|
|
136
|
+
throw CustomError.permissionDenied
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private func setLabel(_ label: String?, for id: UUID) {
|
|
141
|
+
guard let label = label else {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
var labels = getLabels()
|
|
145
|
+
labels[id.uuidString] = label
|
|
146
|
+
UserDefaults.standard.set(labels, forKey: labelsUserDefaultsKey)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc(AlarmPlugin)
|
|
5
|
+
public class AlarmPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
6
|
+
public let identifier = "AlarmPlugin"
|
|
7
|
+
public let jsName = "Alarm"
|
|
8
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
9
|
+
CAPPluginMethod(name: "cancelAlarm", returnType: CAPPluginReturnPromise),
|
|
10
|
+
CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
|
|
11
|
+
CAPPluginMethod(name: "createAlarm", returnType: CAPPluginReturnPromise),
|
|
12
|
+
CAPPluginMethod(name: "createTimer", returnType: CAPPluginReturnPromise),
|
|
13
|
+
CAPPluginMethod(name: "getAlarms", returnType: CAPPluginReturnPromise),
|
|
14
|
+
CAPPluginMethod(name: "isAvailable", returnType: CAPPluginReturnPromise),
|
|
15
|
+
CAPPluginMethod(name: "openAlarms", returnType: CAPPluginReturnPromise),
|
|
16
|
+
CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise)
|
|
17
|
+
]
|
|
18
|
+
public static let tag = "AlarmPlugin"
|
|
19
|
+
|
|
20
|
+
private var implementation: Any?
|
|
21
|
+
|
|
22
|
+
override public func load() {
|
|
23
|
+
if #available(iOS 26.0, *) {
|
|
24
|
+
self.implementation = Alarm(plugin: self)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@objc func cancelAlarm(_ call: CAPPluginCall) {
|
|
29
|
+
guard #available(iOS 26.0, *), let implementation = implementation as? Alarm else {
|
|
30
|
+
rejectCallAsUnavailable(call)
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
do {
|
|
34
|
+
let options = try CancelAlarmOptions(call)
|
|
35
|
+
implementation.cancelAlarm(options, completion: { error in
|
|
36
|
+
if let error = error {
|
|
37
|
+
self.rejectCall(call, error)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
self.resolveCall(call)
|
|
41
|
+
})
|
|
42
|
+
} catch {
|
|
43
|
+
self.rejectCall(call, error)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@objc override public func checkPermissions(_ call: CAPPluginCall) {
|
|
48
|
+
guard #available(iOS 26.0, *), let implementation = implementation as? Alarm else {
|
|
49
|
+
rejectCallAsUnavailable(call)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
implementation.checkPermissions(completion: { result in
|
|
53
|
+
self.resolveCall(call, result)
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@objc func createAlarm(_ call: CAPPluginCall) {
|
|
58
|
+
guard #available(iOS 26.0, *), let implementation = implementation as? Alarm else {
|
|
59
|
+
rejectCallAsUnavailable(call)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
do {
|
|
63
|
+
let options = try CreateAlarmOptions(call)
|
|
64
|
+
implementation.createAlarm(options, completion: { result, error in
|
|
65
|
+
if let error = error {
|
|
66
|
+
self.rejectCall(call, error)
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
self.resolveCall(call, result)
|
|
70
|
+
})
|
|
71
|
+
} catch {
|
|
72
|
+
self.rejectCall(call, error)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@objc func createTimer(_ call: CAPPluginCall) {
|
|
77
|
+
rejectCallAsUnimplemented(call)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@objc func getAlarms(_ call: CAPPluginCall) {
|
|
81
|
+
guard #available(iOS 26.0, *), let implementation = implementation as? Alarm else {
|
|
82
|
+
rejectCallAsUnavailable(call)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
implementation.getAlarms(completion: { result, error in
|
|
86
|
+
if let error = error {
|
|
87
|
+
self.rejectCall(call, error)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
self.resolveCall(call, result)
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@objc func isAvailable(_ call: CAPPluginCall) {
|
|
95
|
+
if #available(iOS 26.0, *), let implementation = implementation as? Alarm {
|
|
96
|
+
implementation.isAvailable(completion: { result in
|
|
97
|
+
self.resolveCall(call, result)
|
|
98
|
+
})
|
|
99
|
+
} else {
|
|
100
|
+
resolveCall(call, IsAvailableResult(available: false))
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@objc func openAlarms(_ call: CAPPluginCall) {
|
|
105
|
+
rejectCallAsUnimplemented(call)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@objc override public func requestPermissions(_ call: CAPPluginCall) {
|
|
109
|
+
guard #available(iOS 26.0, *), let implementation = implementation as? Alarm else {
|
|
110
|
+
rejectCallAsUnavailable(call)
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
implementation.requestPermissions(completion: { result, error in
|
|
114
|
+
if let error = error {
|
|
115
|
+
self.rejectCall(call, error)
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
self.resolveCall(call, result)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private func rejectCall(_ call: CAPPluginCall, _ error: Error) {
|
|
123
|
+
CAPLog.print("[", AlarmPlugin.tag, "] ", error)
|
|
124
|
+
let code = (error as? CustomError)?.code
|
|
125
|
+
call.reject(error.localizedDescription, code)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private func rejectCallAsUnavailable(_ call: CAPPluginCall) {
|
|
129
|
+
call.unavailable("This method is not available on this platform.")
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private func rejectCallAsUnimplemented(_ call: CAPPluginCall) {
|
|
133
|
+
call.unimplemented("This method is not available on this platform.")
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private func resolveCall(_ call: CAPPluginCall) {
|
|
137
|
+
call.resolve()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private func resolveCall(_ call: CAPPluginCall, _ result: Result?) {
|
|
141
|
+
if let result = result?.toJSObject() as? JSObject {
|
|
142
|
+
call.resolve(result)
|
|
143
|
+
} else {
|
|
144
|
+
call.resolve()
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc public class CancelAlarmOptions: NSObject {
|
|
5
|
+
let id: UUID
|
|
6
|
+
|
|
7
|
+
init(_ call: CAPPluginCall) throws {
|
|
8
|
+
self.id = try CancelAlarmOptions.getIdFromCall(call)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
private static func getIdFromCall(_ call: CAPPluginCall) throws -> UUID {
|
|
12
|
+
guard let id = call.getString("id") else {
|
|
13
|
+
throw CustomError.idMissing
|
|
14
|
+
}
|
|
15
|
+
guard let uuid = UUID(uuidString: id) else {
|
|
16
|
+
throw CustomError.idInvalid
|
|
17
|
+
}
|
|
18
|
+
return uuid
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@available(iOS 26.0, *)
|
|
5
|
+
@objc public class CreateAlarmOptions: NSObject {
|
|
6
|
+
let days: [Locale.Weekday]?
|
|
7
|
+
let hour: Int
|
|
8
|
+
let label: String?
|
|
9
|
+
let minute: Int
|
|
10
|
+
|
|
11
|
+
init(_ call: CAPPluginCall) throws {
|
|
12
|
+
self.days = try CreateAlarmOptions.getDaysFromCall(call)
|
|
13
|
+
self.hour = try CreateAlarmOptions.getHourFromCall(call)
|
|
14
|
+
self.label = call.getString("label")
|
|
15
|
+
self.minute = try CreateAlarmOptions.getMinuteFromCall(call)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private static func getDaysFromCall(_ call: CAPPluginCall) throws -> [Locale.Weekday]? {
|
|
19
|
+
guard let days = call.getArray("days") else {
|
|
20
|
+
return nil
|
|
21
|
+
}
|
|
22
|
+
return try days.map { day in
|
|
23
|
+
guard let weekday = day as? String else {
|
|
24
|
+
throw CustomError.daysInvalid
|
|
25
|
+
}
|
|
26
|
+
return try CreateAlarmOptions.getWeekdayFromString(weekday)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private static func getHourFromCall(_ call: CAPPluginCall) throws -> Int {
|
|
31
|
+
guard let hour = call.getInt("hour") else {
|
|
32
|
+
throw CustomError.hourMissing
|
|
33
|
+
}
|
|
34
|
+
guard (0...23).contains(hour) else {
|
|
35
|
+
throw CustomError.hourInvalid
|
|
36
|
+
}
|
|
37
|
+
return hour
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private static func getMinuteFromCall(_ call: CAPPluginCall) throws -> Int {
|
|
41
|
+
guard let minute = call.getInt("minute") else {
|
|
42
|
+
throw CustomError.minuteMissing
|
|
43
|
+
}
|
|
44
|
+
guard (0...59).contains(minute) else {
|
|
45
|
+
throw CustomError.minuteInvalid
|
|
46
|
+
}
|
|
47
|
+
return minute
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private static func getWeekdayFromString(_ weekday: String) throws -> Locale.Weekday {
|
|
51
|
+
switch weekday {
|
|
52
|
+
case "FRIDAY":
|
|
53
|
+
return .friday
|
|
54
|
+
case "MONDAY":
|
|
55
|
+
return .monday
|
|
56
|
+
case "SATURDAY":
|
|
57
|
+
return .saturday
|
|
58
|
+
case "SUNDAY":
|
|
59
|
+
return .sunday
|
|
60
|
+
case "THURSDAY":
|
|
61
|
+
return .thursday
|
|
62
|
+
case "TUESDAY":
|
|
63
|
+
return .tuesday
|
|
64
|
+
case "WEDNESDAY":
|
|
65
|
+
return .wednesday
|
|
66
|
+
default:
|
|
67
|
+
throw CustomError.daysInvalid
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc public class CreateAlarmResult: NSObject, Result {
|
|
5
|
+
let id: String?
|
|
6
|
+
|
|
7
|
+
init(id: String?) {
|
|
8
|
+
self.id = id
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@objc public func toJSObject() -> AnyObject {
|
|
12
|
+
var result = JSObject()
|
|
13
|
+
result["id"] = id == nil ? NSNull() : id
|
|
14
|
+
return result as AnyObject
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import AlarmKit
|
|
4
|
+
|
|
5
|
+
@available(iOS 26.0, *)
|
|
6
|
+
@objc public class GetAlarmsResult: NSObject, Result {
|
|
7
|
+
let alarms: [AlarmKit.Alarm]
|
|
8
|
+
let labels: [String: String]
|
|
9
|
+
|
|
10
|
+
init(alarms: [AlarmKit.Alarm], labels: [String: String]) {
|
|
11
|
+
self.alarms = alarms
|
|
12
|
+
self.labels = labels
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@objc public func toJSObject() -> AnyObject {
|
|
16
|
+
var alarmsResult = JSArray()
|
|
17
|
+
for alarm in alarms {
|
|
18
|
+
let label = labels[alarm.id.uuidString]
|
|
19
|
+
let time = GetAlarmsResult.getTimeFromAlarm(alarm)
|
|
20
|
+
var alarmResult = JSObject()
|
|
21
|
+
alarmResult["enabled"] = alarm.state == .scheduled || alarm.state == .alerting
|
|
22
|
+
alarmResult["hour"] = time == nil ? NSNull() : time?.hour
|
|
23
|
+
alarmResult["id"] = alarm.id.uuidString
|
|
24
|
+
alarmResult["label"] = label == nil ? NSNull() : label
|
|
25
|
+
alarmResult["minute"] = time == nil ? NSNull() : time?.minute
|
|
26
|
+
alarmsResult.append(alarmResult)
|
|
27
|
+
}
|
|
28
|
+
var result = JSObject()
|
|
29
|
+
result["alarms"] = alarmsResult
|
|
30
|
+
return result as AnyObject
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private static func getTimeFromAlarm(_ alarm: AlarmKit.Alarm) -> (hour: Int, minute: Int)? {
|
|
34
|
+
switch alarm.schedule {
|
|
35
|
+
case .fixed(let date):
|
|
36
|
+
let components = Calendar.current.dateComponents([.hour, .minute], from: date)
|
|
37
|
+
guard let hour = components.hour, let minute = components.minute else {
|
|
38
|
+
return nil
|
|
39
|
+
}
|
|
40
|
+
return (hour, minute)
|
|
41
|
+
case .relative(let relative):
|
|
42
|
+
return (relative.time.hour, relative.time.minute)
|
|
43
|
+
case .none:
|
|
44
|
+
return nil
|
|
45
|
+
@unknown default:
|
|
46
|
+
return nil
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc public class IsAvailableResult: NSObject, Result {
|
|
5
|
+
let available: Bool
|
|
6
|
+
|
|
7
|
+
init(available: Bool) {
|
|
8
|
+
self.available = available
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@objc public func toJSObject() -> AnyObject {
|
|
12
|
+
var result = JSObject()
|
|
13
|
+
result["available"] = available
|
|
14
|
+
return result as AnyObject
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc public class PermissionStatusResult: NSObject, Result {
|
|
5
|
+
let alarms: String
|
|
6
|
+
|
|
7
|
+
init(alarms: String) {
|
|
8
|
+
self.alarms = alarms
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@objc public func toJSObject() -> AnyObject {
|
|
12
|
+
var result = JSObject()
|
|
13
|
+
result["alarms"] = alarms
|
|
14
|
+
return result as AnyObject
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
enum CustomError: Error {
|
|
4
|
+
case daysInvalid
|
|
5
|
+
case hourInvalid
|
|
6
|
+
case hourMissing
|
|
7
|
+
case idInvalid
|
|
8
|
+
case idMissing
|
|
9
|
+
case minuteInvalid
|
|
10
|
+
case minuteMissing
|
|
11
|
+
case permissionDenied
|
|
12
|
+
case privacyDescriptionsMissing
|
|
13
|
+
|
|
14
|
+
var code: String? {
|
|
15
|
+
switch self {
|
|
16
|
+
case .permissionDenied:
|
|
17
|
+
return "PERMISSION_DENIED"
|
|
18
|
+
case .daysInvalid, .hourInvalid, .hourMissing, .idInvalid, .idMissing, .minuteInvalid, .minuteMissing, .privacyDescriptionsMissing:
|
|
19
|
+
return nil
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
extension CustomError: LocalizedError {
|
|
25
|
+
public var errorDescription: String? {
|
|
26
|
+
switch self {
|
|
27
|
+
case .daysInvalid:
|
|
28
|
+
return NSLocalizedString("days must contain only valid weekdays.", comment: "daysInvalid")
|
|
29
|
+
case .hourInvalid:
|
|
30
|
+
return NSLocalizedString("hour must be between 0 and 23.", comment: "hourInvalid")
|
|
31
|
+
case .hourMissing:
|
|
32
|
+
return NSLocalizedString("hour must be provided.", comment: "hourMissing")
|
|
33
|
+
case .idInvalid:
|
|
34
|
+
return NSLocalizedString("id must be a valid UUID.", comment: "idInvalid")
|
|
35
|
+
case .idMissing:
|
|
36
|
+
return NSLocalizedString("id must be provided.", comment: "idMissing")
|
|
37
|
+
case .minuteInvalid:
|
|
38
|
+
return NSLocalizedString("minute must be between 0 and 59.", comment: "minuteInvalid")
|
|
39
|
+
case .minuteMissing:
|
|
40
|
+
return NSLocalizedString("minute must be provided.", comment: "minuteMissing")
|
|
41
|
+
case .permissionDenied:
|
|
42
|
+
return NSLocalizedString("The permission to schedule alarms was denied.", comment: "permissionDenied")
|
|
43
|
+
case .privacyDescriptionsMissing:
|
|
44
|
+
return NSLocalizedString("One or more privacy descriptions are missing.", comment: "privacyDescriptionsMissing")
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>FMWK</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>1.0</string>
|
|
19
|
+
<key>CFBundleVersion</key>
|
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
21
|
+
<key>NSPrincipalClass</key>
|
|
22
|
+
<string></string>
|
|
23
|
+
</dict>
|
|
24
|
+
</plist>
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capawesome/capacitor-alarm",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Capacitor plugin to create system alarms and timers.",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Plugin/",
|
|
14
|
+
"CapawesomeCapacitorAlarm.podspec",
|
|
15
|
+
"Package.swift"
|
|
16
|
+
],
|
|
17
|
+
"author": "Robin Genz <mail@robingenz.dev>",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/capawesome-team/capacitor-plugins.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/capawesome-team/capacitor-plugins/issues"
|
|
25
|
+
},
|
|
26
|
+
"funding": [
|
|
27
|
+
{
|
|
28
|
+
"type": "github",
|
|
29
|
+
"url": "https://github.com/sponsors/capawesome-team/"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "opencollective",
|
|
33
|
+
"url": "https://opencollective.com/capawesome"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"homepage": "https://capawesome.io/docs/sdks/capacitor/alarm/",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"capacitor",
|
|
39
|
+
"plugin",
|
|
40
|
+
"native",
|
|
41
|
+
"alarm",
|
|
42
|
+
"alarmkit",
|
|
43
|
+
"timer",
|
|
44
|
+
"clock"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
48
|
+
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
|
|
49
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
50
|
+
"verify:web": "npm run build",
|
|
51
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
52
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
53
|
+
"eslint": "eslint . --ext ts",
|
|
54
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
55
|
+
"swiftlint": "node-swiftlint",
|
|
56
|
+
"docgen": "docgen --api AlarmPlugin --output-readme README.md --output-json dist/docs.json",
|
|
57
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
58
|
+
"clean": "rimraf ./dist",
|
|
59
|
+
"watch": "tsc --watch",
|
|
60
|
+
"ios:pod:install": "cd ios && pod install --repo-update && cd ..",
|
|
61
|
+
"ios:spm:install": "cd ios && swift package resolve && cd ..",
|
|
62
|
+
"prepublishOnly": "npm run build"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@capacitor/android": "8.0.0",
|
|
66
|
+
"@capacitor/cli": "8.0.0",
|
|
67
|
+
"@capacitor/core": "8.0.0",
|
|
68
|
+
"@capacitor/docgen": "0.3.1",
|
|
69
|
+
"@capacitor/ios": "8.0.0",
|
|
70
|
+
"@ionic/eslint-config": "0.4.0",
|
|
71
|
+
"eslint": "8.57.0",
|
|
72
|
+
"prettier-plugin-java": "2.6.7",
|
|
73
|
+
"rimraf": "6.1.2",
|
|
74
|
+
"rollup": "4.53.3",
|
|
75
|
+
"swiftlint": "2.0.0",
|
|
76
|
+
"typescript": "5.9.3"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"@capacitor/core": ">=8.0.0"
|
|
80
|
+
},
|
|
81
|
+
"eslintConfig": {
|
|
82
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
83
|
+
},
|
|
84
|
+
"capacitor": {
|
|
85
|
+
"ios": {
|
|
86
|
+
"src": "ios"
|
|
87
|
+
},
|
|
88
|
+
"android": {
|
|
89
|
+
"src": "android"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"publishConfig": {
|
|
93
|
+
"access": "public"
|
|
94
|
+
}
|
|
95
|
+
}
|