@react-native-ama/core 2.0.0-beta.1 → 2.0.0-beta.2

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.
@@ -0,0 +1,189 @@
1
+ package expo.modules.ama
2
+
3
+ import android.app.Activity
4
+ import android.graphics.*
5
+ import android.graphics.drawable.Drawable
6
+ import android.graphics.drawable.LayerDrawable
7
+ import android.graphics.drawable.ShapeDrawable
8
+ import android.graphics.drawable.shapes.RectShape
9
+ import android.view.View
10
+ import expo.modules.kotlin.AppContext
11
+ import java.util.concurrent.ConcurrentHashMap
12
+
13
+ class Highlight(private val appContext: AppContext) {
14
+ private val originalBackgrounds = ConcurrentHashMap<Int, Drawable?>()
15
+
16
+ /**
17
+ * Highlight the view with the given ID.
18
+ * @param viewId the Android view ID
19
+ * @param mode "background" | "border" | "both"
20
+ */
21
+ fun highlight(viewId: Int, mode: String, hexColor: String, gap: Int = 0, lineWidth: Float = 6f, issueCount: Int = 1) {
22
+ val activity: Activity = appContext.currentActivity ?: return
23
+ val color = hexColor.toColor()
24
+
25
+ activity.runOnUiThread {
26
+ val target = activity.findViewById<View>(viewId) ?: return@runOnUiThread
27
+
28
+ val view = activity.findViewById<View>(viewId) ?: return@runOnUiThread
29
+
30
+ view.background?.let { bg -> originalBackgrounds.putIfAbsent(viewId, bg) }
31
+
32
+ when (mode) {
33
+ "background" -> applyStripyBackground(target, color)
34
+ "border" -> applyRedBorderOverlay(target, color, gap, lineWidth, issueCount)
35
+ else -> {
36
+ applyRedBorderOverlay(target, color, gap, lineWidth, issueCount)
37
+ applyStripyBackground(target, color)
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ fun clearHighlight(viewId: Int) {
44
+ val activity: Activity = appContext.currentActivity ?: return
45
+
46
+ activity.runOnUiThread {
47
+ val view = activity.findViewById<View>(viewId) ?: return@runOnUiThread
48
+
49
+ val original = originalBackgrounds.remove(viewId)
50
+ view.background = original
51
+
52
+ view.overlay.clear()
53
+ }
54
+ }
55
+
56
+ private fun applyStripyBackground(view: View, color: Int?) {
57
+ val originalBackground = view.background
58
+
59
+ val stripeWidth = 5f
60
+ val gapWidth = 25f
61
+ val bmpWidth = 150
62
+ val bmpHeight = bmpWidth
63
+
64
+ val bmp = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888)
65
+ val canvas = Canvas(bmp)
66
+
67
+ val stripePaint =
68
+ Paint().apply {
69
+ this.color = color ?: Color.RED
70
+ isAntiAlias = true
71
+ }
72
+
73
+ val canvasCenter = bmpWidth / 2f
74
+ canvas.save()
75
+ canvas.rotate(-45f, canvasCenter, canvasCenter)
76
+
77
+ val extendedSize = (bmpWidth * 1.5f)
78
+ var y = -extendedSize
79
+ while (y < extendedSize) {
80
+ canvas.drawRect(-extendedSize, y, extendedSize, y + stripeWidth, stripePaint)
81
+ y += stripeWidth + gapWidth
82
+ }
83
+
84
+ canvas.restore()
85
+
86
+ val shader = BitmapShader(bmp, Shader.TileMode.MIRROR, Shader.TileMode.REPEAT)
87
+
88
+ val backgroundPaint = Paint().apply { this.shader = shader }
89
+
90
+ val stripedDrawable =
91
+ object : Drawable() {
92
+ override fun draw(c: Canvas) = c.drawRect(bounds, backgroundPaint)
93
+
94
+ override fun setAlpha(alpha: Int) {
95
+ backgroundPaint.alpha = alpha
96
+ }
97
+
98
+ override fun setColorFilter(cf: ColorFilter?) {
99
+ backgroundPaint.colorFilter = cf
100
+ }
101
+
102
+ @Deprecated(
103
+ "Deprecated in Java",
104
+ ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat")
105
+ )
106
+ override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
107
+ }
108
+
109
+ if (originalBackground == null) {
110
+ view.background = stripedDrawable
111
+ } else {
112
+ val layers = arrayOf(originalBackground, stripedDrawable)
113
+ view.background = LayerDrawable(layers)
114
+ }
115
+ }
116
+
117
+ private fun applyRedBorderOverlay(view: View, color: Int?, gap: Int, lineWidth: Float = 6f, issueCount: Int = 1) {
118
+ view.overlay.clear()
119
+
120
+ val stroke = lineWidth
121
+ val half = (stroke / 2).toInt()
122
+ val shape =
123
+ ShapeDrawable(RectShape()).apply {
124
+ paint.apply {
125
+ this.color = color ?: Color.RED
126
+ style = Paint.Style.STROKE
127
+ strokeWidth = stroke
128
+ // Make the border dotted
129
+ pathEffect = DashPathEffect(floatArrayOf(stroke * 2, stroke * 2), 0f)
130
+ }
131
+ }
132
+
133
+ val left = -gap
134
+ val top = -gap
135
+ val right = view.width - half + gap
136
+ val bottom = view.height - half + gap
137
+
138
+ shape.setBounds(left, top, right, bottom)
139
+ view.overlay.add(shape)
140
+
141
+ val iconDrawable = object : Drawable() {
142
+ val fillPaint = Paint().apply {
143
+ this.color = color ?: Color.RED
144
+ style = Paint.Style.FILL
145
+ isAntiAlias = true
146
+ }
147
+ val textPaint = Paint().apply {
148
+ this.color = Color.WHITE
149
+ style = Paint.Style.FILL
150
+ textSize = 28f
151
+ textAlign = Paint.Align.CENTER
152
+ isAntiAlias = true
153
+ typeface = android.graphics.Typeface.DEFAULT_BOLD
154
+ }
155
+
156
+ override fun draw(canvas: Canvas) {
157
+ val badgeSize = 48f
158
+ val centerX = right.toFloat()
159
+ val centerY = top.toFloat()
160
+
161
+ // Draw circle badge
162
+ canvas.drawCircle(centerX, centerY, badgeSize / 2, fillPaint)
163
+
164
+ // Draw issue count text centered in circle
165
+ val textBounds = android.graphics.Rect()
166
+ val countText = issueCount.toString()
167
+ textPaint.getTextBounds(countText, 0, countText.length, textBounds)
168
+ val textY = centerY + textBounds.height() / 2f
169
+ canvas.drawText(countText, centerX, textY, textPaint)
170
+ }
171
+
172
+ override fun setAlpha(alpha: Int) {}
173
+ override fun setColorFilter(colorFilter: ColorFilter?) {}
174
+ override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
175
+ }
176
+
177
+ // We need to set bounds for the icon drawable too, usually view bounds is fine as we draw relative to coordinates
178
+ iconDrawable.setBounds(0, 0, view.width, view.height)
179
+ view.overlay.add(iconDrawable)
180
+ }
181
+ }
182
+
183
+ fun String.toColor(): Int {
184
+ if (this.length == 4 && this.startsWith("#")) {
185
+ val expandedHex = "#" + this[1] + this[1] + this[2] + this[2] + this[3] + this[3]
186
+ return Color.parseColor(expandedHex)
187
+ }
188
+ return Color.parseColor(this)
189
+ }
@@ -0,0 +1,25 @@
1
+ package expo.modules.ama
2
+
3
+ import android.util.Log
4
+
5
+ object Logger {
6
+ public fun info(fn: String, message: String, extra: String? = null) {
7
+ if (extra.isNullOrEmpty()) {
8
+ Log.i("[ReactNative AMA]: ", fn + " " + message)
9
+ } else {
10
+ Log.i("[ReactNative AMA]: ", fn + " " + message + " >>> " + extra)
11
+ }
12
+ }
13
+
14
+ public fun info2(fn: String, message: String) {
15
+ Logger.info(" " + fn, message)
16
+ }
17
+
18
+ public fun debug(fn: String, message: String) {
19
+ Log.d("[ReactNative AMA]: ", fn + " " + message)
20
+ }
21
+
22
+ public fun error(fn: String, message: String) {
23
+ Log.e("[ReactNative AMA - Error]: ", fn + " " + message)
24
+ }
25
+ }