Files
assistant-android/app/src/main/java/com/gh/vspace/VLoadCompleteWindowHelper.kt

284 lines
12 KiB
Kotlin

package com.gh.vspace
import android.animation.*
import android.app.Activity
import android.content.Context
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.get
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.core.utils.ClickUtils
import com.gh.gamecenter.core.utils.doOnEnd
import com.gh.gamecenter.databinding.ItemFloatGameLoadCompleteBinding
import com.gh.gamecenter.databinding.LayoutFloatLoadCompleteBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.vspace.Constants.LAUNCH_LOCATION_FLOATING_WINDOW
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lzf.easyfloat.EasyFloat
import com.lzf.easyfloat.enums.SidePattern
import com.lzf.easyfloat.interfaces.OnFloatAnimator
import java.lang.ref.WeakReference
@Deprecated("use VGameInstalledLaunchDialog instead.")
object VLoadCompleteWindowHelper {
private const val LOAD_COMPLETE_WINDOW = "load_complete_window"
private const val LOOP_TIME = 2000L
private const val LOOP_DURATION = 200L
private const val AUTO_DISMISS_TIME = 3000L
private val mDismissTask = Runnable { EasyFloat.dismiss(LOAD_COMPLETE_WINDOW) }
fun showFloatingWindow(activity: Activity, gameEntity: GameEntity) {
showFloatingWindow(activity, listOf(gameEntity))
}
fun showFloatingWindow(activity: Activity, gameEntityList: List<GameEntity> = emptyList()) {
val floatingView = EasyFloat.getFloatView(LOAD_COMPLETE_WINDOW)
if (floatingView != null) {
if (!EasyFloat.isShow(LOAD_COMPLETE_WINDOW)) EasyFloat.show(LOAD_COMPLETE_WINDOW)
floatingView.findViewById<ConstraintLayout>(R.id.container)?.let {
val binding = LayoutFloatLoadCompleteBinding.bind(it)
binding.viewPager.run {
val adapter = adapter
var isLastItem = false
if (adapter is GameLoadCompleteAdapter) {
if (currentItem == adapter.gameEntityList.size - 1) isLastItem = true
adapter.submitList(gameEntityList)
}
removeCallbacks(mDismissTask)
if (isLastItem) {
val mLoopTask = object : Runnable {
private val reference: WeakReference<ViewPager2> = WeakReference(binding.viewPager)
override fun run() {
val vp: ViewPager2? = reference.get()
if (vp != null) {
val count = binding.viewPager.adapter?.itemCount ?: 0
if (count == 0) return
val next = vp.currentItem + 1
if (next < count) {
vp.setCurrentItem(next, LOOP_DURATION)
vp.postDelayed(this, LOOP_TIME)
} else {
vp.postDelayed(mDismissTask, AUTO_DISMISS_TIME)
}
}
}
}
post(mLoopTask)
}
}
}
return
}
EasyFloat.with(activity)
.setLayout(R.layout.layout_float_load_complete)
.setTag(LOAD_COMPLETE_WINDOW)
.setDragEnable(false)
.setMatchParent(widthMatch = true, heightMatch = false)
.setGravity(Gravity.BOTTOM, 0, (-62F).dip2px())
.setAnimator(LoadCompleteFloatAnimator())
.registerCallback {
createResult { _, _, view ->
view?.findViewById<ConstraintLayout>(R.id.container)?.let {
initFloatingView(it, activity, gameEntityList)
}
}
}
.show()
}
private fun initFloatingView(view: ConstraintLayout, activity: Activity, entityList: List<GameEntity>) {
val mBinding = LayoutFloatLoadCompleteBinding.bind(view)
val mAdapter = GameLoadCompleteAdapter(activity, entityList)
val mLoopTask = object : Runnable {
private val reference: WeakReference<ViewPager2> = WeakReference(mBinding.viewPager)
override fun run() {
val vp: ViewPager2? = reference.get()
if (vp != null) {
val count = mBinding.viewPager.adapter?.itemCount ?: 0
if (count == 0) return
val next = vp.currentItem + 1
if (next < count) {
vp.setCurrentItem(next, LOOP_DURATION)
vp.postDelayed(this, LOOP_TIME)
} else {
vp.postDelayed(mDismissTask, AUTO_DISMISS_TIME)
}
}
}
}
mBinding.viewPager.run {
adapter = mAdapter
isUserInputEnabled = false
orientation = ViewPager2.ORIENTATION_VERTICAL
offscreenPageLimit = entityList.size
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
val layoutManager = (get(0) as RecyclerView).layoutManager as LinearLayoutManager
layoutManager.findViewByPosition(position)?.alpha = 1 - positionOffset
layoutManager.findViewByPosition(position + 1)?.alpha = positionOffset
}
})
if (entityList.size > 1) {
postDelayed(mLoopTask, LOOP_TIME)
} else {
postDelayed(mDismissTask, AUTO_DISMISS_TIME)
}
}
mBinding.closeIv.setOnClickListener {
if (!ClickUtils.isFastDoubleClick(it.id)) {
NewFlatLogUtils.logHaloFunDownloadCompleteTipClick(
"关闭",
mAdapter.gameEntityList[mBinding.viewPager.currentItem].id
)
mBinding.viewPager.removeCallbacks(mLoopTask)
mBinding.viewPager.removeCallbacks(mDismissTask)
EasyFloat.dismiss(LOAD_COMPLETE_WINDOW)
}
}
mBinding.launchTv.setOnClickListener {
NewFlatLogUtils.logHaloFunDownloadCompleteTipClick(
"启动",
mAdapter.gameEntityList[mBinding.viewPager.currentItem].id
)
VHelper.installOrLaunch(activity, mAdapter.gameEntityList[mBinding.viewPager.currentItem], LAUNCH_LOCATION_FLOATING_WINDOW)
}
}
}
class LoadCompleteFloatAnimator : OnFloatAnimator {
override fun enterAnim(
view: View,
params: WindowManager.LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator = getEnterAnimator(view)
override fun exitAnim(
view: View,
params: WindowManager.LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator = getExitAnimator(view)
private fun getEnterAnimator(view: View): Animator {
val alphaAnimator = ObjectAnimator.ofFloat(view, "alpha", 0F, 1F).apply {
duration = DURATION
interpolator = AccelerateDecelerateInterpolator()
}
val scaleXAnimator = ObjectAnimator.ofFloat(view, "scaleX", 0.8F, 1F).apply {
duration = DURATION
interpolator = AccelerateDecelerateInterpolator()
}
val scaleYAnimator = ObjectAnimator.ofFloat(view, "scaleY", 0.8F, 1F).apply {
duration = DURATION
interpolator = AccelerateDecelerateInterpolator()
}
view.pivotX = view.width / 2F
view.pivotY = view.height / 2F
return AnimatorSet().apply { playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator) }
}
private fun getExitAnimator(view: View): Animator {
val alphaAnimator = ObjectAnimator.ofFloat(view, "alpha", 1F, 0F).apply {
duration = DURATION
interpolator = AccelerateDecelerateInterpolator()
}
val scaleXAnimator = ObjectAnimator.ofFloat(view, "scaleX", 1F, 0.8F).apply {
duration = DURATION
interpolator = AccelerateDecelerateInterpolator()
}
val scaleYAnimator = ObjectAnimator.ofFloat(view, "scaleY", 1F, 0.8F).apply {
duration = DURATION
interpolator = AccelerateDecelerateInterpolator()
}
view.pivotX = view.width / 2F
view.pivotY = view.height / 2F
return AnimatorSet().apply {
playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator)
doOnEnd {
view.visibility = View.GONE
}
}
}
companion object {
const val DURATION = 200L
}
}
class GameLoadCompleteAdapter(context: Context, var gameEntityList: List<GameEntity> = emptyList()) :
BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
fun submitList(entityList: List<GameEntity>) {
if (entityList.isNotEmpty()) {
gameEntityList = arrayListOf<GameEntity>().apply {
addAll(gameEntityList)
addAll(entityList)
}
notifyDataSetChanged()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = GameLoadCompleteViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameLoadCompleteViewHolder) {
val gameEntity = gameEntityList[position]
holder.binding.gameIconIv.displayGameIcon(gameEntity)
holder.binding.gameNameTv.text = gameEntity.name
}
}
override fun getItemCount() = gameEntityList.size
class GameLoadCompleteViewHolder(val binding: ItemFloatGameLoadCompleteBinding) :
RecyclerView.ViewHolder(binding.root)
}
private fun ViewPager2.setCurrentItem(
item: Int,
duration: Long,
interpolator: TimeInterpolator = AccelerateDecelerateInterpolator(),
pagePxHeight: Int = height
) {
val pxToDrag: Int = pagePxHeight * (item - currentItem)
val animator = ValueAnimator.ofInt(0, pxToDrag)
var previousValue = 0
animator.addUpdateListener { valueAnimator ->
val currentValue = valueAnimator.animatedValue as Int
val currentPxToDrag = (currentValue - previousValue).toFloat()
fakeDragBy(-currentPxToDrag)
previousValue = currentValue
}
animator.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
beginFakeDrag()
}
override fun onAnimationEnd(animation: Animator) {
endFakeDrag()
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
animator.interpolator = interpolator
animator.duration = duration
animator.start()
}