@capgo/capacitor-alarm 7.1.14 → 7.1.16
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.
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import Foundation
|
|
2
|
+
#if canImport(UIKit)
|
|
3
|
+
import UIKit
|
|
4
|
+
#endif
|
|
2
5
|
|
|
3
6
|
#if canImport(AlarmKit)
|
|
4
7
|
import AlarmKit
|
|
8
|
+
#if canImport(SwiftUI)
|
|
9
|
+
import SwiftUI
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
@available(iOS 26.0, *)
|
|
13
|
+
private struct AlarmBridgeMetadata: AlarmMetadata {
|
|
14
|
+
let label: String
|
|
15
|
+
}
|
|
5
16
|
#endif
|
|
6
17
|
|
|
7
18
|
class AlarmKitBridge {
|
|
@@ -18,7 +29,6 @@ class AlarmKitBridge {
|
|
|
18
29
|
if #available(iOS 26.0, *) {
|
|
19
30
|
Task {
|
|
20
31
|
do {
|
|
21
|
-
// Acquire the AlarmKit manager; many Apple frameworks use a shared singleton.
|
|
22
32
|
let alarmManager = AlarmManager.shared
|
|
23
33
|
let state = try await alarmManager.requestAuthorization()
|
|
24
34
|
completion(state == .authorized, nil)
|
|
@@ -35,9 +45,34 @@ class AlarmKitBridge {
|
|
|
35
45
|
static func createAlarm(hour: Int, minute: Int, label: String?, completion: @escaping (Bool, String?) -> Void) {
|
|
36
46
|
#if canImport(AlarmKit)
|
|
37
47
|
if #available(iOS 26.0, *) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
guard (0..<24).contains(hour), (0..<60).contains(minute) else {
|
|
49
|
+
completion(false, "Invalid time components for alarm.")
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Task {
|
|
54
|
+
do {
|
|
55
|
+
guard let triggerDate = nextTriggerDate(hour: hour, minute: minute) else {
|
|
56
|
+
completion(false, "Unable to compute next trigger date.")
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
let displayLabel = sanitizedLabel(label)
|
|
60
|
+
let configuration = try alarmConfiguration(triggerDate: triggerDate, label: displayLabel)
|
|
61
|
+
|
|
62
|
+
_ = try await AlarmManager.shared.schedule(id: UUID(), configuration: configuration)
|
|
63
|
+
|
|
64
|
+
let formatter = DateFormatter()
|
|
65
|
+
formatter.dateStyle = .none
|
|
66
|
+
formatter.timeStyle = .short
|
|
67
|
+
formatter.locale = Locale.current
|
|
68
|
+
formatter.timeZone = Calendar.current.timeZone
|
|
69
|
+
|
|
70
|
+
let message = "Alarm scheduled for \(formatter.string(from: triggerDate))."
|
|
71
|
+
completion(true, message)
|
|
72
|
+
} catch {
|
|
73
|
+
completion(false, "Failed to schedule alarm: \(error.localizedDescription)")
|
|
74
|
+
}
|
|
75
|
+
}
|
|
41
76
|
return
|
|
42
77
|
}
|
|
43
78
|
#endif
|
|
@@ -45,13 +80,84 @@ class AlarmKitBridge {
|
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
static func openAlarms(completion: @escaping (Bool, String?) -> Void) {
|
|
48
|
-
#if canImport(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return
|
|
83
|
+
#if canImport(UIKit)
|
|
84
|
+
DispatchQueue.main.async {
|
|
85
|
+
let candidates = AlarmKitBridge.clockURLCandidates()
|
|
86
|
+
attemptOpenClock(urls: candidates, index: 0, completion: completion)
|
|
53
87
|
}
|
|
88
|
+
#else
|
|
89
|
+
completion(false, "Clock UI cannot be opened on this platform.")
|
|
54
90
|
#endif
|
|
55
|
-
completion(false, "AlarmKit not available on this device/SDK")
|
|
56
91
|
}
|
|
57
92
|
}
|
|
93
|
+
|
|
94
|
+
#if canImport(AlarmKit)
|
|
95
|
+
@available(iOS 26.0, *)
|
|
96
|
+
private extension AlarmKitBridge {
|
|
97
|
+
static func sanitizedLabel(_ label: String?) -> String {
|
|
98
|
+
let trimmed = label?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
99
|
+
return trimmed.isEmpty ? "Alarm" : trimmed
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static func nextTriggerDate(hour: Int, minute: Int) -> Date? {
|
|
103
|
+
let now = Date()
|
|
104
|
+
var components = Calendar.current.dateComponents([.year, .month, .day], from: now)
|
|
105
|
+
components.hour = hour
|
|
106
|
+
components.minute = minute
|
|
107
|
+
components.second = 0
|
|
108
|
+
|
|
109
|
+
guard let candidate = Calendar.current.date(from: components) else { return nil }
|
|
110
|
+
if candidate.timeIntervalSince(now) > 1 {
|
|
111
|
+
return candidate
|
|
112
|
+
}
|
|
113
|
+
return Calendar.current.date(byAdding: .day, value: 1, to: candidate)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static func alarmConfiguration(triggerDate: Date, label: String) throws -> AlarmManager.AlarmConfiguration<AlarmBridgeMetadata> {
|
|
117
|
+
#if canImport(SwiftUI)
|
|
118
|
+
let stopTitle: LocalizedStringResource = LocalizedStringResource("Stop")
|
|
119
|
+
let stopButton = AlarmButton(text: stopTitle, textColor: Color.white, systemImageName: "stop.fill")
|
|
120
|
+
|
|
121
|
+
let titleResource = LocalizedStringResource(String.LocalizationValue(label))
|
|
122
|
+
let alert = AlarmPresentation.Alert(title: titleResource, stopButton: stopButton)
|
|
123
|
+
let presentation = AlarmPresentation(alert: alert)
|
|
124
|
+
|
|
125
|
+
let tintColor = Color.orange
|
|
126
|
+
let metadata = AlarmBridgeMetadata(label: label)
|
|
127
|
+
|
|
128
|
+
let attributes = AlarmAttributes<AlarmBridgeMetadata>(presentation: presentation, metadata: metadata, tintColor: tintColor)
|
|
129
|
+
return AlarmManager.AlarmConfiguration<AlarmBridgeMetadata>.alarm(
|
|
130
|
+
schedule: .fixed(triggerDate),
|
|
131
|
+
attributes: attributes
|
|
132
|
+
)
|
|
133
|
+
#else
|
|
134
|
+
struct MissingSwiftUI: Error {}
|
|
135
|
+
throw MissingSwiftUI()
|
|
136
|
+
#endif
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
#endif
|
|
141
|
+
|
|
142
|
+
#if canImport(UIKit)
|
|
143
|
+
private extension AlarmKitBridge {
|
|
144
|
+
static func clockURLCandidates() -> [URL] {
|
|
145
|
+
["clock-alarm://", "clock://", "clock-app://"].compactMap { URL(string: $0) }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static func attemptOpenClock(urls: [URL], index: Int, completion: @escaping (Bool, String?) -> Void) {
|
|
149
|
+
guard index < urls.count else {
|
|
150
|
+
completion(false, "Clock app not reachable on this device.")
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
UIApplication.shared.open(urls[index], options: [:]) { success in
|
|
155
|
+
if success {
|
|
156
|
+
completion(true, nil)
|
|
157
|
+
} else {
|
|
158
|
+
attemptOpenClock(urls: urls, index: index + 1, completion: completion)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
#endif
|