Skip to content

Commit 5facb80

Browse files
authored
Merge pull request #3 from mobven/v1.0.3
[DEV][close button added]
2 parents 4bc4694 + 4089bc1 commit 5facb80

2 files changed

Lines changed: 112 additions & 79 deletions

File tree

mb-version/src/main/java/com/mobven/mb_version/MBVersionOverlay.kt

Lines changed: 108 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,41 @@
11
package com.mobven.mb_version
22

3-
import android.app.Activity
43
import android.annotation.SuppressLint
4+
import android.app.Activity
55
import android.app.Application
66
import android.content.Context
77
import android.content.pm.PackageInfo
88
import android.graphics.Color
99
import android.os.Build
1010
import android.view.Gravity
11+
import android.view.MotionEvent
1112
import android.view.View
13+
import android.view.ViewConfiguration
1214
import android.view.ViewGroup
1315
import android.widget.FrameLayout
16+
import android.widget.ImageView
1417
import android.widget.TextView
18+
import androidx.core.content.ContextCompat
19+
import com.mobven.mb_version.MBVersionOverlay.show
20+
import androidx.core.graphics.toColorInt
1521

1622
/**
1723
* A lightweight Android library for displaying app version information as an overlay on all activities.
1824
* @author Mobven
19-
* @version 1.0.1
25+
* @version 1.0.3
2026
* @since 1.0.0
2127
*/
2228
object MBVersionOverlay {
2329

2430
private var isEnabled = false
2531
private var customText: String? = null
26-
private var backgroundColor = Color.parseColor("#AA4444FF")
32+
private var backgroundColor = "#AA4444FF".toColorInt()
2733
private var textColor = Color.WHITE
2834
private var textSize = 16f
2935
private var position = Position.BOTTOM
3036
private var bottomMargin = 32
3137
private var isDraggable = true
38+
private var dismissedForSession = false
3239

3340
enum class Position {
3441
TOP, BOTTOM
@@ -43,12 +50,9 @@ object MBVersionOverlay {
4350
*
4451
* @since 1.0.0
4552
*/
46-
fun init(
47-
application: Application,
48-
enabled: Boolean = true
49-
) {
53+
fun init(application: Application, enabled: Boolean = true) {
5054
isEnabled = enabled
51-
55+
dismissedForSession = false
5256
if (isEnabled) {
5357
application.registerActivityLifecycleCallbacks(MBVersionOverlayLifecycleCallback())
5458
} else {
@@ -91,12 +95,7 @@ object MBVersionOverlay {
9195
*/
9296
fun show(activity: Activity, show: Boolean = true) {
9397
if (!isEnabled) return
94-
95-
if (show) {
96-
addOverlayToActivity(activity)
97-
} else {
98-
removeOverlayFromActivity(activity)
99-
}
98+
if (show) addOverlayToActivity(activity) else removeOverlayFromActivity(activity)
10099
}
101100

102101
/**
@@ -108,26 +107,15 @@ object MBVersionOverlay {
108107
* @since 1.0.0
109108
*/
110109
internal fun addOverlayToActivity(activity: Activity) {
111-
if (!isEnabled) {
112-
println("MBVersionOverlay: Not enabled, skipping")
110+
if (!isEnabled || dismissedForSession) {
111+
println("MBVersionOverlay: Not enabled or dismissed for session, skipping")
113112
return
114113
}
115-
116114
activity.runOnUiThread {
117-
println("MBVersionOverlay: Adding overlay to ${activity.javaClass.simpleName}")
118-
119-
val rootView = activity.findViewById<ViewGroup>(android.R.id.content)
120-
if (rootView == null) {
121-
println("MBVersionOverlay: Root view is null!")
122-
return@runOnUiThread
123-
}
124-
115+
val rootView =
116+
activity.findViewById<ViewGroup>(android.R.id.content) ?: return@runOnUiThread
125117
val overlayId = getOverlayId()
126-
127-
if (rootView.findViewById<View>(overlayId) != null) {
128-
println("MBVersionOverlay: Overlay already exists")
129-
return@runOnUiThread
130-
}
118+
if (rootView.findViewById<View>(overlayId) != null) return@runOnUiThread
131119

132120
val overlay = createOverlayView(activity)
133121
overlay.id = overlayId
@@ -140,14 +128,11 @@ object MBVersionOverlay {
140128
Position.TOP -> Gravity.TOP
141129
Position.BOTTOM -> Gravity.BOTTOM
142130
}
143-
144131
if (position == Position.BOTTOM) {
145132
bottomMargin = dpToPx(activity, this@MBVersionOverlay.bottomMargin)
146133
}
147134
}
148-
149135
rootView.addView(overlay, params)
150-
println("MBVersionOverlay: Overlay added successfully")
151136
}
152137
}
153138

@@ -181,28 +166,70 @@ object MBVersionOverlay {
181166
*
182167
* @since 1.0.0
183168
*/
184-
private fun createOverlayView(context: Context): TextView {
185-
return TextView(context).apply {
186-
text = getDisplayText(context)
169+
@SuppressLint("ClickableViewAccessibility")
170+
private fun createOverlayView(context: Context): View {
171+
val act = context as Activity
172+
173+
val container = FrameLayout(context).apply {
187174
setBackgroundColor(backgroundColor)
175+
elevation = 100f
176+
translationZ = 100f
177+
setPadding(
178+
dpToPx(context, 4),
179+
dpToPx(context, 4),
180+
dpToPx(context, 4),
181+
dpToPx(context, 4)
182+
)
183+
layoutParams = FrameLayout.LayoutParams(
184+
FrameLayout.LayoutParams.MATCH_PARENT,
185+
FrameLayout.LayoutParams.WRAP_CONTENT
186+
)
187+
}
188+
189+
val tv = TextView(context).apply {
190+
text = getDisplayText(context)
188191
setTextColor(textColor)
189192
textSize = this@MBVersionOverlay.textSize
190-
setPadding(16, 8, 16, 8)
191193
gravity = Gravity.CENTER
194+
layoutParams = FrameLayout.LayoutParams(
195+
FrameLayout.LayoutParams.MATCH_PARENT,
196+
FrameLayout.LayoutParams.WRAP_CONTENT
197+
).apply {
198+
marginEnd = dpToPx(context, 48)
199+
gravity = Gravity.CENTER_VERTICAL
200+
}
201+
}
192202

193-
elevation = 100f
194-
translationZ = 100f
195-
196-
if (isDraggable) {
197-
setupDragAndDrop(this)
198-
} else {
199-
setOnClickListener {
200-
visibility = if (visibility == View.VISIBLE) View.GONE else View.VISIBLE
201-
}
203+
val close = ImageView(context).apply {
204+
id = R.id.mb_version_close_button
205+
setPadding(
206+
dpToPx(context, 8),
207+
dpToPx(context, 8),
208+
dpToPx(context, 8),
209+
dpToPx(context, 8)
210+
)
211+
setImageResource(android.R.drawable.ic_menu_close_clear_cancel)
212+
imageTintList = ContextCompat.getColorStateList(context, android.R.color.white)
213+
layoutParams = FrameLayout.LayoutParams(
214+
FrameLayout.LayoutParams.WRAP_CONTENT,
215+
FrameLayout.LayoutParams.WRAP_CONTENT,
216+
Gravity.END or Gravity.CENTER_VERTICAL
217+
)
218+
setOnClickListener {
219+
dismissedForSession = true
220+
removeOverlayFromActivity(act)
202221
}
203222
}
223+
224+
container.addView(tv)
225+
container.addView(close)
226+
227+
if (isDraggable) setupDragOnly(container)
228+
229+
return container
204230
}
205231

232+
206233
/**
207234
* Generates the display text for the overlay.
208235
* If customText is set, it returns that. Otherwise, generates version info from PackageManager.
@@ -264,51 +291,55 @@ object MBVersionOverlay {
264291
* @since 1.0.1
265292
*/
266293
@SuppressLint("ClickableViewAccessibility")
267-
private fun setupDragAndDrop(view: TextView) {
294+
private fun setupDragOnly(view: View) {
268295
var dX = 0f
269296
var dY = 0f
270-
var lastAction = 0
271-
272-
view.setOnTouchListener { v, event ->
273-
when (event.actionMasked) {
274-
android.view.MotionEvent.ACTION_DOWN -> {
275-
dX = v.x - event.rawX
276-
dY = v.y - event.rawY
277-
lastAction = android.view.MotionEvent.ACTION_DOWN
297+
var startX = 0f
298+
var startY = 0f
299+
var dragging = false
300+
val slop = ViewConfiguration.get(view.context).scaledTouchSlop
301+
302+
view.setOnTouchListener { v, e ->
303+
when (e.actionMasked) {
304+
MotionEvent.ACTION_DOWN -> {
305+
dX = v.x - e.rawX
306+
dY = v.y - e.rawY
307+
startX = e.rawX
308+
startY = e.rawY
309+
dragging = false
310+
v.parent?.requestDisallowInterceptTouchEvent(true)
278311
true
279312
}
280313

281-
android.view.MotionEvent.ACTION_MOVE -> {
282-
val newX = event.rawX + dX
283-
val newY = event.rawY + dY
284-
285-
val parent = v.parent as? ViewGroup
286-
parent?.let { parentView ->
287-
val maxX = parentView.width - v.width
288-
val maxY = parentView.height - v.height
289-
290-
v.x = newX.coerceIn(0f, maxX.toFloat())
291-
v.y = newY.coerceIn(0f, maxY.toFloat())
314+
MotionEvent.ACTION_MOVE -> {
315+
val dx = e.rawX - startX
316+
val dy = e.rawY - startY
317+
if (!dragging && (kotlin.math.abs(dx) > slop || kotlin.math.abs(dy) > slop)) {
318+
dragging = true
292319
}
293-
294-
lastAction = android.view.MotionEvent.ACTION_MOVE
295-
true
320+
if (dragging) {
321+
val p = v.parent as? ViewGroup
322+
p?.let {
323+
val newX = (e.rawX + dX).coerceIn(0f, (it.width - v.width).toFloat())
324+
val newY = (e.rawY + dY).coerceIn(0f, (it.height - v.height).toFloat())
325+
v.x = newX; v.y = newY
326+
}
327+
true
328+
} else false
296329
}
297330

298-
android.view.MotionEvent.ACTION_UP -> {
299-
if (lastAction == android.view.MotionEvent.ACTION_DOWN) {
300-
v.visibility = if (v.visibility == View.VISIBLE) View.GONE else View.VISIBLE
301-
} else {
302-
snapToEdge(v)
303-
}
304-
true
331+
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
332+
if (dragging) {
333+
snapToEdge(v); true
334+
} else false
305335
}
306336

307337
else -> false
308338
}
309339
}
310340
}
311341

342+
312343
/**
313344
* Snaps the overlay to the nearest edge of the screen after dragging.
314345
* This provides a cleaner user experience by avoiding overlays in the middle of content.
@@ -367,13 +398,11 @@ object MBVersionOverlay {
367398

368399
/**
369400
* Generates a unique ID for the overlay view to prevent duplicates and enable easy retrieval.
370-
* Uses hash code of a constant string to ensure consistent ID across app lifecycle.
371-
*
372401
* @return Unique integer ID for the overlay view
373402
*
374403
* @since 1.0.0
375404
*/
376405
private fun getOverlayId(): Int {
377-
return "mb_version_overlay_view".hashCode()
406+
return R.id.mb_version_overlay_view
378407
}
379408
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<resources>
2+
<item name="mb_version_close_button" type="id" />
3+
<item name="mb_version_overlay_view" type="id" />
4+
</resources>

0 commit comments

Comments
 (0)