207 lines
9.1 KiB
Kotlin
207 lines
9.1 KiB
Kotlin
package com.adlerosn.brasilfurfest.helper
|
|
|
|
import android.app.Activity
|
|
import android.graphics.Point
|
|
import android.graphics.Rect
|
|
import androidx.annotation.IdRes
|
|
import androidx.annotation.LayoutRes
|
|
import androidx.appcompat.app.AlertDialog
|
|
import android.util.DisplayMetrics
|
|
import android.util.Log
|
|
import android.view.GestureDetector
|
|
import android.view.MotionEvent
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import kotlin.math.roundToInt
|
|
|
|
class PeekAndPop(builder: Builder) {
|
|
class Builder private constructor(val activity: Activity, val builderData: BuilderData) {
|
|
constructor(activity: Activity) : this(activity, BuilderData(
|
|
null,
|
|
null,
|
|
null,
|
|
false,
|
|
NullObjects.nullGeneralActionListener,
|
|
NullObjects.nullHoldAndReleaseListener
|
|
))
|
|
|
|
class BuilderData(
|
|
val peekLayout: Int?,
|
|
val longClickViews: View?,
|
|
val parentViewGroupToDisallowTouchEvents: ViewGroup?,
|
|
val blurs: Boolean,
|
|
val onGeneralActionListener: OnGeneralActionListener,
|
|
val onHoldAndReleaseListener: OnHoldAndReleaseListener
|
|
)
|
|
|
|
fun peekLayout(@LayoutRes layoutId: Int) = Builder(activity, BuilderData(
|
|
layoutId,
|
|
builderData.longClickViews,
|
|
builderData.parentViewGroupToDisallowTouchEvents,
|
|
builderData.blurs,
|
|
builderData.onGeneralActionListener,
|
|
builderData.onHoldAndReleaseListener
|
|
))
|
|
|
|
fun longClickViews(view: View): Builder = Builder(activity, BuilderData(
|
|
builderData.peekLayout,
|
|
view,
|
|
builderData.parentViewGroupToDisallowTouchEvents,
|
|
builderData.blurs,
|
|
builderData.onGeneralActionListener,
|
|
builderData.onHoldAndReleaseListener
|
|
))
|
|
|
|
fun parentViewGroupToDisallowTouchEvents(viewGroup: ViewGroup) = Builder(activity, BuilderData(
|
|
builderData.peekLayout,
|
|
builderData.longClickViews,
|
|
viewGroup,
|
|
builderData.blurs,
|
|
builderData.onGeneralActionListener,
|
|
builderData.onHoldAndReleaseListener
|
|
))
|
|
|
|
fun onGeneralActionListener(onGeneralActionListener: OnGeneralActionListener) = Builder(activity, BuilderData(
|
|
builderData.peekLayout,
|
|
builderData.longClickViews,
|
|
builderData.parentViewGroupToDisallowTouchEvents,
|
|
builderData.blurs,
|
|
onGeneralActionListener,
|
|
builderData.onHoldAndReleaseListener
|
|
))
|
|
|
|
fun onHoldAndReleaseListener(onHoldAndReleaseListener: PeekAndPop.OnHoldAndReleaseListener) = Builder(activity, BuilderData(
|
|
builderData.peekLayout,
|
|
builderData.longClickViews,
|
|
builderData.parentViewGroupToDisallowTouchEvents,
|
|
builderData.blurs,
|
|
builderData.onGeneralActionListener,
|
|
onHoldAndReleaseListener
|
|
))
|
|
|
|
fun blurBackground(blur: Boolean) = Builder(activity, BuilderData(
|
|
builderData.peekLayout,
|
|
builderData.longClickViews,
|
|
builderData.parentViewGroupToDisallowTouchEvents,
|
|
blur,
|
|
builderData.onGeneralActionListener,
|
|
builderData.onHoldAndReleaseListener
|
|
))
|
|
|
|
fun build(): PeekAndPop = PeekAndPop(this)
|
|
}
|
|
|
|
private val activity = builder.activity
|
|
private val peekLayout = builder.builderData.peekLayout!!
|
|
private val longClickViews = builder.builderData.longClickViews!!
|
|
private val parentViewGroupToDisallowTouchEvents = ( builder.builderData.parentViewGroupToDisallowTouchEvents ?: longClickViews ) as ViewGroup
|
|
private val onGeneralActionListener = builder.builderData.onGeneralActionListener
|
|
private val onHoldAndReleaseListener = builder.builderData.onHoldAndReleaseListener
|
|
|
|
val peekView = activity.layoutInflater.inflate(peekLayout)
|
|
|
|
init {
|
|
longClickViews.isLongClickable = true
|
|
longClickViews.setOnLongClickListener {
|
|
onGeneralActionListener.onPeek(longClickViews, -1)
|
|
parentViewGroupToDisallowTouchEvents.requestDisallowInterceptTouchEvent(true)
|
|
AlertDialog.Builder(activity)
|
|
.setView(peekView)
|
|
.setOnDismissListener {
|
|
(peekView.parent as ViewGroup).removeView(peekView)
|
|
longClickViews.setOnTouchListener(null)
|
|
cursorIsOver = null
|
|
onGeneralActionListener.onPop(longClickViews, -1)
|
|
}
|
|
.show()
|
|
.apply {
|
|
val dialog = this
|
|
window?.setBackgroundDrawableResource(android.R.color.transparent)
|
|
longClickViews.setOnTouchListener(object : View.OnTouchListener {
|
|
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
|
when {
|
|
event.action == MotionEvent.ACTION_CANCEL -> dialog.dismiss()
|
|
event.action == MotionEvent.ACTION_MOVE -> {
|
|
val metrics = DisplayMetrics()
|
|
activity.windowManager.defaultDisplay.getMetrics(metrics)
|
|
val winSize = Point(metrics.widthPixels, metrics.heightPixels+(40*metrics.density).roundToInt())
|
|
val peekSize = peekView.let { Point(it.width, it.height) }
|
|
val offset = Point(
|
|
((winSize.x/2) - (peekSize.x/2)),
|
|
((winSize.y/2) - (peekSize.y/2))
|
|
)
|
|
val newCursorIsOver = holdAndReleaseViews.firstOrNull { view ->
|
|
val relativePosition = Rect()
|
|
view.getGlobalVisibleRect(relativePosition)
|
|
val actualPosition = Rect(
|
|
relativePosition.left+offset.x,
|
|
relativePosition.top+offset.y,
|
|
relativePosition.right+offset.x,
|
|
relativePosition.bottom+offset.y
|
|
)
|
|
Point(event.rawX.roundToInt(), event.rawY.roundToInt()) in actualPosition
|
|
}
|
|
updateCursorIsOver(newCursorIsOver)
|
|
}
|
|
event.action == MotionEvent.ACTION_UP -> {
|
|
cursorIsOver?.let { releasedView ->
|
|
onHoldAndReleaseListener.onRelease(releasedView, -1)
|
|
|
|
}
|
|
dialog.dismiss()
|
|
}
|
|
else -> dialog.dismiss()
|
|
}
|
|
return false
|
|
}
|
|
})
|
|
}
|
|
true
|
|
}
|
|
}
|
|
private var cursorIsOver: View? = null
|
|
private val holdAndReleaseViews = mutableListOf<View>()
|
|
private fun updateCursorIsOver(view: View?){
|
|
if(view != cursorIsOver){
|
|
cursorIsOver?.let {
|
|
onHoldAndReleaseListener.onLeave(it, -1)
|
|
}
|
|
view?.let {
|
|
onHoldAndReleaseListener.onHold(it, -1)
|
|
}
|
|
cursorIsOver = view
|
|
}
|
|
}
|
|
|
|
fun addHoldAndReleaseView(@IdRes idRes: Int) {
|
|
peekView.findViewById<View?>(idRes)?.let {
|
|
holdAndReleaseViews.add(it)
|
|
}
|
|
}
|
|
|
|
interface OnGeneralActionListener {
|
|
fun onPeek(longClickView: View, position: Int)
|
|
fun onPop(longClickView: View, position: Int)
|
|
}
|
|
|
|
interface OnHoldAndReleaseListener {
|
|
fun onHold(view: View, position: Int)
|
|
fun onLeave(view: View, position: Int)
|
|
fun onRelease(view: View, position: Int)
|
|
}
|
|
|
|
private object NullObjects {
|
|
val nullGeneralActionListener = object : OnGeneralActionListener{
|
|
override fun onPeek(longClickView: View, position: Int) {}
|
|
override fun onPop(longClickView: View, position: Int) {}
|
|
}
|
|
val nullHoldAndReleaseListener = object : OnHoldAndReleaseListener{
|
|
override fun onHold(view: View, position: Int) {}
|
|
override fun onLeave(view: View, position: Int) {}
|
|
override fun onRelease(view: View, position: Int) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
private operator fun Rect.contains(point: Point): Boolean = contains(point.x, point.y)
|