284 lines
12 KiB
Kotlin
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()
|
|
} |