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 = emptyList()) { val floatingView = EasyFloat.getFloatView(LOAD_COMPLETE_WINDOW) if (floatingView != null) { if (!EasyFloat.isShow(LOAD_COMPLETE_WINDOW)) EasyFloat.show(LOAD_COMPLETE_WINDOW) floatingView.findViewById(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 = 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(R.id.container)?.let { initFloatingView(it, activity, gameEntityList) } } } .show() } private fun initFloatingView(view: ConstraintLayout, activity: Activity, entityList: List) { val mBinding = LayoutFloatLoadCompleteBinding.bind(view) val mAdapter = GameLoadCompleteAdapter(activity, entityList) val mLoopTask = object : Runnable { private val reference: WeakReference = 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 = emptyList()) : BaseRecyclerAdapter(context) { fun submitList(entityList: List) { if (entityList.isNotEmpty()) { gameEntityList = arrayListOf().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() }