@@ -6,12 +6,16 @@ import android.graphics.Bitmap
6
6
import android.graphics.BitmapFactory
7
7
import android.graphics.Color
8
8
import android.graphics.PorterDuff
9
+ import android.graphics.PorterDuffColorFilter
9
10
import android.graphics.drawable.AnimatedVectorDrawable
10
11
import android.graphics.drawable.GradientDrawable
11
12
import android.os.Handler
12
13
import android.os.Looper
14
+ import android.view.GestureDetector
13
15
import android.view.Gravity
14
16
import android.view.LayoutInflater
17
+ import android.view.MotionEvent
18
+ import android.view.View
15
19
import android.widget.ImageView
16
20
import android.widget.LinearLayout
17
21
import android.widget.ProgressBar
@@ -25,6 +29,7 @@ import com.facebook.react.bridge.WritableMap
25
29
import com.hjq.window.EasyWindow
26
30
import java.io.IOException
27
31
import java.net.URL
32
+ import kotlin.math.abs
28
33
import kotlin.math.roundToInt
29
34
30
35
@@ -37,9 +42,9 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
37
42
private var alertOptionInit: ReadableMap ? = null
38
43
39
44
@ReactMethod
40
- override fun toast (RNOptions : ReadableMap ) {
45
+ override fun toast (rnOptions : ReadableMap ) {
41
46
// get container View
42
- val options = toastOptionInit?.let { mergeMaps(it, RNOptions ) } ? : RNOptions
47
+ val options = toastOptionInit?.let { mergeMaps(it, rnOptions ) } ? : rnOptions
43
48
44
49
val container = getContainerView(R .layout.toast, options, " toast" )
45
50
val duration: Int = getDuration(options)
@@ -65,19 +70,46 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
65
70
setYOffset(48 )
66
71
setAnimStyle(toastAnim)
67
72
setOutsideTouchable(true )
68
- setOnClickListener(R .id.toast,
69
- EasyWindow .OnClickListener { toast: EasyWindow <* >, _: LinearLayout ? ->
70
- val shouldDismissByTap =
71
- if (options.hasKey(" shouldDismissByDrag" )) options.getBoolean(" shouldDismissByDrag" ) else true
72
- if (shouldDismissByTap) toast.cancel()
73
- })
73
+
74
+ if (options.hasKey(" shouldDismissByDrag" ) && options.getBoolean(" shouldDismissByDrag" )) {
75
+ // Define dragThreshold in density-independent pixels (dp)
76
+ val dragThresholdDP = 12
77
+ val scale = context.resources.displayMetrics.density
78
+ val dragThreshold = (dragThresholdDP * scale + 0.5f ).toInt()
79
+
80
+ // Add drag gesture recognizer
81
+ contentView?.let { contentView ->
82
+ val gestureDetector = GestureDetector (context, object : GestureDetector .SimpleOnGestureListener () {
83
+ override fun onScroll (e1 : MotionEvent , e2 : MotionEvent , distanceX : Float , distanceY : Float ): Boolean {
84
+ // Check if the user scrolls vertically and dismiss the toast window if needed
85
+ if (abs(distanceY) > abs(distanceX)) {
86
+ if (position == Gravity .TOP && distanceY > dragThreshold) { // Dismiss upward if toast is at the top
87
+ toastWindow.cancel()
88
+ return true
89
+ } else if (position == Gravity .BOTTOM && distanceY < - dragThreshold) { // Dismiss downward if toast is at the bottom
90
+ toastWindow.cancel()
91
+ return true
92
+ }
93
+ }
94
+
95
+ return super .onScroll(e1, e2, distanceX, distanceY)
96
+ }
97
+ })
98
+
99
+ contentView.setOnTouchListener(fun (_: View , event : MotionEvent ): Boolean {
100
+ gestureDetector.onTouchEvent(event)
101
+ return true // Consume the touch event
102
+ })
103
+ }
104
+ }
105
+
74
106
}.show()
75
107
}
76
108
}
77
109
78
110
@ReactMethod
79
- override fun alert (RNOptions : ReadableMap ) {
80
- val options = alertOptionInit?.let { mergeMaps(it, RNOptions ) } ? : RNOptions
111
+ override fun alert (rnOptions : ReadableMap ) {
112
+ val options = alertOptionInit?.let { mergeMaps(it, rnOptions ) } ? : rnOptions
81
113
82
114
val container = getContainerView(R .layout.alert, options, " alert" )
83
115
val duration: Int = getDuration(options)
@@ -147,6 +179,7 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
147
179
val titleColor = options?.getString(" titleColor" )
148
180
val message = options?.getString(" message" )
149
181
val messageColor = options?.getString(" messageColor" )
182
+ val progressColor = options?.getString(" progressColor" )
150
183
val preset = options?.getString(" preset" )
151
184
val backgroundColor = options?.getString(" backgroundColor" )
152
185
val borderRadius = if (options.hasKey(" borderRadius" )) options?.getInt(" borderRadius" ) else null
@@ -213,6 +246,13 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
213
246
iconView.visibility = ImageView .GONE
214
247
progressBar.id = R .id.loading_spinner
215
248
progressBar.layoutParams = progressSize
249
+
250
+ if (progressColor != null ) {
251
+ val progressDrawable = progressBar.indeterminateDrawable.mutate()
252
+ progressDrawable.colorFilter = PorterDuffColorFilter (parseColor(progressColor), PorterDuff .Mode .SRC_IN )
253
+ progressBar.indeterminateDrawable = progressDrawable
254
+ }
255
+
216
256
container.addView(progressBar, 0 )
217
257
}
218
258
@@ -271,14 +311,36 @@ fun isNumber(value: Any?): Boolean {
271
311
return value != null && (value is Int || value is Long || value is Float || value is Double )
272
312
}
273
313
274
- fun parseColor (hexColor : String ): Int {
314
+ fun parseColor (colorString : String ): Int {
275
315
val fallbackColor = Color .BLACK
276
- val color = try {
277
- Color .parseColor(hexColor)
278
- } catch (e: IllegalArgumentException ) {
279
- fallbackColor
316
+ // Try parsing color as hex
317
+ if (colorString.startsWith(" #" )) {
318
+ return Color .parseColor(colorString)
280
319
}
281
- return color
320
+
321
+ // Try parsing color as named color
322
+ val namedColor = try {
323
+ Color ::class .java.getField(colorString.uppercase()).get(null ) as Int
324
+ } catch (e: Exception ) {
325
+ null
326
+ }
327
+ if (namedColor != null ) {
328
+ return namedColor
329
+ }
330
+
331
+ // Try parsing color as RGB or RGBA
332
+ val rgbRegex = Regex (""" rgba?\((\d{1,3}), (\d{1,3}), (\d{1,3})(, (\d(\.\d)?))?\)""" )
333
+ val rgbMatchResult = rgbRegex.matchEntire(colorString)
334
+ if (rgbMatchResult != null ) {
335
+ val red = rgbMatchResult.groups[1 ]?.value?.toIntOrNull() ? : return fallbackColor
336
+ val green = rgbMatchResult.groups[2 ]?.value?.toIntOrNull() ? : return fallbackColor
337
+ val blue = rgbMatchResult.groups[3 ]?.value?.toIntOrNull() ? : return fallbackColor
338
+ val alpha = if (colorString.startsWith(" rgb(" )) 1.0f else rgbMatchResult.groups[5 ]?.value?.toFloatOrNull() ? : 1.0f
339
+ return Color .argb((alpha * 255 ).toInt(), red, green, blue)
340
+ }
341
+
342
+ // Return fallback color if parsing fails
343
+ return fallbackColor
282
344
}
283
345
284
346
fun convertInt2Size (number : Int? ): Int {
0 commit comments