Skip to content

Commit aaf8f88

Browse files
committed
feat: custom color support hex, rgba, named colors
1 parent 2dfce8e commit aaf8f88

File tree

4 files changed

+81
-28
lines changed

4 files changed

+81
-28
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ alert({
177177
- [x] `tintColor` for icon (v.1.0.5)
178178
- [x] `backgroundColor` (v.1.0.3)
179179
- [x] `spinner preset for toast` (v.1.1.0)
180-
- [ ] custom color like StyleSheet (e.g. `#fff`, `red`, `rgba(0, 0, 0, .8)`)
180+
- [x] custom color like StyleSheet (e.g. `#fff`, `red`, `rgba(0, 0, 0, .8)`)
181181
- [ ] `shouldDismissByDrag` on **Android**
182182
- [ ] `callback`
183183

android/src/main/java/com/ting/TingModule.kt

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
3838
private var alertOptionInit: ReadableMap? = null
3939

4040
@ReactMethod
41-
override fun toast(RNOptions: ReadableMap) {
41+
override fun toast(options: ReadableMap) {
4242
// get container View
43-
val options = toastOptionInit?.let { mergeMaps(it, RNOptions) } ?: RNOptions
43+
val options = toastOptionInit?.let { mergeMaps(it, options) } ?: options
4444

4545
val container = getContainerView(R.layout.toast, options, "toast")
4646
val duration: Int = getDuration(options)
@@ -77,8 +77,8 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
7777
}
7878

7979
@ReactMethod
80-
override fun alert(RNOptions: ReadableMap) {
81-
val options = alertOptionInit?.let { mergeMaps(it, RNOptions) } ?: RNOptions
80+
override fun alert(options: ReadableMap) {
81+
val options = alertOptionInit?.let { mergeMaps(it, options) } ?: options
8282

8383
val container = getContainerView(R.layout.alert, options, "alert")
8484
val duration: Int = getDuration(options)
@@ -280,14 +280,36 @@ fun isNumber(value: Any?): Boolean {
280280
return value != null && (value is Int || value is Long || value is Float || value is Double)
281281
}
282282

283-
fun parseColor(hexColor: String): Int {
283+
fun parseColor(colorString: String): Int {
284284
val fallbackColor = Color.BLACK
285-
val color = try {
286-
Color.parseColor(hexColor)
287-
} catch (e: IllegalArgumentException) {
288-
fallbackColor
285+
// Try parsing color as hex
286+
if (colorString.startsWith("#")) {
287+
return Color.parseColor(colorString)
289288
}
290-
return color
289+
290+
// Try parsing color as named color
291+
val namedColor = try {
292+
Color::class.java.getField(colorString.uppercase()).get(null) as Int
293+
} catch (e: Exception) {
294+
null
295+
}
296+
if (namedColor != null) {
297+
return namedColor
298+
}
299+
300+
// Try parsing color as RGB or RGBA
301+
val rgbRegex = Regex("""rgba?\((\d{1,3}), (\d{1,3}), (\d{1,3})(, (\d(\.\d)?))?\)""")
302+
val rgbMatchResult = rgbRegex.matchEntire(colorString)
303+
if (rgbMatchResult != null) {
304+
val red = rgbMatchResult.groups[1]?.value?.toIntOrNull() ?: return fallbackColor
305+
val green = rgbMatchResult.groups[2]?.value?.toIntOrNull() ?: return fallbackColor
306+
val blue = rgbMatchResult.groups[3]?.value?.toIntOrNull() ?: return fallbackColor
307+
val alpha = if (colorString.startsWith("rgb(")) 1.0f else rgbMatchResult.groups[5]?.value?.toFloatOrNull() ?: 1.0f
308+
return Color.argb((alpha * 255).toInt(), red, green, blue)
309+
}
310+
311+
// Return fallback color if parsing fails
312+
return fallbackColor
291313
}
292314

293315
fun convertInt2Size(number: Int?): Int {

ios/Type.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ class Options {
2727
self.title = option["title"] as? String ?? "Title"
2828
self.message = option["message"] as? String
2929
self.duration = option["duration"] as? TimeInterval ?? 3
30-
self.backgroundColor = UIColor.hexStringToColor(option["backgroundColor"] as? String)
30+
self.backgroundColor = UIColor.parseColor(option["backgroundColor"] as? String)
3131

3232
if let messageColor = option["messageColor"] as? String {
33-
self.messageColor = UIColor.hexStringToColor(messageColor)
33+
self.messageColor = UIColor.parseColor(messageColor)
3434
}
3535

3636
if let titleColor = option["titleColor"] as? String {
37-
self.titleColor = UIColor.hexStringToColor(titleColor)
37+
self.titleColor = UIColor.parseColor(titleColor)
3838
}
3939

4040
// custom icon
@@ -53,7 +53,7 @@ class Options {
5353
func getCustomIcon(icon: NSDictionary) -> UIImage? {
5454
if let iconURI = icon["uri"] as? String {
5555
if let iconImage = getImage(icon: iconURI) {
56-
let color = UIColor.hexStringToColor(icon["tintColor"] as? String)
56+
let color = UIColor.parseColor(icon["tintColor"] as? String)
5757
if(color != nil){
5858
return iconImage.getTintColor(color!)
5959
}

ios/Utils.swift

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,57 @@ extension UIImage {
3030
}
3131

3232
extension UIColor {
33-
static func hexStringToColor(_ stringToConvert: String?) -> UIColor? {
34-
if stringToConvert == nil {
33+
static func parseColor(_ colorString: String?) -> UIColor? {
34+
guard let colorString = colorString else {
3535
return nil
3636
}
3737

38-
let noHashString = stringToConvert!.replacingOccurrences(of: "#", with: "")
39-
40-
// Đảm bảo độ dài chuỗi hợp lệ
41-
guard noHashString.count == 6 else {
42-
return nil
38+
// Try parsing color as hex
39+
if colorString.hasPrefix("#") {
40+
let hexString = String(colorString.dropFirst()) // Remove '#' character
41+
42+
// Check if the hex string has valid length
43+
guard hexString.count == 6 || hexString.count == 8 else {
44+
return .gray // Return gray color for invalid hex string
45+
}
46+
47+
// Parse hex values
48+
var rgbValue: UInt64 = 0
49+
Scanner(string: hexString).scanHexInt64(&rgbValue)
50+
51+
// Extract individual color components
52+
let red = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0
53+
let green = CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0
54+
let blue = CGFloat(rgbValue & 0x0000FF) / 255.0
55+
let alpha = hexString.count == 8 ? CGFloat((rgbValue & 0xFF000000) >> 24) / 255.0 : 1.0
56+
57+
// Create and return UIColor
58+
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
4359
}
4460

45-
var rgbValue: UInt64 = 0
46-
Scanner(string: noHashString).scanHexInt64(&rgbValue)
61+
// Try parsing color as named color
62+
if let namedColor = UIColor(named: colorString) {
63+
return namedColor
64+
}
4765

48-
let r = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0
49-
let g = CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0
50-
let b = CGFloat(rgbValue & 0x0000FF) / 255.0
66+
// Try parsing color as RGB or RGBA
67+
let rgbRegex = try! NSRegularExpression(pattern: #"rgba?\((\d{1,3}), (\d{1,3}), (\d{1,3})(, (\d(\.\d)?))?\)"#)
68+
if let rgbMatch = rgbRegex.firstMatch(in: colorString, range: NSRange(colorString.startIndex..., in: colorString)) {
69+
let red = Int(colorString[Range(rgbMatch.range(at: 1), in: colorString)!])!
70+
let green = Int(colorString[Range(rgbMatch.range(at: 2), in: colorString)!])!
71+
let blue = Int(colorString[Range(rgbMatch.range(at: 3), in: colorString)!])!
72+
let alpha = rgbMatch.numberOfRanges > 5 ? Float(colorString[Range(rgbMatch.range(at: 5), in: colorString)!])! : 1.0
73+
74+
// If the color string starts with "rgb(", ignore the alpha component
75+
if colorString.hasPrefix("rgb(") {
76+
return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
77+
} else {
78+
return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: CGFloat(alpha))
79+
}
80+
}
5181

52-
return UIColor(red: r, green: g, blue: b, alpha: 1.0)
82+
// Fallback to black color
83+
return .black
5384
}
5485
}
5586

0 commit comments

Comments
 (0)