capacitor-extended-dialog 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.
Files changed (30) hide show
  1. package/CapacitorExtendedDialog.podspec +17 -0
  2. package/Package.swift +28 -0
  3. package/README.md +190 -0
  4. package/android/build.gradle +59 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/albermonte/extendeddialog/DialogStyleOptions.java +99 -0
  7. package/android/src/main/java/com/albermonte/extendeddialog/ExtendedDialog.java +734 -0
  8. package/android/src/main/java/com/albermonte/extendeddialog/ExtendedDialogPlugin.java +207 -0
  9. package/android/src/main/java/com/albermonte/extendeddialog/FullScreenDialogFragment.java +589 -0
  10. package/android/src/main/res/.gitkeep +0 -0
  11. package/android/src/main/res/values/themes.xml +34 -0
  12. package/dist/docs.json +384 -0
  13. package/dist/esm/definitions.d.ts +101 -0
  14. package/dist/esm/definitions.js +2 -0
  15. package/dist/esm/definitions.js.map +1 -0
  16. package/dist/esm/index.d.ts +4 -0
  17. package/dist/esm/index.js +7 -0
  18. package/dist/esm/index.js.map +1 -0
  19. package/dist/esm/web.d.ts +14 -0
  20. package/dist/esm/web.js +193 -0
  21. package/dist/esm/web.js.map +1 -0
  22. package/dist/plugin.cjs.js +207 -0
  23. package/dist/plugin.cjs.js.map +1 -0
  24. package/dist/plugin.js +210 -0
  25. package/dist/plugin.js.map +1 -0
  26. package/ios/Sources/ExtendedDialogPlugin/ExtendedDialog.swift +497 -0
  27. package/ios/Sources/ExtendedDialogPlugin/ExtendedDialogPlugin.swift +177 -0
  28. package/ios/Sources/ExtendedDialogPlugin/FullScreenDialogViewController.swift +506 -0
  29. package/ios/Tests/ExtendedDialogPluginTests/ExtendedDialogPluginTests.swift +15 -0
  30. package/package.json +80 -0
@@ -0,0 +1,497 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+ public struct SelectOption {
5
+ let label: String
6
+ let value: String
7
+ }
8
+
9
+ public struct DialogStyleOptions {
10
+ var buttonColor: UIColor?
11
+ var cancelButtonColor: UIColor?
12
+ var titleColor: UIColor?
13
+ var messageColor: UIColor?
14
+ var backgroundColor: UIColor?
15
+ var titleFontSize: CGFloat?
16
+ var messageFontSize: CGFloat?
17
+ var buttonFontSize: CGFloat?
18
+
19
+ init(
20
+ buttonColor: String? = nil,
21
+ cancelButtonColor: String? = nil,
22
+ titleColor: String? = nil,
23
+ messageColor: String? = nil,
24
+ backgroundColor: String? = nil,
25
+ titleFontSize: Double? = nil,
26
+ messageFontSize: Double? = nil,
27
+ buttonFontSize: Double? = nil
28
+ ) {
29
+ self.buttonColor = Self.parseColor(buttonColor)
30
+ self.cancelButtonColor = Self.parseColor(cancelButtonColor)
31
+ self.titleColor = Self.parseColor(titleColor)
32
+ self.messageColor = Self.parseColor(messageColor)
33
+ self.backgroundColor = Self.parseColor(backgroundColor)
34
+ self.titleFontSize = titleFontSize.map { CGFloat($0) }
35
+ self.messageFontSize = messageFontSize.map { CGFloat($0) }
36
+ self.buttonFontSize = buttonFontSize.map { CGFloat($0) }
37
+ }
38
+
39
+ private static func parseColor(_ hex: String?) -> UIColor? {
40
+ guard let hex = hex, !hex.isEmpty else { return nil }
41
+ var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
42
+ hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
43
+
44
+ var rgb: UInt64 = 0
45
+ guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil }
46
+
47
+ if hexSanitized.count == 6 {
48
+ return UIColor(
49
+ red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
50
+ green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
51
+ blue: CGFloat(rgb & 0x0000FF) / 255.0,
52
+ alpha: 1.0
53
+ )
54
+ } else if hexSanitized.count == 8 {
55
+ return UIColor(
56
+ red: CGFloat((rgb & 0xFF000000) >> 24) / 255.0,
57
+ green: CGFloat((rgb & 0x00FF0000) >> 16) / 255.0,
58
+ blue: CGFloat((rgb & 0x0000FF00) >> 8) / 255.0,
59
+ alpha: CGFloat(rgb & 0x000000FF) / 255.0
60
+ )
61
+ }
62
+ return nil
63
+ }
64
+
65
+ var hasStyles: Bool {
66
+ return buttonColor != nil || cancelButtonColor != nil ||
67
+ titleColor != nil || messageColor != nil ||
68
+ backgroundColor != nil || titleFontSize != nil ||
69
+ messageFontSize != nil || buttonFontSize != nil
70
+ }
71
+ }
72
+
73
+ @objc public class ExtendedDialog: NSObject {
74
+
75
+ public typealias AlertCallback = () -> Void
76
+ public typealias ConfirmCallback = (Bool) -> Void
77
+ public typealias PromptCallback = (String, Bool) -> Void
78
+ public typealias SingleSelectCallback = (String?, Bool) -> Void
79
+ public typealias MultiSelectCallback = ([String], Bool) -> Void
80
+
81
+ // MARK: - Alert
82
+
83
+ public func showAlert(
84
+ title: String?,
85
+ message: String,
86
+ buttonTitle: String?,
87
+ fullscreen: Bool,
88
+ styleOptions: DialogStyleOptions? = nil,
89
+ callback: @escaping AlertCallback
90
+ ) {
91
+ DispatchQueue.main.async {
92
+ if fullscreen {
93
+ self.showFullScreenAlert(title: title, message: message, buttonTitle: buttonTitle, styleOptions: styleOptions, callback: callback)
94
+ } else {
95
+ self.showBasicAlert(title: title, message: message, buttonTitle: buttonTitle, styleOptions: styleOptions, callback: callback)
96
+ }
97
+ }
98
+ }
99
+
100
+ private func showBasicAlert(title: String?, message: String, buttonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping AlertCallback) {
101
+ let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
102
+
103
+ let action = UIAlertAction(title: buttonTitle ?? "OK", style: .default) { _ in
104
+ callback()
105
+ }
106
+ if let color = styleOptions?.buttonColor {
107
+ action.setValue(color, forKey: "titleTextColor")
108
+ }
109
+ alert.addAction(action)
110
+
111
+ applyLiquidGlassStyle(to: alert)
112
+ applyMessageStyle(to: alert, styleOptions: styleOptions)
113
+ presentAlert(alert)
114
+ }
115
+
116
+ private func showFullScreenAlert(title: String?, message: String, buttonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping AlertCallback) {
117
+ let vc = FullScreenDialogViewController(
118
+ dialogType: .alert,
119
+ dialogTitle: title,
120
+ message: message,
121
+ okButtonTitle: buttonTitle ?? "OK",
122
+ cancelButtonTitle: nil,
123
+ inputPlaceholder: nil,
124
+ inputText: nil,
125
+ options: nil,
126
+ selectedValue: nil,
127
+ selectedValues: nil,
128
+ styleOptions: styleOptions
129
+ )
130
+ vc.alertCallback = callback
131
+ presentFullScreen(vc)
132
+ }
133
+
134
+ // MARK: - Confirm
135
+
136
+ public func showConfirm(
137
+ title: String?,
138
+ message: String,
139
+ okButtonTitle: String?,
140
+ cancelButtonTitle: String?,
141
+ fullscreen: Bool,
142
+ styleOptions: DialogStyleOptions? = nil,
143
+ callback: @escaping ConfirmCallback
144
+ ) {
145
+ DispatchQueue.main.async {
146
+ if fullscreen {
147
+ self.showFullScreenConfirm(title: title, message: message, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, styleOptions: styleOptions, callback: callback)
148
+ } else {
149
+ self.showBasicConfirm(title: title, message: message, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, styleOptions: styleOptions, callback: callback)
150
+ }
151
+ }
152
+ }
153
+
154
+ private func showBasicConfirm(title: String?, message: String, okButtonTitle: String?, cancelButtonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping ConfirmCallback) {
155
+ let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
156
+
157
+ let cancelAction = UIAlertAction(title: cancelButtonTitle ?? "Cancel", style: .cancel) { _ in
158
+ callback(false)
159
+ }
160
+ let okAction = UIAlertAction(title: okButtonTitle ?? "OK", style: .default) { _ in
161
+ callback(true)
162
+ }
163
+
164
+ if let color = styleOptions?.cancelButtonColor {
165
+ cancelAction.setValue(color, forKey: "titleTextColor")
166
+ }
167
+ if let color = styleOptions?.buttonColor {
168
+ okAction.setValue(color, forKey: "titleTextColor")
169
+ }
170
+
171
+ alert.addAction(cancelAction)
172
+ alert.addAction(okAction)
173
+
174
+ applyLiquidGlassStyle(to: alert)
175
+ applyMessageStyle(to: alert, styleOptions: styleOptions)
176
+ presentAlert(alert)
177
+ }
178
+
179
+ private func showFullScreenConfirm(title: String?, message: String, okButtonTitle: String?, cancelButtonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping ConfirmCallback) {
180
+ let vc = FullScreenDialogViewController(
181
+ dialogType: .confirm,
182
+ dialogTitle: title,
183
+ message: message,
184
+ okButtonTitle: okButtonTitle ?? "OK",
185
+ cancelButtonTitle: cancelButtonTitle ?? "Cancel",
186
+ inputPlaceholder: nil,
187
+ inputText: nil,
188
+ options: nil,
189
+ selectedValue: nil,
190
+ selectedValues: nil,
191
+ styleOptions: styleOptions
192
+ )
193
+ vc.confirmCallback = callback
194
+ presentFullScreen(vc)
195
+ }
196
+
197
+ // MARK: - Prompt
198
+
199
+ public func showPrompt(
200
+ title: String?,
201
+ message: String,
202
+ okButtonTitle: String?,
203
+ cancelButtonTitle: String?,
204
+ inputPlaceholder: String?,
205
+ inputText: String?,
206
+ fullscreen: Bool,
207
+ focusInput: Bool = false,
208
+ styleOptions: DialogStyleOptions? = nil,
209
+ callback: @escaping PromptCallback
210
+ ) {
211
+ DispatchQueue.main.async {
212
+ if fullscreen {
213
+ self.showFullScreenPrompt(title: title, message: message, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, inputPlaceholder: inputPlaceholder, inputText: inputText, focusInput: focusInput, styleOptions: styleOptions, callback: callback)
214
+ } else {
215
+ self.showBasicPrompt(title: title, message: message, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, inputPlaceholder: inputPlaceholder, inputText: inputText, focusInput: focusInput, styleOptions: styleOptions, callback: callback)
216
+ }
217
+ }
218
+ }
219
+
220
+ private func showBasicPrompt(title: String?, message: String, okButtonTitle: String?, cancelButtonTitle: String?, inputPlaceholder: String?, inputText: String?, focusInput: Bool, styleOptions: DialogStyleOptions?, callback: @escaping PromptCallback) {
221
+ let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
222
+
223
+ alert.addTextField { textField in
224
+ textField.placeholder = inputPlaceholder
225
+ textField.text = inputText
226
+ }
227
+
228
+ let cancelAction = UIAlertAction(title: cancelButtonTitle ?? "Cancel", style: .cancel) { _ in
229
+ callback("", true)
230
+ }
231
+ let okAction = UIAlertAction(title: okButtonTitle ?? "OK", style: .default) { _ in
232
+ let value = alert.textFields?.first?.text ?? ""
233
+ callback(value, false)
234
+ }
235
+
236
+ if let color = styleOptions?.cancelButtonColor {
237
+ cancelAction.setValue(color, forKey: "titleTextColor")
238
+ }
239
+ if let color = styleOptions?.buttonColor {
240
+ okAction.setValue(color, forKey: "titleTextColor")
241
+ }
242
+
243
+ alert.addAction(cancelAction)
244
+ alert.addAction(okAction)
245
+
246
+ applyLiquidGlassStyle(to: alert)
247
+ applyMessageStyle(to: alert, styleOptions: styleOptions)
248
+ presentAlert(alert)
249
+ }
250
+
251
+ private func showFullScreenPrompt(title: String?, message: String, okButtonTitle: String?, cancelButtonTitle: String?, inputPlaceholder: String?, inputText: String?, focusInput: Bool, styleOptions: DialogStyleOptions?, callback: @escaping PromptCallback) {
252
+ let vc = FullScreenDialogViewController(
253
+ dialogType: .prompt,
254
+ dialogTitle: title,
255
+ message: message,
256
+ okButtonTitle: okButtonTitle ?? "OK",
257
+ cancelButtonTitle: cancelButtonTitle ?? "Cancel",
258
+ inputPlaceholder: inputPlaceholder,
259
+ inputText: inputText,
260
+ options: nil,
261
+ selectedValue: nil,
262
+ selectedValues: nil,
263
+ focusInput: focusInput,
264
+ styleOptions: styleOptions
265
+ )
266
+ vc.promptCallback = callback
267
+ presentFullScreen(vc)
268
+ }
269
+
270
+ // MARK: - Single Select
271
+
272
+ public func showSingleSelect(
273
+ title: String?,
274
+ message: String,
275
+ options: [[String: String]],
276
+ selectedValue: String?,
277
+ okButtonTitle: String?,
278
+ cancelButtonTitle: String?,
279
+ fullscreen: Bool,
280
+ styleOptions: DialogStyleOptions? = nil,
281
+ callback: @escaping SingleSelectCallback
282
+ ) {
283
+ DispatchQueue.main.async {
284
+ let selectOptions = options.compactMap { dict -> SelectOption? in
285
+ guard let label = dict["label"], let value = dict["value"] else { return nil }
286
+ return SelectOption(label: label, value: value)
287
+ }
288
+
289
+ if fullscreen {
290
+ self.showFullScreenSingleSelect(title: title, message: message, options: selectOptions, selectedValue: selectedValue, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, styleOptions: styleOptions, callback: callback)
291
+ } else {
292
+ self.showBasicSingleSelect(title: title, message: message, options: selectOptions, selectedValue: selectedValue, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, styleOptions: styleOptions, callback: callback)
293
+ }
294
+ }
295
+ }
296
+
297
+ private func showBasicSingleSelect(title: String?, message: String, options: [SelectOption], selectedValue: String?, okButtonTitle: String?, cancelButtonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping SingleSelectCallback) {
298
+ let alert = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
299
+
300
+ for option in options {
301
+ let action = UIAlertAction(title: option.label, style: .default) { _ in
302
+ callback(option.value, false)
303
+ }
304
+ if option.value == selectedValue {
305
+ action.setValue(true, forKey: "checked")
306
+ }
307
+ if let color = styleOptions?.buttonColor {
308
+ action.setValue(color, forKey: "titleTextColor")
309
+ }
310
+ alert.addAction(action)
311
+ }
312
+
313
+ let cancelAction = UIAlertAction(title: cancelButtonTitle ?? "Cancel", style: .cancel) { _ in
314
+ callback(nil, true)
315
+ }
316
+ if let color = styleOptions?.cancelButtonColor {
317
+ cancelAction.setValue(color, forKey: "titleTextColor")
318
+ }
319
+ alert.addAction(cancelAction)
320
+
321
+ applyLiquidGlassStyle(to: alert)
322
+ applyMessageStyle(to: alert, styleOptions: styleOptions)
323
+ presentAlert(alert)
324
+ }
325
+
326
+ private func showFullScreenSingleSelect(title: String?, message: String, options: [SelectOption], selectedValue: String?, okButtonTitle: String?, cancelButtonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping SingleSelectCallback) {
327
+ let vc = FullScreenDialogViewController(
328
+ dialogType: .singleSelect,
329
+ dialogTitle: title,
330
+ message: message,
331
+ okButtonTitle: okButtonTitle ?? "OK",
332
+ cancelButtonTitle: cancelButtonTitle ?? "Cancel",
333
+ inputPlaceholder: nil,
334
+ inputText: nil,
335
+ options: options,
336
+ selectedValue: selectedValue,
337
+ selectedValues: nil,
338
+ styleOptions: styleOptions
339
+ )
340
+ vc.singleSelectCallback = callback
341
+ presentFullScreen(vc)
342
+ }
343
+
344
+ // MARK: - Multi Select
345
+
346
+ public func showMultiSelect(
347
+ title: String?,
348
+ message: String,
349
+ options: [[String: String]],
350
+ selectedValues: [String]?,
351
+ okButtonTitle: String?,
352
+ cancelButtonTitle: String?,
353
+ fullscreen: Bool,
354
+ styleOptions: DialogStyleOptions? = nil,
355
+ callback: @escaping MultiSelectCallback
356
+ ) {
357
+ DispatchQueue.main.async {
358
+ let selectOptions = options.compactMap { dict -> SelectOption? in
359
+ guard let label = dict["label"], let value = dict["value"] else { return nil }
360
+ return SelectOption(label: label, value: value)
361
+ }
362
+
363
+ if fullscreen {
364
+ self.showFullScreenMultiSelect(title: title, message: message, options: selectOptions, selectedValues: selectedValues, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, styleOptions: styleOptions, callback: callback)
365
+ } else {
366
+ self.showBasicMultiSelect(title: title, message: message, options: selectOptions, selectedValues: selectedValues, okButtonTitle: okButtonTitle, cancelButtonTitle: cancelButtonTitle, styleOptions: styleOptions, callback: callback)
367
+ }
368
+ }
369
+ }
370
+
371
+ private func showBasicMultiSelect(title: String?, message: String, options: [SelectOption], selectedValues: [String]?, okButtonTitle: String?, cancelButtonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping MultiSelectCallback) {
372
+ let vc = FullScreenDialogViewController(
373
+ dialogType: .multiSelect,
374
+ dialogTitle: title,
375
+ message: message,
376
+ okButtonTitle: okButtonTitle ?? "OK",
377
+ cancelButtonTitle: cancelButtonTitle ?? "Cancel",
378
+ inputPlaceholder: nil,
379
+ inputText: nil,
380
+ options: options,
381
+ selectedValue: nil,
382
+ selectedValues: selectedValues,
383
+ styleOptions: styleOptions
384
+ )
385
+ vc.multiSelectCallback = callback
386
+ presentBasicSheet(vc)
387
+ }
388
+
389
+ private func showFullScreenMultiSelect(title: String?, message: String, options: [SelectOption], selectedValues: [String]?, okButtonTitle: String?, cancelButtonTitle: String?, styleOptions: DialogStyleOptions?, callback: @escaping MultiSelectCallback) {
390
+ let vc = FullScreenDialogViewController(
391
+ dialogType: .multiSelect,
392
+ dialogTitle: title,
393
+ message: message,
394
+ okButtonTitle: okButtonTitle ?? "OK",
395
+ cancelButtonTitle: cancelButtonTitle ?? "Cancel",
396
+ inputPlaceholder: nil,
397
+ inputText: nil,
398
+ options: options,
399
+ selectedValue: nil,
400
+ selectedValues: selectedValues,
401
+ styleOptions: styleOptions
402
+ )
403
+ vc.multiSelectCallback = callback
404
+ presentFullScreen(vc)
405
+ }
406
+
407
+ // MARK: - Helpers
408
+
409
+ private func applyLiquidGlassStyle(to alert: UIAlertController) {
410
+ // Apply Liquid Glass styling for iOS 26+
411
+ if #available(iOS 26, *) {
412
+ // iOS 26 automatically applies Liquid Glass styling to UIAlertController
413
+ // The system handles glass background effects for alerts natively
414
+ // Additional layer-based glass effects can be applied to custom views if needed
415
+ if let view = alert.view {
416
+ view.layer.cornerCurve = .continuous
417
+ }
418
+ } else {
419
+ // For older iOS versions, apply a similar visual style
420
+ if let view = alert.view {
421
+ view.layer.cornerRadius = 28.0
422
+ view.layer.cornerCurve = .continuous
423
+ view.clipsToBounds = true
424
+ }
425
+ }
426
+
427
+ // Ensure dialog appears on top
428
+ alert.view.layer.zPosition = CGFloat.greatestFiniteMagnitude
429
+ }
430
+
431
+ private func applyMessageStyle(to alert: UIAlertController, styleOptions: DialogStyleOptions?) {
432
+ guard let styleOptions = styleOptions, let fontSize = styleOptions.messageFontSize else { return }
433
+
434
+ // Access the message label using KVC (undocumented but commonly used)
435
+ if let message = alert.message {
436
+ let attributedMessage = NSMutableAttributedString(
437
+ string: message,
438
+ attributes: [
439
+ .font: UIFont.systemFont(ofSize: fontSize)
440
+ ]
441
+ )
442
+ alert.setValue(attributedMessage, forKey: "attributedMessage")
443
+ }
444
+ }
445
+
446
+ private func presentAlert(_ alert: UIAlertController) {
447
+ guard let viewController = getTopViewController() else { return }
448
+
449
+ // Configure popover for iPad
450
+ if let popover = alert.popoverPresentationController {
451
+ popover.sourceView = viewController.view
452
+ popover.sourceRect = CGRect(x: viewController.view.bounds.midX, y: viewController.view.bounds.midY, width: 0, height: 0)
453
+ popover.permittedArrowDirections = []
454
+ }
455
+
456
+ viewController.present(alert, animated: true)
457
+ }
458
+
459
+ private func presentFullScreen(_ viewController: UIViewController) {
460
+ guard let topVC = getTopViewController() else { return }
461
+
462
+ viewController.modalPresentationStyle = .fullScreen
463
+ viewController.modalTransitionStyle = .coverVertical
464
+ topVC.present(viewController, animated: true)
465
+ }
466
+
467
+ private func presentBasicSheet(_ viewController: UIViewController) {
468
+ guard let topVC = getTopViewController() else { return }
469
+
470
+ viewController.modalPresentationStyle = .pageSheet
471
+ viewController.modalTransitionStyle = .coverVertical
472
+
473
+ if #available(iOS 15.0, *) {
474
+ if let sheet = viewController.sheetPresentationController {
475
+ sheet.detents = [.medium(), .large()]
476
+ sheet.prefersGrabberVisible = true
477
+ sheet.prefersScrollingExpandsWhenScrolledToEdge = false
478
+ }
479
+ }
480
+
481
+ topVC.present(viewController, animated: true)
482
+ }
483
+
484
+ private func getTopViewController() -> UIViewController? {
485
+ guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
486
+ let window = windowScene.windows.first(where: { $0.isKeyWindow }),
487
+ var topController = window.rootViewController else {
488
+ return nil
489
+ }
490
+
491
+ while let presentedViewController = topController.presentedViewController {
492
+ topController = presentedViewController
493
+ }
494
+
495
+ return topController
496
+ }
497
+ }
@@ -0,0 +1,177 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(ExtendedDialogPlugin)
5
+ public class ExtendedDialogPlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "ExtendedDialogPlugin"
7
+ public let jsName = "ExtendedDialog"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "alert", returnType: CAPPluginReturnPromise),
10
+ CAPPluginMethod(name: "confirm", returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: "prompt", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "singleSelect", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "multiSelect", returnType: CAPPluginReturnPromise)
14
+ ]
15
+
16
+ private let implementation = ExtendedDialog()
17
+
18
+ private func extractStyleOptions(_ call: CAPPluginCall) -> DialogStyleOptions {
19
+ return DialogStyleOptions(
20
+ buttonColor: call.getString("buttonColor"),
21
+ cancelButtonColor: call.getString("cancelButtonColor"),
22
+ titleColor: call.getString("titleColor"),
23
+ messageColor: call.getString("messageColor"),
24
+ backgroundColor: call.getString("backgroundColor"),
25
+ titleFontSize: call.getDouble("titleFontSize"),
26
+ messageFontSize: call.getDouble("messageFontSize"),
27
+ buttonFontSize: call.getDouble("buttonFontSize")
28
+ )
29
+ }
30
+
31
+ @objc func alert(_ call: CAPPluginCall) {
32
+ let title = call.getString("title")
33
+ guard let message = call.getString("message") else {
34
+ call.reject("message is required")
35
+ return
36
+ }
37
+ let buttonTitle = call.getString("buttonTitle")
38
+ let mode = call.getString("mode") ?? "basic"
39
+ let fullscreen = mode == "fullscreen"
40
+ let styleOptions = extractStyleOptions(call)
41
+
42
+ implementation.showAlert(
43
+ title: title,
44
+ message: message,
45
+ buttonTitle: buttonTitle,
46
+ fullscreen: fullscreen,
47
+ styleOptions: styleOptions
48
+ ) {
49
+ call.resolve()
50
+ }
51
+ }
52
+
53
+ @objc func confirm(_ call: CAPPluginCall) {
54
+ let title = call.getString("title")
55
+ guard let message = call.getString("message") else {
56
+ call.reject("message is required")
57
+ return
58
+ }
59
+ let okButtonTitle = call.getString("okButtonTitle")
60
+ let cancelButtonTitle = call.getString("cancelButtonTitle")
61
+ let mode = call.getString("mode") ?? "basic"
62
+ let fullscreen = mode == "fullscreen"
63
+ let styleOptions = extractStyleOptions(call)
64
+
65
+ implementation.showConfirm(
66
+ title: title,
67
+ message: message,
68
+ okButtonTitle: okButtonTitle,
69
+ cancelButtonTitle: cancelButtonTitle,
70
+ fullscreen: fullscreen,
71
+ styleOptions: styleOptions
72
+ ) { value in
73
+ call.resolve(["value": value])
74
+ }
75
+ }
76
+
77
+ @objc func prompt(_ call: CAPPluginCall) {
78
+ let title = call.getString("title")
79
+ guard let message = call.getString("message") else {
80
+ call.reject("message is required")
81
+ return
82
+ }
83
+ let okButtonTitle = call.getString("okButtonTitle")
84
+ let cancelButtonTitle = call.getString("cancelButtonTitle")
85
+ let inputPlaceholder = call.getString("inputPlaceholder")
86
+ let inputText = call.getString("inputText")
87
+ let mode = call.getString("mode") ?? "basic"
88
+ let fullscreen = mode == "fullscreen"
89
+ let focusInput = call.getBool("focusInput") ?? false
90
+ let styleOptions = extractStyleOptions(call)
91
+
92
+ implementation.showPrompt(
93
+ title: title,
94
+ message: message,
95
+ okButtonTitle: okButtonTitle,
96
+ cancelButtonTitle: cancelButtonTitle,
97
+ inputPlaceholder: inputPlaceholder,
98
+ inputText: inputText,
99
+ fullscreen: fullscreen,
100
+ focusInput: focusInput,
101
+ styleOptions: styleOptions
102
+ ) { value, cancelled in
103
+ call.resolve([
104
+ "value": value,
105
+ "cancelled": cancelled
106
+ ])
107
+ }
108
+ }
109
+
110
+ @objc func singleSelect(_ call: CAPPluginCall) {
111
+ let title = call.getString("title")
112
+ guard let message = call.getString("message") else {
113
+ call.reject("message is required")
114
+ return
115
+ }
116
+ guard let optionsArray = call.getArray("options") as? [[String: String]] else {
117
+ call.reject("options is required")
118
+ return
119
+ }
120
+ let selectedValue = call.getString("selectedValue")
121
+ let okButtonTitle = call.getString("okButtonTitle")
122
+ let cancelButtonTitle = call.getString("cancelButtonTitle")
123
+ let mode = call.getString("mode") ?? "basic"
124
+ let fullscreen = mode == "fullscreen"
125
+ let styleOptions = extractStyleOptions(call)
126
+
127
+ implementation.showSingleSelect(
128
+ title: title,
129
+ message: message,
130
+ options: optionsArray,
131
+ selectedValue: selectedValue,
132
+ okButtonTitle: okButtonTitle,
133
+ cancelButtonTitle: cancelButtonTitle,
134
+ fullscreen: fullscreen,
135
+ styleOptions: styleOptions
136
+ ) { value, cancelled in
137
+ call.resolve([
138
+ "value": value as Any,
139
+ "cancelled": cancelled
140
+ ])
141
+ }
142
+ }
143
+
144
+ @objc func multiSelect(_ call: CAPPluginCall) {
145
+ let title = call.getString("title")
146
+ guard let message = call.getString("message") else {
147
+ call.reject("message is required")
148
+ return
149
+ }
150
+ guard let optionsArray = call.getArray("options") as? [[String: String]] else {
151
+ call.reject("options is required")
152
+ return
153
+ }
154
+ let selectedValues = call.getArray("selectedValues") as? [String]
155
+ let okButtonTitle = call.getString("okButtonTitle")
156
+ let cancelButtonTitle = call.getString("cancelButtonTitle")
157
+ let mode = call.getString("mode") ?? "basic"
158
+ let fullscreen = mode == "fullscreen"
159
+ let styleOptions = extractStyleOptions(call)
160
+
161
+ implementation.showMultiSelect(
162
+ title: title,
163
+ message: message,
164
+ options: optionsArray,
165
+ selectedValues: selectedValues,
166
+ okButtonTitle: okButtonTitle,
167
+ cancelButtonTitle: cancelButtonTitle,
168
+ fullscreen: fullscreen,
169
+ styleOptions: styleOptions
170
+ ) { values, cancelled in
171
+ call.resolve([
172
+ "values": values,
173
+ "cancelled": cancelled
174
+ ])
175
+ }
176
+ }
177
+ }