@@ -6,12 +6,16 @@ import android.graphics.Bitmap
66import android.graphics.BitmapFactory
77import android.graphics.Color
88import android.graphics.PorterDuff
9+ import android.graphics.PorterDuffColorFilter
910import android.graphics.drawable.AnimatedVectorDrawable
1011import android.graphics.drawable.GradientDrawable
1112import android.os.Handler
1213import android.os.Looper
14+ import android.view.GestureDetector
1315import android.view.Gravity
1416import android.view.LayoutInflater
17+ import android.view.MotionEvent
18+ import android.view.View
1519import android.widget.ImageView
1620import android.widget.LinearLayout
1721import android.widget.ProgressBar
@@ -25,6 +29,7 @@ import com.facebook.react.bridge.WritableMap
2529import com.hjq.window.EasyWindow
2630import java.io.IOException
2731import java.net.URL
32+ import kotlin.math.abs
2833import kotlin.math.roundToInt
2934
3035
@@ -37,9 +42,9 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
3742 private var alertOptionInit: ReadableMap ? = null
3843
3944 @ReactMethod
40- override fun toast (RNOptions : ReadableMap ) {
45+ override fun toast (rnOptions : ReadableMap ) {
4146 // get container View
42- val options = toastOptionInit?.let { mergeMaps(it, RNOptions ) } ? : RNOptions
47+ val options = toastOptionInit?.let { mergeMaps(it, rnOptions ) } ? : rnOptions
4348
4449 val container = getContainerView(R .layout.toast, options, " toast" )
4550 val duration: Int = getDuration(options)
@@ -65,19 +70,46 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
6570 setYOffset(48 )
6671 setAnimStyle(toastAnim)
6772 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+
74106 }.show()
75107 }
76108 }
77109
78110 @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
81113
82114 val container = getContainerView(R .layout.alert, options, " alert" )
83115 val duration: Int = getDuration(options)
@@ -147,6 +179,7 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
147179 val titleColor = options?.getString(" titleColor" )
148180 val message = options?.getString(" message" )
149181 val messageColor = options?.getString(" messageColor" )
182+ val progressColor = options?.getString(" progressColor" )
150183 val preset = options?.getString(" preset" )
151184 val backgroundColor = options?.getString(" backgroundColor" )
152185 val borderRadius = if (options.hasKey(" borderRadius" )) options?.getInt(" borderRadius" ) else null
@@ -213,6 +246,13 @@ class TingModule internal constructor(context: ReactApplicationContext) : TingSp
213246 iconView.visibility = ImageView .GONE
214247 progressBar.id = R .id.loading_spinner
215248 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+
216256 container.addView(progressBar, 0 )
217257 }
218258
@@ -271,14 +311,36 @@ fun isNumber(value: Any?): Boolean {
271311 return value != null && (value is Int || value is Long || value is Float || value is Double )
272312}
273313
274- fun parseColor (hexColor : String ): Int {
314+ fun parseColor (colorString : String ): Int {
275315 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)
280319 }
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
282344}
283345
284346fun convertInt2Size (number : Int? ): Int {
0 commit comments