enhance(mobile): native alert

This commit is contained in:
Tienson Qin
2025-11-28 03:06:13 +08:00
parent bfce853b88
commit 9c01d46bc3
12 changed files with 219 additions and 19 deletions

View File

@@ -9,6 +9,7 @@ import Capacitor
import Foundation
import Speech
import NaturalLanguage
import Drops
func isDarkMode() -> Bool {
if #available(iOS 12.0, *) {
@@ -211,9 +212,123 @@ public class UILocalPlugin: CAPPlugin, CAPBridgedPlugin {
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "showDatePicker", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "transcribeAudio2Text", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "routeDidChange", returnType: CAPPluginReturnPromise)
CAPPluginMethod(name: "routeDidChange", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "alert", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "hideAlert", returnType: CAPPluginReturnPromise)
]
@objc func alert(_ call: CAPPluginCall) {
guard let title = call.getString("title") ?? call.getString("message") else {
call.reject("title is required")
return
}
let subtitle = call.getString("subtitle") ?? call.getString("description")
let type = call.getString("type")?.lowercased()
let iconName = call.getString("icon")
let iconColorHex = call.getString("iconColor") ?? call.getString("tintColor")
let position = (call.getString("position")?.lowercased() == "bottom") ? Drop.Position.bottom : Drop.Position.top
let durationSeconds = call.getDouble("duration")
let accessibilityMessage = call.getString("accessibility")
let drop = Drop(
title: title,
subtitle: subtitle,
icon: buildIcon(type: type, iconName: iconName, hexColor: iconColorHex),
action: nil,
position: position,
duration: durationSeconds.flatMap { Drop.Duration.seconds($0) } ?? .recommended,
accessibility: accessibilityMessage.map { Drop.Accessibility(message: $0) }
)
Drops.show(drop)
call.resolve()
}
@objc func hideAlert(_ call: CAPPluginCall) {
Drops.hideAll()
call.resolve()
}
private func buildIcon(type: String?, iconName: String?, hexColor: String?) -> UIImage? {
let tint = color(fromHex: hexColor) ?? color(for: type)
if let iconName, let image = UIImage(systemName: iconName) {
guard let tint else { return image }
return image.withTintColor(tint, renderingMode: .alwaysOriginal)
}
guard let type else { return nil }
let symbolName: String
switch type {
case "success":
symbolName = "checkmark.circle.fill"
case "warning":
symbolName = "exclamationmark.triangle.fill"
case "error", "danger":
symbolName = "xmark.octagon.fill"
default:
symbolName = "info.circle.fill"
}
if let tint {
return UIImage(systemName: symbolName)?
.withTintColor(tint, renderingMode: .alwaysOriginal)
}
return UIImage(systemName: symbolName)
}
private func color(for type: String?) -> UIColor? {
guard let type else { return nil }
switch type {
case "success":
return .systemGreen
case "warning":
return .systemOrange
case "error", "danger":
return .systemRed
default:
return .systemBlue
}
}
private func color(fromHex hexString: String?) -> UIColor? {
guard var hex = hexString?
.trimmingCharacters(in: .whitespacesAndNewlines)
.uppercased(),
!hex.isEmpty else {
return nil
}
if hex.hasPrefix("#") {
hex.removeFirst()
}
var rgbValue: UInt64 = 0
guard Scanner(string: hex).scanHexInt64(&rgbValue) else { return nil }
switch hex.count {
case 6:
return UIColor(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: 1.0
)
case 8:
return UIColor(
red: CGFloat((rgbValue & 0xFF000000) >> 24) / 255.0,
green: CGFloat((rgbValue & 0x00FF0000) >> 16) / 255.0,
blue: CGFloat((rgbValue & 0x0000FF00) >> 8) / 255.0,
alpha: CGFloat(rgbValue & 0x000000FF) / 255.0
)
default:
return nil
}
}
@available(iOS 26.0, *)
func recognizeWithAutoLocale(from file: URL,
completion: @escaping (String?, Error?) -> Void) {

View File

@@ -28,6 +28,7 @@ def capacitor_pods
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
pod 'CapgoCapacitorNavigationBar', :path => '../../node_modules/@capgo/capacitor-navigation-bar'
pod 'SendIntent', :path => '../../node_modules/send-intent'
pod 'Drops', :git => 'https://github.com/omaralbeik/Drops.git', :tag => '1.7.0'
pod 'JcesarmobileSslSkip', :path => '../../node_modules/@jcesarmobile/ssl-skip'
end

View File

@@ -10,7 +10,7 @@ PODS:
- Capacitor
- CapacitorCamera (7.0.1):
- Capacitor
- CapacitorClipboard (7.0.1):
- CapacitorClipboard (7.0.2):
- Capacitor
- CapacitorCommunitySafeArea (7.0.0-alpha.1):
- Capacitor
@@ -35,6 +35,7 @@ PODS:
- Capacitor
- CapgoCapacitorNavigationBar (7.1.32):
- Capacitor
- Drops (1.7.0)
- JcesarmobileSslSkip (0.4.0):
- Capacitor
- KeychainSwift (21.0.0)
@@ -60,6 +61,7 @@ DEPENDENCIES:
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
- "CapgoCapacitorNavigationBar (from `../../node_modules/@capgo/capacitor-navigation-bar`)"
- Drops (from `https://github.com/omaralbeik/Drops.git`, tag `1.7.0`)
- "JcesarmobileSslSkip (from `../../node_modules/@jcesarmobile/ssl-skip`)"
- SendIntent (from `../../node_modules/send-intent`)
@@ -104,18 +106,26 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/status-bar"
CapgoCapacitorNavigationBar:
:path: "../../node_modules/@capgo/capacitor-navigation-bar"
Drops:
:git: https://github.com/omaralbeik/Drops.git
:tag: 1.7.0
JcesarmobileSslSkip:
:path: "../../node_modules/@jcesarmobile/ssl-skip"
SendIntent:
:path: "../../node_modules/send-intent"
CHECKOUT OPTIONS:
Drops:
:git: https://github.com/omaralbeik/Drops.git
:tag: 1.7.0
SPEC CHECKSUMS:
AparajitaCapacitorSecureStorage: 502bff73187cf9d0164459458ccf47ec65d5895a
Capacitor: 03bc7cbdde6a629a8b910a9d7d78c3cc7ed09ea7
CapacitorActionSheet: 4213427449132ae4135674d93010cb011725647e
CapacitorApp: febecbb9582cb353aed037e18ec765141f880fe9
CapacitorCamera: 6e73f1fc6c629a672658705a02409b60854bc0f1
CapacitorClipboard: 70bfdb42b877b320a6e511ab94fa7a6a55d57ecb
CapacitorClipboard: 7e227702976d4435a5a40df54f65e154d0dfc1f3
CapacitorCommunitySafeArea: 3f049619072ab5d0da2529bcb05b358ff6c13dc1
CapacitorCordova: 5967b9ba03915ef1d585469d6e31f31dc49be96f
CapacitorDevice: 81ae78d5d1942707caad79276badd458bf6ec603
@@ -128,10 +138,11 @@ SPEC CHECKSUMS:
CapacitorSplashScreen: 1d67815a422a9b61539c94f283c08ed56667c0fc
CapacitorStatusBar: 6e7af040d8fc4dd655999819625cae9c2d74c36f
CapgoCapacitorNavigationBar: 067b1c1d1ede5ce96200a730ce7fd498e9641509
Drops: 5155b9ede54a2666b2129ac33f0734509b9f0784
JcesarmobileSslSkip: 5fa98636a64c36faa50f32ab4daf34e38f4d45b9
KeychainSwift: 4a71a45c802fd9e73906457c2dcbdbdc06c9419d
SendIntent: 8a6f646a4489f788d253ffbd1082a98ea388d870
PODFILE CHECKSUM: 2ba428e46e22e2bca616c46fc132c5699b98e54b
PODFILE CHECKSUM: 4c45370d0465170bcb1b7c0b1ed45c9e46b9b742
COCOAPODS: 1.16.2