485 lines
20 KiB
Kotlin
485 lines
20 KiB
Kotlin
package com.gh.common.dialog
|
|
|
|
import android.animation.ValueAnimator
|
|
import android.content.Context
|
|
import android.content.DialogInterface
|
|
import android.content.pm.PackageInfo
|
|
import android.os.Bundle
|
|
import android.view.LayoutInflater
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.view.animation.LinearInterpolator
|
|
import android.widget.LinearLayout
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.core.view.isVisible
|
|
import androidx.fragment.app.FragmentTransaction
|
|
import androidx.lifecycle.Lifecycle
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import com.gh.common.util.DirectUtils
|
|
import com.gh.common.util.LogUtils
|
|
import com.gh.common.util.PackageUtils
|
|
import com.gh.download.DownloadManager
|
|
import com.gh.gamecenter.R
|
|
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
|
import com.gh.gamecenter.common.callback.ConfirmListener
|
|
import com.gh.gamecenter.common.constant.Constants
|
|
import com.gh.gamecenter.common.entity.LinkEntity
|
|
import com.gh.gamecenter.common.utils.*
|
|
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
|
|
import com.gh.gamecenter.core.utils.DisplayUtils
|
|
import com.gh.gamecenter.core.utils.SPUtils
|
|
import com.gh.gamecenter.core.utils.SpanBuilder
|
|
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
|
|
import com.gh.gamecenter.databinding.PackageCheckItemBinding
|
|
import com.gh.gamecenter.feature.entity.DetectionObjectEntity
|
|
import com.gh.gamecenter.feature.entity.GameEntity
|
|
import com.gh.gamecenter.feature.entity.PackageDialogEntity
|
|
import com.gh.gamecenter.eventbus.EBPackage
|
|
import com.halo.assistant.HaloApp
|
|
import com.lightgame.adapter.BaseRecyclerAdapter
|
|
import com.lightgame.dialog.BaseDialogFragment
|
|
import com.lightgame.download.DataWatcher
|
|
import com.lightgame.download.DownloadEntity
|
|
import com.lightgame.download.DownloadStatus
|
|
import io.reactivex.disposables.Disposable
|
|
import org.greenrobot.eventbus.EventBus
|
|
import org.greenrobot.eventbus.Subscribe
|
|
import org.greenrobot.eventbus.ThreadMode
|
|
|
|
/**
|
|
* 包名检测弹窗
|
|
*/
|
|
// TODO 将 gameEntity 放到 argument 里再取出,避免重建时为空
|
|
class PackageCheckDialogFragment : BaseDialogFragment() {
|
|
|
|
private lateinit var binding: FragmentPackageCheckBinding
|
|
private var mTotalWidth = 0f
|
|
private val mDuration = 3000
|
|
private var mDisposable: Disposable? = null
|
|
private var mAdapter: PackageCheckAdapter? = null
|
|
private var mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
|
var gameEntity: GameEntity? = null
|
|
var callBack: ConfirmListener? = null
|
|
|
|
private var mDismissByTouchInside = false
|
|
|
|
private val dataWatcher = object : DataWatcher() {
|
|
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
|
val packageName = downloadEntity.packageName
|
|
val detectionObjects = gameEntity?.packageDialog?.detectionObjects
|
|
if (DownloadStatus.add == downloadEntity.status || DownloadStatus.done == downloadEntity.status) {
|
|
detectionObjects?.forEach { detectionObject ->
|
|
if (detectionObject.packages.contains(packageName)) {
|
|
val packageLink = gameEntity?.packageDialog?.links?.find { it.buttonLink }
|
|
LogUtils.uploadPackageCheck(
|
|
"pkg_check_pop_download",
|
|
if (DownloadStatus.add == downloadEntity.status) "下载开始" else "下载完成",
|
|
gameEntity,
|
|
packageLink?.text ?: "",
|
|
packageLink?.title
|
|
?: "",
|
|
downloadEntity.gameId,
|
|
downloadEntity.getMetaExtra(Constants.GAME_NAME)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
EventBus.getDefault().register(this)
|
|
gameEntity?.let {
|
|
LogUtils.uploadPackageCheck("pkg_check_pop_click", "出现弹窗", it, "", "", "", "")
|
|
SensorsBridge.trackPkgCheckDialogShow(
|
|
gameId = it.id,
|
|
gameName = it.name ?: "",
|
|
gameType = it.categoryChinese
|
|
)
|
|
}
|
|
}
|
|
|
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
|
binding = FragmentPackageCheckBinding.inflate(inflater, container, false)
|
|
return binding.root
|
|
}
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
super.onViewCreated(view, savedInstanceState)
|
|
gameEntity?.packageDialog?.let {
|
|
changeParams(it.detectionObjects.size)
|
|
|
|
binding.packageRv.layoutManager = LinearLayoutManager(requireContext())
|
|
mAdapter = PackageCheckAdapter(requireContext(), it.detectionObjects)
|
|
binding.packageRv.adapter = mAdapter
|
|
|
|
binding.titleTv.text = it.title
|
|
binding.contentTv.text = it.content
|
|
|
|
val spanBuilder = SpanBuilder(it.linkHintText).build()
|
|
it.links.forEachIndexed { index, link ->
|
|
val linkSpan = SpanBuilder(link.title ?: "").click(
|
|
requireContext(),
|
|
0,
|
|
(link.title ?: "").length,
|
|
R.color.text_theme,
|
|
true
|
|
) {
|
|
LogUtils.uploadPackageCheck(
|
|
"pkg_check_pop_click",
|
|
"点击链接",
|
|
gameEntity,
|
|
link.text,
|
|
link.title,
|
|
"",
|
|
""
|
|
)
|
|
SensorsBridge.trackPkgCheckDialogClick(
|
|
buttonName = "点击链接",
|
|
gameId = gameEntity?.id ?: "",
|
|
gameName = gameEntity?.name ?: "",
|
|
gameType = gameEntity?.categoryChinese ?: "",
|
|
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
|
|
binding.noRemindAgainCb.isChecked
|
|
} else null,
|
|
linkId = link.link ?: "",
|
|
linkType = link.type ?: "",
|
|
linkText = link.linkText ?: ""
|
|
)
|
|
DirectUtils.directToLinkPage(requireContext(), link, "包名检测弹窗", "")
|
|
}.build()
|
|
spanBuilder.append(linkSpan)
|
|
if (index != it.links.size - 1) {
|
|
spanBuilder.append("、")
|
|
}
|
|
}
|
|
binding.linkHintTv.text = spanBuilder
|
|
binding.linkHintTv.movementMethod = CustomLinkMovementMethod.getInstance()
|
|
|
|
when (it.level) {
|
|
"HINT_SKIP" -> {
|
|
binding.cancelTv.text = "取消"
|
|
binding.noRemindAgainCb.visibility = View.GONE
|
|
}
|
|
"ALWAYS_HINT" -> {
|
|
binding.cancelTv.text = "我知道了"
|
|
binding.noRemindAgainCb.visibility = View.GONE
|
|
}
|
|
"OPTIONAL_CURRENT_HINT" -> {
|
|
binding.cancelTv.text = "我知道了"
|
|
binding.noRemindAgainCb.visibility = View.VISIBLE
|
|
}
|
|
else -> {
|
|
binding.cancelTv.text = "我知道了"
|
|
binding.noRemindAgainCb.visibility = View.VISIBLE
|
|
}
|
|
}
|
|
initListener(it)
|
|
}
|
|
binding.root.post {
|
|
checkPackage()
|
|
}
|
|
}
|
|
|
|
private fun changeParams(size: Int) {
|
|
val params = binding.packageRv.layoutParams as LinearLayout.LayoutParams
|
|
params.height = if (size > 3) (28f.dip2px() * 3.5).toInt() else 28f.dip2px() * size
|
|
binding.packageRv.layoutParams = params
|
|
}
|
|
|
|
private fun initListener(entity: PackageDialogEntity) {
|
|
binding.downloadBtn.setOnClickListener {
|
|
if (binding.noRemindAgainCb.isChecked) {
|
|
saveRecord(entity)
|
|
}
|
|
val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
|
|
if (isAllPackageInstalled) {
|
|
mDismissByTouchInside = true
|
|
callBack?.onConfirm()
|
|
dismissAllowingStateLoss()
|
|
} else {
|
|
var packageLink = getNotInstalledLink(entity)
|
|
if (packageLink == null) {
|
|
packageLink = entity.links.find { it.buttonLink }
|
|
}
|
|
if (packageLink != null) {
|
|
LogUtils.uploadPackageCheck(
|
|
"pkg_check_pop_click",
|
|
"点击前往下载",
|
|
gameEntity,
|
|
packageLink.text,
|
|
packageLink.title,
|
|
"",
|
|
""
|
|
)
|
|
SensorsBridge.trackPkgCheckDialogClick(
|
|
buttonName = "点击前往下载",
|
|
gameId = gameEntity?.id ?: "",
|
|
gameName = gameEntity?.name ?: "",
|
|
gameType = gameEntity?.categoryChinese ?: "",
|
|
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
|
|
binding.noRemindAgainCb.isChecked
|
|
} else null
|
|
)
|
|
DirectUtils.directToLinkPage(requireContext(), packageLink, "包名检测弹窗", "")
|
|
}
|
|
}
|
|
}
|
|
|
|
binding.cancelTv.setOnClickListener {
|
|
if (entity.level != "HINT_SKIP") {
|
|
callBack?.onConfirm()
|
|
}
|
|
if (binding.noRemindAgainCb.isChecked) {
|
|
saveRecord(entity)
|
|
LogUtils.uploadPackageCheck("pkg_check_pop_click", "不再提示", gameEntity, "", "", "", "")
|
|
}
|
|
|
|
mDismissByTouchInside = true
|
|
|
|
SensorsBridge.trackPkgCheckDialogClick(
|
|
buttonName = binding.cancelTv.text.toString(),
|
|
gameId = gameEntity?.id ?: "",
|
|
gameName = gameEntity?.name ?: "",
|
|
gameType = gameEntity?.categoryChinese ?: "",
|
|
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
|
|
binding.noRemindAgainCb.isChecked
|
|
} else null
|
|
)
|
|
|
|
dismissAllowingStateLoss()
|
|
}
|
|
}
|
|
|
|
private fun saveRecord(entity: PackageDialogEntity) {
|
|
if (entity.level == "OPTIONAL_CURRENT_HINT") {
|
|
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.id}", true)
|
|
} else {
|
|
SPUtils.setBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity?.packageDialog?.id}", true)
|
|
}
|
|
}
|
|
|
|
private fun checkPackage() {
|
|
var index = 0
|
|
mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat()
|
|
mDisposable = rxTimer(1) {
|
|
gameEntity?.packageDialog?.detectionObjects?.let { objects ->
|
|
if (objects.isNotEmpty()) {
|
|
val averageTime = if (objects.size == 1) {
|
|
mDuration
|
|
} else {
|
|
mDuration / objects.size
|
|
}
|
|
if (it != 0L && it % averageTime == 0L && index < objects.size) {
|
|
mAdapter?.notifyPackages()
|
|
binding.packageRv.smoothScrollToPosition(index)
|
|
index++
|
|
}
|
|
}
|
|
}
|
|
|
|
if (it >= mDuration) {
|
|
mDisposable?.dispose()
|
|
binding.downloadBtn.isEnabled = true
|
|
binding.downloadBtn.background = R.drawable.bg_notification_open_btn_style_2.toDrawable()
|
|
}
|
|
}
|
|
val animator = ValueAnimator.ofInt(0, 100)
|
|
animator.duration = mDuration.toLong()
|
|
animator.interpolator = LinearInterpolator()
|
|
animator.addUpdateListener {
|
|
binding.progressBar.progress = it.animatedValue as Int
|
|
}
|
|
animator.start()
|
|
}
|
|
|
|
private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
|
|
val links = LinkedHashSet<LinkEntity>()
|
|
packageDialogEntity.detectionObjects.forEach { obj ->
|
|
if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
|
|
obj.assignDownload.forEach {
|
|
links.add(packageDialogEntity.links[it])
|
|
}
|
|
}
|
|
}
|
|
var link: LinkEntity? = null
|
|
if (links.size > 1) {
|
|
link = links.find { it.buttonLink } ?: links.toList()[0]
|
|
} else if (links.size == 1) {
|
|
link = links.toList()[0]
|
|
}
|
|
return link
|
|
}
|
|
|
|
override fun onStart() {
|
|
super.onStart()
|
|
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
|
|
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
|
requireDialog().window?.setLayout(width, height)
|
|
requireDialog().setCanceledOnTouchOutside(true)
|
|
DownloadManager.getInstance().addObserver(dataWatcher)
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
|
gameEntity?.packageDialog?.let {
|
|
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
|
|
callBack?.onConfirm()
|
|
dismissAllowingStateLoss()
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onDestroyView() {
|
|
super.onDestroyView()
|
|
EventBus.getDefault().unregister(this)
|
|
if (mDisposable?.isDisposed == false) {
|
|
mDisposable?.dispose()
|
|
}
|
|
LogUtils.uploadPackageCheck("pkg_check_pop_click", "关闭弹窗", gameEntity, "", "", "", "")
|
|
DownloadManager.getInstance().removeObserver(dataWatcher)
|
|
}
|
|
|
|
override fun onDismiss(dialog: DialogInterface) {
|
|
if (!mDismissByTouchInside) {
|
|
SensorsBridge.trackPkgCheckDialogClick(
|
|
buttonName = "关闭弹窗",
|
|
gameId = gameEntity?.id ?: "",
|
|
gameName = gameEntity?.name ?: "",
|
|
gameType = gameEntity?.categoryChinese ?: "",
|
|
isNotPrompt = if (binding.noRemindAgainCb.isVisible) {
|
|
binding.noRemindAgainCb.isChecked
|
|
} else null
|
|
)
|
|
}
|
|
super.onDismiss(dialog)
|
|
}
|
|
|
|
//安装、卸载事件
|
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
fun onEventMainThread(busFour: EBPackage) {
|
|
if (busFour.isInstalledOrUninstalled()) {
|
|
mAllInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
|
mAdapter?.notifyDataSetChanged()
|
|
}
|
|
}
|
|
|
|
inner class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) :
|
|
BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
|
private var index = -1
|
|
|
|
fun notifyPackages() {
|
|
index++
|
|
notifyItemChanged(index)
|
|
}
|
|
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
|
return PackageCheckViewHolder(parent.toBinding())
|
|
}
|
|
|
|
override fun getItemCount(): Int = entities.size
|
|
|
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
|
if (holder is PackageCheckViewHolder) {
|
|
val entity = entities[position]
|
|
holder.binding.gameNameTv.text = entity.text
|
|
if (position <= index) {
|
|
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
|
|
if (isAllInstalled) {
|
|
holder.binding.statusTv.text = "已安装"
|
|
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.text_theme))
|
|
} else {
|
|
holder.binding.statusTv.text = "未安装"
|
|
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.secondary_red))
|
|
}
|
|
holder.binding.statusTv.visibility = View.VISIBLE
|
|
} else {
|
|
holder.binding.statusTv.visibility = View.GONE
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class PackageCheckViewHolder(val binding: PackageCheckItemBinding) :
|
|
BaseRecyclerViewHolder<DetectionObjectEntity>(binding.root)
|
|
|
|
companion object {
|
|
@JvmStatic
|
|
fun show(activity: AppCompatActivity, gameEntity: GameEntity, callBack: ConfirmListener) {
|
|
val packageDialogEntity = gameEntity.packageDialog
|
|
if (packageDialogEntity == null) {
|
|
callBack.onConfirm()
|
|
return
|
|
}
|
|
|
|
val allInstalledPackages = PackageUtils.getInstalledPackages(HaloApp.getInstance().application, 0)
|
|
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
|
|
callBack.onConfirm()
|
|
return
|
|
}
|
|
|
|
val isChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${packageDialogEntity.id}", false)
|
|
if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
|
|
callBack.onConfirm()
|
|
return
|
|
}
|
|
|
|
val isCurrentGameChoose = SPUtils.getBoolean("${Constants.SP_PACKAGE_CHECK}:${gameEntity.id}", false)
|
|
if (packageDialogEntity.level == "OPTIONAL_CURRENT_HINT" && isCurrentGameChoose) {
|
|
callBack.onConfirm()
|
|
return
|
|
}
|
|
|
|
if (!activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return
|
|
|
|
var dialogFragment =
|
|
activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.name) as? PackageCheckDialogFragment
|
|
if (dialogFragment == null) {
|
|
dialogFragment = PackageCheckDialogFragment()
|
|
dialogFragment.gameEntity = gameEntity
|
|
dialogFragment.callBack = callBack
|
|
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.name)
|
|
} else {
|
|
dialogFragment.gameEntity = gameEntity
|
|
dialogFragment.callBack = callBack
|
|
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
|
|
transaction.show(dialogFragment)
|
|
transaction.commit()
|
|
}
|
|
}
|
|
|
|
private fun checkDetectionsInstalled(
|
|
allInstalledPackages: List<PackageInfo>,
|
|
packages: ArrayList<String>
|
|
): Boolean {
|
|
var isPackagesInstalled = false
|
|
packages.forEach { packageName ->
|
|
val isInstalled = allInstalledPackages.find { it.packageName == packageName } != null
|
|
if (isInstalled) {
|
|
isPackagesInstalled = true
|
|
return@forEach
|
|
}
|
|
}
|
|
return isPackagesInstalled
|
|
}
|
|
|
|
|
|
fun isAllPackageInstalled(
|
|
allInstalledPackages: List<PackageInfo>,
|
|
packageDialogEntity: PackageDialogEntity
|
|
): Boolean {
|
|
var isAllInstalled = true
|
|
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
|
|
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
|
|
isAllInstalled = false
|
|
return isAllInstalled
|
|
}
|
|
}
|
|
return isAllInstalled
|
|
}
|
|
}
|
|
} |