Merge branch 'dev-4.5.0' into dev

# Conflicts:
#	app/src/main/java/com/gh/download/DownloadDataHelper.kt
This commit is contained in:
chenjuntao
2020-12-02 09:51:41 +08:00
313 changed files with 9137 additions and 2622 deletions

View File

@ -26,6 +26,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import io.sentry.core.Sentry;
public class AppUncaughtHandler implements UncaughtExceptionHandler {
private Context mContext;
@ -45,7 +47,9 @@ public class AppUncaughtHandler implements UncaughtExceptionHandler {
Looper.loop();
}
});
saveLocalLog(mContext, ex);
Sentry.captureException(ex);
restart(mContext);
}

View File

@ -32,13 +32,17 @@ import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.StringUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.lightgame.BaseAppCompatActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
@ -122,6 +126,23 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
if (BuildConfig.DEBUG) {
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
}
if (savedInstanceState != null) {
String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY);
String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL);
Utils.log("页面重建了--" + xapkUnzipActivity + "--" + xapkUrl);
if (this.getClass().getName().equals(SplashScreenActivity.class.getName())) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
return;
}
if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) {
DownloadEntity downloadEntity = DownloadManager.getInstance(this).getDownloadEntityByUrl(xapkUrl);
PackageInstaller.install(this, downloadEntity, false);
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
}
}
}
@SuppressWarnings("ConstantConditions")

View File

@ -81,8 +81,13 @@ public class WaitingDialogFragment extends BaseDialogFragment {
@Override
public void dismiss() {
dismissAllowingStateLoss();
}
@Override
public void dismissAllowingStateLoss() {
mBackListener = null;
super.dismiss();
super.dismissAllowingStateLoss();
}
public static class WaitingDialogData {

View File

@ -252,6 +252,11 @@ class DefaultJsApi(var context: Context) {
}
}
@JavascriptInterface
fun openInNewWebview(url: Any) {
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") }
}
@Keep
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)

View File

@ -129,6 +129,11 @@ public class Constants {
public static final String SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT = "has_user_accepted_privacy_statement";
public static final String SP_BRAND_NEW_USER = "brand_new_user";
//包名检测是否点击不再提示
public static final String SP_PACKAGE_CHECK = "package_check";
public static final String SP_XAPK_UNZIP_ACTIVITY = "xapk_unzip_activity";
public static final String SP_XAPK_URL = "xapk_url";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";

View File

@ -14,10 +14,17 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.base.OnViewClickListener;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.PackageCheckDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
@ -38,7 +45,6 @@ import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PermissionHelper;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.common.view.DownloadProgressBar;
@ -74,12 +80,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Created by khy on 12/02/18.
*/
@ -256,6 +256,14 @@ public class BindingAdapters {
}
}
/**
* lazy 的 paddingTop
*/
@BindingAdapter("lazyPaddingLeft")
public static void lazyPaddingLeft(View view, int paddingLeftInDp) {
view.setPadding(DisplayUtils.dip2px(paddingLeftInDp), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
}
/**
* lazy 的 paddingTop
*/
@ -448,12 +456,14 @@ public class BindingAdapters {
return;
}
}
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
});
});
});
});
@ -509,13 +519,11 @@ public class BindingAdapters {
break;
case RESERVABLE:
CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(progressBar.getContext(), () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
});
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(gameEntity, () -> {
LogUtils.logReservation(gameEntity, traceEvent);
updateReservation(progressBar, gameEntity);
});
dialogFragment.show(((AppCompatActivity) progressBar.getContext()).getSupportFragmentManager(), "reserve");
});
break;
case RESERVED:

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,7 @@ class GameOffServiceDialogFragment
siteTv.setOnClickListener {
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
dismiss()
dismissAllowingStateLoss()
}
container.addView(siteTv)

View File

@ -13,16 +13,19 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentTransaction
import com.airbnb.lottie.LottieAnimationView
import com.gh.common.constant.Config
import com.gh.common.util.MtaHelper
import com.gh.common.util.PermissionHelper
import com.gh.common.util.PermissionHelper.INSTALL_PERMISS_CODE
import com.gh.common.util.goneIf
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.util.PermissionHelper.INSTALL_PERMISSION_CODE
import com.gh.common.xapk.XapkInstaller
import com.gh.gamecenter.R
import com.lightgame.download.DownloadEntity
import kotlin.random.Random
class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
lateinit var mView: View
var isXapk = false
var url: String = ""
var mCallBack: (() -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -35,16 +38,26 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
val closeTv = mView.findViewById<TextView>(R.id.closeTv)
val closeIv = mView.findViewById<ImageView>(R.id.closeIv)
val activateTv = mView.findViewById<TextView>(R.id.activateTv)
val contentTv = mView.findViewById<TextView>(R.id.contentTv)
val switchLottie = mView.findViewById<LottieAnimationView>(R.id.switchLottie)
contentTv.text = if (isXapk) "未授权下解压XAPK可能导致解压失败" else "以保证游戏的安装和更新"
switchLottie.setAnimation("lottie/install_permission_switch.json")
switchLottie.playAnimation()
val randomNumber = Random.nextInt(2)
val randomNumber = if (isXapk) 1 else Random.nextInt(2)
closeTv.goneIf(randomNumber == 0)
closeIv.goneIf(randomNumber != 0)
if (isXapk) {
closeTv.text = "暂不,尝试解压"
closeIv.visibility = View.VISIBLE
}
closeTv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), "文案样式_点击以后再说")
if (isXapk) {
mCallBack?.invoke()
}
dismiss()
}
closeIv.setOnClickListener {
@ -54,12 +67,18 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
activateTv.setOnClickListener {
MtaHelper.onEvent(getEvent(), getKey(), if (randomNumber == 0) "文案样式_点击立即开启" else "图标样式_点击立即开启")
PermissionHelper.toInstallPermissionSetting(requireActivity())
if (isXapk) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, requireActivity().javaClass.name)
SPUtils.setString(Constants.SP_XAPK_URL, url)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISS_CODE) {
if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISSION_CODE) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
SPUtils.setString(Constants.SP_XAPK_URL, "")
mCallBack?.invoke()
dismiss()
}
@ -71,30 +90,43 @@ class InstallPermissionDialogFragment : BaseTrackableDialogFragment() {
companion object {
@JvmStatic
fun show(activity: AppCompatActivity, callBack: (() -> Unit)?) {
fun show(activity: AppCompatActivity, downloadEntity: DownloadEntity, callBack: (() -> Unit)?) {
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == downloadEntity.path.getExtension()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
callBack?.invoke()
return
}
if (!Config.isPermissionPopupSwitchOpen()) {
callBack?.invoke()
return
}
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls();
val haveInstallPermission = activity.packageManager.canRequestPackageInstalls()
if (haveInstallPermission) {
callBack?.invoke()
return
}
if (isXapk) {
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
callBack?.invoke()
return
}
} else {
val installVersions = Config.getSettings()?.permissionPopupAppliedVersions?.install
if (installVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
callBack?.invoke()
return
}
}
var installPermissionDialogFragment = activity.supportFragmentManager.findFragmentByTag(InstallPermissionDialogFragment::class.java.simpleName) as? InstallPermissionDialogFragment
if (installPermissionDialogFragment != null) {
installPermissionDialogFragment.mCallBack = callBack
installPermissionDialogFragment.isXapk = isXapk
installPermissionDialogFragment.url = downloadEntity.url
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(installPermissionDialogFragment)
transaction.commit()
} else {
installPermissionDialogFragment = InstallPermissionDialogFragment().apply {
mCallBack = callBack
this.mCallBack = callBack
this.isXapk = isXapk
this.url = downloadEntity.url
}
installPermissionDialogFragment.show(activity.supportFragmentManager, InstallPermissionDialogFragment::class.java.simpleName)
}

View File

@ -0,0 +1,296 @@
package com.gh.common.dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentPackageCheckBinding
import com.gh.gamecenter.databinding.PackageCheckItemBinding
import com.gh.gamecenter.entity.DetectionObjectEntity
import com.gh.gamecenter.entity.PackageDialogEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.dialog.BaseDialogFragment
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
/**
* 包名检测弹窗
*/
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
var packageDialogEntity: PackageDialogEntity? = null
var callBack: DialogUtils.ConfirmListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
}
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)
packageDialogEntity?.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, packageLink ->
val linkSpan = SpanBuilder(packageLink.text).click(0, packageLink.text.length, R.color.theme_font, true) {
val linkEntity = packageLink.transform()
DirectUtils.directToLinkPage(requireContext(), linkEntity, "包名检测弹窗", "")
}.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
}
else -> {
binding.cancelTv.text = "我知道了"
binding.noRemindAgainCb.visibility = View.VISIBLE
}
}
initListener(it)
}
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) {
SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true)
}
val isAllPackageInstalled = isAllPackageInstalled(entity)
if (isAllPackageInstalled) {
callBack?.onConfirm()
dismissAllowingStateLoss()
} else {
val packageLink = entity.links.find { it.buttonLink }
if (packageLink != null) {
val linkEntity = packageLink.transform()
DirectUtils.directToLinkPage(requireContext(), linkEntity, "包名检测弹窗", "")
}
}
}
binding.cancelTv.setOnClickListener {
if (entity.level != "HINT_SKIP") {
callBack?.onConfirm()
}
if (binding.noRemindAgainCb.isChecked) {
SPUtils.setBoolean(Constants.SP_PACKAGE_CHECK, true)
}
dismissAllowingStateLoss()
}
}
private fun checkPackage() {
var index = 0
mTotalWidth = (DisplayUtils.getScreenWidth() - 108f.dip2px()).toFloat()
mDisposable = rxTimer(1) {
val width = (mTotalWidth / mDuration) * it
val params = binding.progressView.layoutParams as RelativeLayout.LayoutParams
params.width = width.toInt()
binding.progressView.layoutParams = params
packageDialogEntity?.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.progressText.text = "检测完成"
binding.progressView.background = ContextCompat.getDrawable(requireContext(), R.drawable.package_check_complete_bg)
}
}
}
override fun onStart() {
super.onStart()
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
dialog?.setCanceledOnTouchOutside(true)
}
override fun onResume() {
super.onResume()
packageDialogEntity?.let {
if (isAllPackageInstalled(it)) {
callBack?.onConfirm()
dismissAllowingStateLoss()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
EventBus.getDefault().unregister(this)
if (mDisposable?.isDisposed == false) {
mDisposable?.dispose()
}
}
//安装、卸载事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if ("安装" == busFour.type || "卸载" == busFour.type) {
mAdapter?.notifyDataSetChanged()
}
}
class PackageCheckAdapter(val context: Context, val entities: ArrayList<DetectionObjectEntity>) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private var index = -1
fun notifyPackages() {
index++
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return PackageCheckViewHolder(PackageCheckItemBinding.bind(LayoutInflater.from(context).inflate(R.layout.package_check_item, parent, false)))
}
override fun getItemCount(): Int = entities.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is PackageCheckViewHolder) {
val entity = entities[position]
holder.binding.entity = entity
if (position <= index) {
var isAllInstalled = true
entity.packages.forEach {
val isInstalled = PackageUtils.isInstalled(context, it)
if (!isInstalled) {
isAllInstalled = false
return@forEach
}
}
if (isAllInstalled) {
holder.binding.statusTv.text = "已安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
} else {
holder.binding.statusTv.text = "未安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, R.color.text_FF4147))
}
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, packageDialogEntity: PackageDialogEntity?, callBack: DialogUtils.ConfirmListener) {
if (packageDialogEntity == null) {
callBack.onConfirm()
return
}
if (isAllPackageInstalled(packageDialogEntity)) {
callBack.onConfirm()
return
}
val isChoose = SPUtils.getBoolean(Constants.SP_PACKAGE_CHECK, false)
if (packageDialogEntity.level == "OPTIONAL_HINT" && isChoose) {
callBack.onConfirm()
return
}
var dialogFragment = activity.supportFragmentManager.findFragmentByTag(PackageCheckDialogFragment::class.java.simpleName) as? PackageCheckDialogFragment
if (dialogFragment == null) {
dialogFragment = PackageCheckDialogFragment()
dialogFragment.packageDialogEntity = packageDialogEntity
dialogFragment.callBack = callBack
dialogFragment.show(activity.supportFragmentManager, PackageCheckDialogFragment::class.java.simpleName)
} else {
dialogFragment.packageDialogEntity = packageDialogEntity
dialogFragment.callBack = callBack
val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction()
transaction.show(dialogFragment)
transaction.commit()
}
}
fun isAllPackageInstalled(packageDialogEntity: PackageDialogEntity): Boolean {
var isAllInstalled = true
packageDialogEntity.detectionObjects.forEach { obj ->
obj.packages.forEach {
val isInstalled = PackageUtils.isInstalled(HaloApp.getInstance(), it)
if (!isInstalled) {
isAllInstalled = false
return isAllInstalled
}
}
}
return isAllInstalled
}
}
}

View File

@ -2,23 +2,27 @@ package com.gh.common.dialog
import android.app.Dialog
import android.content.DialogInterface
import android.os.Build
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
import android.text.method.ScrollingMovementMethod
import android.text.style.ClickableSpan
import android.view.*
import android.webkit.WebSettings
import android.webkit.WebView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils.directToExternalBrowser
import com.gh.common.util.dip2px
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.R
class PrivacyDialogFragment : BaseDialogFragment() {
private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
// private val mLocalPrivacyHtml = "file:///android_asset/privacy_policies.html"
// private val mLocalRegulationHtml = "file:///android_asset/user_regulation.html"
var containerView: View? = null
var mCallBack: ((isSuccess: Boolean) -> Unit)? = null
@ -30,83 +34,80 @@ class PrivacyDialogFragment : BaseDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
// val mWebViewRegulation = containerView?.findViewById<WebView>(R.id.webView2)
//
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
// mWebViewRegulation?.isHorizontalScrollBarEnabled = false
mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
mWebViewRegulation?.isHorizontalScrollBarEnabled = false
val contentTv = containerView?.findViewById<TextView>(R.id.contentTv)
val descTv = containerView?.findViewById<TextView>(R.id.descTv)
contentTv?.movementMethod = ScrollingMovementMethod()
val mTitlePrivacyTv = containerView?.findViewById<TextView>(R.id.privacyTitleTv)
val mTitleRegulationTv = containerView?.findViewById<TextView>(R.id.userRegulationTitleTv)
val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
for (settings in settingsArrayList) {
settings?.javaScriptEnabled = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
// 避免提示网页有害信息不能访问
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings?.safeBrowsingEnabled = false
val skipText = SpannableStringBuilder("查看完整版的隐私政策和用户协议")
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
// 适配大于屏幕宽度的页面
settings?.useWideViewPort = true
settings?.loadWithOverviewMode = true
settings?.domStorageEnabled = true
// 自适应屏幕
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
override fun onClick(widget: View) {
directToExternalBrowser(context!!, context!!.getString(R.string.privacy_policy_url))
}
}
}, skipText.length - 9, skipText.length - 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
// if (NetworkUtils.isNetworkConnected(requireContext())) {
// mWebViewPrivacy?.loadUrl(requireContext().getString(R.string.privacy_policy_url))
// mWebViewRegulation?.loadUrl(requireContext().getString(R.string.user_regulation_url))
// } else {
mWebViewPrivacy?.loadUrl(mLocalPrivacyHtml)
mWebViewRegulation?.loadUrl(mLocalRegulationHtml)
// }
skipText.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(requireContext(), R.color.theme_font)
ds.isUnderlineText = false
}
// val client = object : WebViewClient() {
// override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
// super.onReceivedError(view, request, error)
// if (view == mWebViewPrivacy) {
// view?.loadUrl(mLocalPrivacyHtml)
// } else {
// view?.loadUrl(mLocalRegulationHtml)
// }
override fun onClick(widget: View) {
directToExternalBrowser(requireContext(), requireContext().getString(R.string.disclaimer_url))
}
}, skipText.length - 4, skipText.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
descTv?.movementMethod = CustomLinkMovementMethod()
descTv?.text = skipText
// val mWebViewPrivacy = containerView?.findViewById<WebView>(R.id.webView)
//
// mWebViewPrivacy?.isHorizontalScrollBarEnabled = false
//
// val settingsArrayList = arrayListOf(mWebViewPrivacy?.settings, mWebViewRegulation?.settings)
//
// for (settings in settingsArrayList) {
// settings?.javaScriptEnabled = true
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
// }
// // 避免提示网页有害信息不能访问
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// settings?.safeBrowsingEnabled = false
// }
//
// // 适配大于屏幕宽度的页面
// settings?.useWideViewPort = true
// settings?.loadWithOverviewMode = true
// settings?.domStorageEnabled = true
//
// // 自适应屏幕
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// settings?.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
// }
// }
// mWebViewPrivacy?.webViewClient = client
// mWebViewRegulation?.webViewClient = client
mTitlePrivacyTv?.setOnClickListener {
mTitlePrivacyTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
mTitleRegulationTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
mWebViewPrivacy?.visibility = View.VISIBLE
mWebViewRegulation?.visibility = View.GONE
}
mTitleRegulationTv?.setOnClickListener {
mTitlePrivacyTv?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_F5F5F5))
mTitleRegulationTv.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
mWebViewPrivacy?.visibility = View.GONE
mWebViewRegulation?.visibility = View.VISIBLE
}
containerView?.findViewById<View>(R.id.refuseTv)?.setOnClickListener {
mCallBack?.invoke(false)
dismiss()
dismissAllowingStateLoss()
}
containerView?.findViewById<View>(R.id.agreeTv)?.setOnClickListener {
mCallBack?.invoke(true)
dismiss()
dismissAllowingStateLoss()
}
}

View File

@ -24,6 +24,7 @@ object MetaUtil {
private var m: Meta? = null
private var imei: String? = null
private var base64EncodedImei: String? = null
private var androidId: String? = null
fun refreshMeta() {
@ -104,6 +105,20 @@ object MetaUtil {
}
@JvmStatic
fun getBase64EncodedIMEI(): String {
if (TextUtils.isEmpty(base64EncodedImei) && imei != null) {
try {
base64EncodedImei = android.util.Base64.encodeToString(getIMEI().trim().toByteArray(), android.util.Base64.NO_WRAP)
} catch (e: java.lang.Exception) {
e.printStackTrace()
return ""
}
}
return base64EncodedImei ?: ""
}
fun getModel(): String? {
return Build.MODEL
}

View File

@ -4,6 +4,7 @@ import com.gh.common.runOnIoThread
import com.gh.common.util.clearHtmlFormatCompletely
import com.gh.common.util.removeInsertedContent
import com.gh.common.util.removeVideoContent
import com.gh.common.util.tryCatchInRelease
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
import com.gh.gamecenter.qa.entity.AnswerEntity
@ -14,27 +15,28 @@ object HistoryHelper {
fun insertAnswerEntity(answerDetailEntity: AnswerDetailEntity) {
val answerEntity = convertAnswerDetailToAnswer(answerDetailEntity)
runOnIoThread { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) }
// 偶尔有设备会出现磁盘满了写不进数据库的问题 database or disk is full 异常,毕竟只是插入个本地历史,这里直接捕抓
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.answerDao().addAnswer(answerEntity) } }
}
fun insertArticleEntity(articleDetailEntity: ArticleDetailEntity) {
val articleEntity = convertArticleDetailToArticle(articleDetailEntity)
runOnIoThread { HistoryDatabase.instance.articleDao().addArticle(articleEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.articleDao().addArticle(articleEntity) } }
}
@JvmStatic
fun insertGameEntity(gameEntity: GameEntity) {
val historyGameEntity = convertGameEntityToHistoryGameEntity(gameEntity)
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
}
@JvmStatic
fun insertGameEntity(updateEntity: GameUpdateEntity) {
val historyGameEntity = convertGameUpdateEntityToHistoryGameEntity(updateEntity)
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
}
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity{
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity {
val historyGame = HistoryGameEntity()
historyGame.orderTag = System.currentTimeMillis()

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.database.ContentObserver
import android.media.AudioManager
import android.os.Handler
import com.gh.common.util.tryCatchInRelease
class VolumeObserver(var context: Context, handler: Handler, var callback: MuteCallback? = null)
: ContentObserver(handler) {
@ -11,7 +12,8 @@ class VolumeObserver(var context: Context, handler: Handler, var callback: MuteC
init {
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
// 部分设备的 audioManager getStreamVolume 内部会触发空指针 :(
tryCatchInRelease { previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC) }
}
override fun onChange(selfChange: Boolean) {

View File

@ -2,6 +2,7 @@ package com.gh.common.simulator
import android.app.Dialog
import android.content.Context
import android.view.Gravity
import android.view.View
import android.view.Window
import android.widget.ProgressBar
@ -116,8 +117,8 @@ class SimulatorDownloadManager private constructor() {
key = if (shouldShowUpdate && isInstalled) "更新弹窗" else "下载弹窗",
logShowEvent = true
)
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, {
if (shouldShowUpdate && isInstalled){
DialogUtils.showNewAlertDialog(context, title, message, negativeText, positiveText, trackableEntity, Gravity.LEFT, {
if (shouldShowUpdate && isInstalled) {
cancelCallback?.invoke()
MtaHelper.onEvent(trackableEntity.event, trackableEntity.key, "点击下次再说")
}

View File

@ -33,6 +33,7 @@ object CommentHelper {
showConversation: Boolean,
articleId: String,
communityId: String,
isShowTop: Boolean = false,
ignoreModerator: Boolean = false,
listener: OnCommentOptionClickListener?) {
showCommentOptions(view = view,
@ -40,6 +41,7 @@ object CommentHelper {
showConversation = showConversation,
articleId = articleId,
communityId = communityId,
isShowTop = isShowTop,
ignoreModerator = ignoreModerator,
listener = listener)
}
@ -79,11 +81,16 @@ object CommentHelper {
communityId: String? = null,
answerId: String? = null,
videoId: String? = null,
isShowTop: Boolean = false,
ignoreModerator: Boolean = false,
isVideoAuthor: Boolean = false,
listener: OnCommentOptionClickListener? = null) {
val context = view.context
val dialogOptions = ArrayList<String>()
if (isShowTop && articleId != null && commentEntity.me?.isArticleOrAnswerAuthor == true) {
dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶")
}
dialogOptions.add("复制")
if (commentEntity.user.id != UserManager.getInstance().userId) {
dialogOptions.add("投诉")

View File

@ -2,7 +2,6 @@ package com.gh.common.util;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;
@ -12,6 +11,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.CommentDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
@ -39,8 +41,6 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
@ -529,10 +529,7 @@ public class CommentUtils {
//复制文字
public static void copyText(String copyContent, Context context) {
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
ToastUtils.INSTANCE.showToast("复制成功");
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
}

View File

@ -3,21 +3,34 @@ package com.gh.common.util;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gid.GidCallback;
import com.gh.gid.GidHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import com.tencent.stat.MtaSDkException;
import com.tencent.stat.StatConfig;
import com.tencent.stat.StatCrashReporter;
import com.tencent.stat.StatReportStrategy;
import com.tencent.stat.StatService;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import io.sentry.android.core.SentryAndroid;
import io.sentry.core.Sentry;
import io.sentry.core.protocol.User;
/**
* Created by LGT on 2016/6/15.
* 数据收集 工具类 TalkingData、MTA
@ -35,6 +48,35 @@ public class DataUtils {
if (CommonDebug.IS_DEBUG) {
return;
}
SentryAndroid.init(context, options -> {
options.setDebug(BuildConfig.DEBUG);
options.setEnableSessionTracking(true);
options.setEnvironment(BuildConfig.FLAVOR);
options.setDsn("https://6b1caf0d17c1408e8680f3f73ff80bd0@sentry.ghzs.com/22");
options.setBeforeSend((event, hint) -> {
if (BuildConfig.DEBUG) {
return null;
} else {
return event;
}
});
});
Sentry.configureScope(scope -> {
User user = new User();
user.setId(HaloApp.getInstance().getGid());
scope.setUser(user);
if (BuildConfig.BUILD_TIME != 0L) {
scope.setTag("alias", "内测版" + BuildConfig.VERSION_NAME + "_" + BuildConfig.BUILD_TIME);
} else {
scope.setTag("alias", "正式版" + BuildConfig.VERSION_NAME);
scope.setTag("channel", channel);
}
});
//TalkingData
// try {
// TCAgent.LOG_ON = false;
@ -49,42 +91,42 @@ public class DataUtils {
// }
//MTA
// try {
// /**
// *
// * 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理
// */
// StatConfig.setAutoExceptionCaught(false);
//
// StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context);
// crashReporter.setJavaCrashHandlerStatus(false);
//// crashReporter.setEnableInstantReporting(true);
//
// StatConfig.setDebugEnable(false);
//
// // 设置数据上报策略
// // 测试渠道的时候即时上传,方便查看日志
// if (Config.DEFAULT_CHANNEL.equals(HaloApp.getInstance().getChannel())) {
// StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT);
// } else {
// StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
// StatConfig.setSendPeriodMinutes(5);
// }
//
// // 设置启用Tlink
// StatConfig.setTLinkStatus(true);
//
// StatConfig.init(context);
// StatConfig.setInstallChannel(channel);
// StatConfig.setAntoActivityLifecycleStat(true);
// StatConfig.setAppVersion(PackageUtils.getVersionName());
//
// // 开启收集服务
// StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
// StatService.registerActivityLifecycleCallbacks(context);
// } catch (MtaSDkException e) {
// e.printStackTrace();
// }
try {
/**
*
* 不要启用!!!!全部由{@link com.gh.base.AppUncaughtHandler}处理
*/
StatConfig.setAutoExceptionCaught(false);
StatCrashReporter crashReporter = StatCrashReporter.getStatCrashReporter(context);
crashReporter.setJavaCrashHandlerStatus(false);
// crashReporter.setEnableInstantReporting(true);
StatConfig.setDebugEnable(false);
// 设置数据上报策略
// 测试渠道的时候即时上传,方便查看日志
if (Config.DEFAULT_CHANNEL.equals(HaloApp.getInstance().getChannel())) {
StatConfig.setStatSendStrategy(StatReportStrategy.INSTANT);
} else {
StatConfig.setStatSendStrategy(StatReportStrategy.PERIOD);
StatConfig.setSendPeriodMinutes(5);
}
// 设置启用Tlink
StatConfig.setTLinkStatus(true);
StatConfig.init(context);
StatConfig.setInstallChannel(channel);
StatConfig.setAntoActivityLifecycleStat(true);
StatConfig.setAppVersion(PackageUtils.getVersionName());
// 开启收集服务
StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
StatService.registerActivityLifecycleCallbacks(context);
} catch (MtaSDkException e) {
e.printStackTrace();
}
// init bugly
// try {
@ -141,15 +183,15 @@ public class DataUtils {
public static void onEvent(Context var0, String var1, String var2) {
Properties prop = new Properties();
prop.setProperty(var1, var2);
// StatService.trackCustomKVEvent(var0, var1, prop);
StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void onPause(Activity var0) {
// StatService.onPause(var0);
StatService.onPause(var0);
}
public static void onResume(Activity var0) {
// StatService.onResume(var0);
StatService.onResume(var0);
}
// 游戏启动
@ -166,7 +208,7 @@ public class DataUtils {
for (String key : var3.keySet()) {
prop.setProperty(key, var3.get(key) + "");
}
// StatService.trackCustomKVEvent(var0, var1, prop);
StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void trackTimeEvent(Context context, String eventId, int costTime, String... kv) {
@ -184,41 +226,41 @@ public class DataUtils {
if (prop.size() == 0) return;
// StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
}
// 游戏下载
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
// Map<String, Object> kv = new HashMap<>();
//
// platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
//
// kv.put("版本", platform);
// kv.put("用户机型", Build.MODEL);
// kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
// kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
// kv.put("光环助手版本", BuildConfig.VERSION_NAME);
// kv.put("位置", entrance);
// kv.put("类型", method);
// kv.put("厂商", Build.MANUFACTURER);
// kv.put("Android版本", Build.VERSION.RELEASE);
// onEvent(context, "游戏下载", gameName, kv);
//
// Map<String, Object> kv2 = new HashMap<>();
// kv2.put("状态", status);
// kv2.put("位置", entrance);
//
// if (status.equals("开始")) {
// kv2.put("版本", entrance + "-开始");
// kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
// } else {
// kv2.put("版本", platform);
// kv2.put("游戏分平台", gameName + "-" + platform);
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
// }
//
// onEvent(context, "游戏下载位置", gameName, kv2);
Map<String, Object> kv = new HashMap<>();
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
kv.put("版本", platform);
kv.put("用户机型", Build.MODEL);
kv.put("设备IMEI", MetaUtil.getIMEI());
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
kv.put("位置", entrance);
kv.put("类型", method);
kv.put("厂商", Build.MANUFACTURER);
kv.put("Android版本", Build.VERSION.RELEASE);
onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("状态", status);
kv2.put("位置", entrance);
if (status.equals("开始")) {
kv2.put("版本", entrance + "-开始");
kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
} else {
kv2.put("版本", platform);
kv2.put("游戏分平台", gameName + "-" + platform);
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
}
onEvent(context, "游戏下载位置", gameName, kv2);
}
// 游戏更新

View File

@ -350,7 +350,7 @@ public class DialogUtils {
* @param cmListener 确认按钮监听
*/
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, TrackableEntity trackableEntity, final CancelListener clListener, final ConfirmListener cmListener) {
, String negative, String positive, TrackableEntity trackableEntity, int gravity, final CancelListener clListener, final ConfirmListener cmListener) {
context = checkDialogContext(context);
final Dialog dialog;
if (trackableEntity != null) {
@ -373,6 +373,8 @@ public class DialogUtils {
TextView cancelBtn = contentView.findViewById(R.id.cancel);
TextView confirmBtn = contentView.findViewById(R.id.confirm);
View middleLine = contentView.findViewById(R.id.middle_line);
titleTv.setGravity(gravity);
contentTv.setGravity(gravity);
titleTv.setText(title);
contentTv.setText(message);
@ -411,7 +413,7 @@ public class DialogUtils {
public static Dialog showNewAlertDialog(Context context, String title, CharSequence message
, String negative, String positive, final CancelListener clListener, final ConfirmListener cmListener) {
return showNewAlertDialog(context, title, message, negative, positive, null, clListener, cmListener);
return showNewAlertDialog(context, title, message, negative, positive, null, Gravity.LEFT, clListener, cmListener);
}
/**
@ -986,13 +988,13 @@ public class DialogUtils {
WindowManager.LayoutParams params = window.getAttributes();
params.horizontalMargin = 0;
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
int maxHeight = DisplayUtils.dip2px(446);
if (height > maxHeight) {
params.height = maxHeight;
} else {
params.height = height;
}
// int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
// int maxHeight = DisplayUtils.dip2px(446);
// if (height > maxHeight) {
// params.height = maxHeight;
// } else {
// params.height = height;
// }
window.setAttributes(params);
}
@ -1025,8 +1027,6 @@ public class DialogUtils {
hierarchy.setPlaceholderImage(R.drawable.permission_storage);
} else if (position == 1) {
hierarchy.setPlaceholderImage(R.drawable.permission_phone_state);
} else {
hierarchy.setPlaceholderImage(R.drawable.permission_sdk);
}
}
}

View File

@ -22,6 +22,7 @@ import com.gh.common.exposure.ExposureType
import com.gh.common.util.EntranceUtils.*
import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.catalog.CatalogActivity
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
import com.gh.gamecenter.entity.*
@ -57,7 +58,6 @@ import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.gh.gamecenter.video.game.GameVideoActivity
import com.gh.gamecenter.video.videomanager.VideoManagerActivity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_ClipboardManager
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@ -133,7 +133,9 @@ object DirectUtils {
"server",
"top_game_comment",
"wechat_bind",
"video")
"video",
"catalog"
)
fun directToLinkPage(context: Context,
linkEntity: LinkEntity,
@ -200,6 +202,8 @@ object DirectUtils {
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"block", "版块" -> {
if (linkEntity.link.isNullOrEmpty()) return
directToBlock(context,
@ -575,7 +579,7 @@ object DirectUtils {
@JvmStatic
fun directToExternalBrowser(context: Context, url: String) {
if (url.isEmpty()) return
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Uri.decode(url)))
if (context !is AppCompatActivity) {
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
@ -606,8 +610,7 @@ object DirectUtils {
context.startActivity(intent)
} else {
// 没有安装QQ 复制账号
Util_System_ClipboardManager.setText(context, qq)
Utils.toast(context, "已复制 QQ $qq")
qq?.copyTextAndToast("已复制 QQ $qq")
}
}
@ -889,6 +892,20 @@ object DirectUtils {
jumpActivity(context, bundle)
}
/**
* 跳转新分类
*/
@JvmStatic
fun directCatalog(context: Context, catalogId: String, catalogTitle: String, entrance: String? = null, path: String? = "") {
if (catalogId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CatalogActivity::class.java.name)
bundle.putString(KEY_CATALOG_ID, catalogId)
bundle.putString(KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转到问题标签详情
*/

View File

@ -8,9 +8,16 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.PackageCheckDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
@ -39,12 +46,6 @@ import com.lightgame.utils.Utils;
import java.io.File;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
/**
* todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
*/
@ -419,7 +420,7 @@ public class DownloadItemUtils {
}
/**
* @param clickCallback 供那些需要知道点击回调的地方使用
* @param clickCallback 供那些需要知道点击回调的地方使用,触发具体响应才会回调
*/
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
@ -431,103 +432,13 @@ public class DownloadItemUtils {
final ExposureEvent traceEvent,
@Nullable final EmptyCallback clickCallback) {
if (gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
downloadBtn.setOnClickListener(v -> {
CheckLoginUtils.checkLogin(context, entrance, () -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
});
});
} else {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
if ("download".equals(gameEntity.getReserveStatus())) {
ReservationHelper.showDeleteReservationDialog(context, () -> {
ReservationHelper.deleteReservation(gameEntity, () -> {
adapter.notifyItemChanged(position);
});
});
} else {
ReservationHelper.showCancelReservationDialog(context, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
adapter.notifyItemChanged(position);
});
});
}
});
}
return;
}
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
LinkEntity linkEntity = gameEntity.getH5Link();
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay, linkEntity.getCloseButton());
context.startActivity(i);
});
} else if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(v -> {
EmptyCallback clickRunnable = () -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent);
};
// 启动不需要请求存储权限
if (downloadBtn.getText().toString().equals(context.getString(R.string.launch))) {
clickRunnable.onCallback();
} else {
PermissionHelper.checkStoragePermissionBeforeAction(context, clickRunnable);
}
});
} else {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
}
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location);
});
});
});
});
}
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, clickCallback, null);
}
/**
* @param clickCallback 供那些需要知道点击回调的地方使用,只要触发点击事件就响应回调(未登录状态下点击预约也要响应回调
* @param allStateClickCallback 供那些需要知道点击回调的地方使用,只要触发点击动作就会回调
*/
public static void setOnClickListenerWithInvokeCallbackForAllState(final Context context,
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
final int position,
@ -535,29 +446,36 @@ public class DownloadItemUtils {
final String entrance,
final String location,
final ExposureEvent traceEvent,
@Nullable final EmptyCallback clickCallback) {
@Nullable final EmptyCallback clickCallback,
@Nullable final EmptyCallback allStateClickCallback) {
if (gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
CheckLoginUtils.checkLogin(context, entrance, () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
if (clickCallback != null) {
clickCallback.onCallback();
}
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
gameEntity,
() -> {
LogUtils.logReservation(gameEntity, traceEvent);
adapter.notifyItemChanged(position);
}
);
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
});
});
} else {
downloadBtn.setOnClickListener(v -> {
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
if (clickCallback != null) {
clickCallback.onCallback();
}
@ -581,9 +499,10 @@ public class DownloadItemUtils {
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
if (clickCallback != null) {
clickCallback.onCallback();
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
LinkEntity linkEntity = gameEntity.getH5Link();
@ -599,6 +518,10 @@ public class DownloadItemUtils {
} else if (gameEntity.getApk().size() == 1) {
downloadBtn.setOnClickListener(v -> {
EmptyCallback clickRunnable = () -> {
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
if (clickCallback != null) {
clickCallback.onCallback();
}
@ -614,6 +537,10 @@ public class DownloadItemUtils {
});
} else {
downloadBtn.setOnClickListener(v -> {
if (allStateClickCallback != null) {
allStateClickCallback.onCallback();
}
if (clickCallback != null) {
clickCallback.onCallback();
}
@ -656,24 +583,27 @@ public class DownloadItemUtils {
if (str.equals(context.getString(R.string.download))) {
// 先弹下载弹窗(如果需要的话)
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
});
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
} else if (str.equals(context.getString(R.string.attempt))) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
PackageCheckDialogFragment.show((AppCompatActivity) context, gameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
});
@ -700,7 +630,7 @@ public class DownloadItemUtils {
boolean isInstalled = PackageUtils.isInstalledFromAllPackage(context, gameEntity.getSimulator().getApk().getPackageName());
if (downloadEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity) && !isInstalled) {
SimulatorDownloadManager.getInstance().showDownloadDialog(context, gameEntity.getSimulator(),
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(),null);
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.getId(), gameEntity.getName(), null);
return;
}
}

View File

@ -175,15 +175,15 @@ object DownloadObserver {
}
// 下载过程分析统计
val pm = mApplication.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
if (packageInfo == null) {
// val pm = mApplication.packageManager
// val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
// if (packageInfo == null) {
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
// "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
//
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
// "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
}
// }
}
if (downloadEntity.status == DownloadStatus.done) {

View File

@ -215,6 +215,12 @@ public class EntranceUtils {
public static final String KEY_BBS_ID = "bbs_id";
public static final String KEY_DIAGNOSIS = "diagnosis";
public static final String KEY_SIMULATOR = "simulator";
public static final String KEY_MARKET_DETAILS = "market_details";
public static final String KEY_CATALOG_ID = "catalogId";
public static final String KEY_PRIMARY_CATALOG_ID = "primaryCatalogId";
public static final String KEY_PRIMARY_CATALOG_NAME = "primaryCatalogName";
public static final String KEY_CATALOG_TITLE = "catalog_title";
public static final String KEY_CATALOG_INIT_TITLE = "catalog_init_title";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -1,6 +1,7 @@
package com.gh.common.util
import android.animation.Animator
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.drawable.GradientDrawable
@ -43,8 +44,11 @@ import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import io.reactivex.SingleTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import java.net.URI
@ -124,6 +128,20 @@ fun ViewPager.addOnScrollStateChanged(onStateChanged: ((state: Int) -> Unit)? =
addOnPageChangeListener(listener)
}
/**
* Fragment related
*/
inline fun <reified T : Fragment> Fragment.fragmentFromActivity() =
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
/**
* RecyclerView Extensions
*/
@ -329,6 +347,15 @@ fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) {
}
}
/**
* 在自动打包的包里弹 toast
*/
fun toastInInternalRelease(content: String) {
if (BuildConfig.BUILD_TIME != 0L) {
Utils.toast(HaloApp.getInstance(), content)
}
}
/**
* 主动抛出异常
*/
@ -388,11 +415,25 @@ fun String.getFirstElementDividedByDivider(divider: String): String {
return this
}
fun String.copyText() {
this.copyTextAndToast("")
}
fun String.copyTextAndToast(toastText: String = "复制成功") {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cmb.text = this
ToastUtils.showToast(toastText)
try {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(null, this)
cmb.primaryClip = clip
if (!TextUtils.isEmpty(toastText)) {
ToastUtils.showToast(toastText)
}
} catch (e: SecurityException) {
// 在一些情况下会报以下这样的错误,可能是以浮动窗口显示然后没有焦点?(https://developer.android.com/about/versions/10/privacy/changes#clipboard-data)
// java.lang.Throwable: java.lang.SecurityException: com.xunmeng.pinduoduo from uid 10317 not allowed to perform READ_CLIPBOARD
ToastUtils.showToast("复制失败,请重试")
}
}
fun Map<String, String>.createRequestBody(): RequestBody {
@ -436,6 +477,7 @@ fun Float.sp2px(): Int {
return (this * scale + 0.5f).toInt()
}
/**
* PopupWindow 自动适配方向
* 弹出与锚点右对齐
@ -559,6 +601,19 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
})
}
/**
* ArrayList related
*/
fun <T> ArrayList<T>.safelyGetInRelease(index: Int): T? {
return if (index >= size) {
throwExceptionInDebug("这里触发了数组越界,请检查")
toastInInternalRelease("这个操作可能触发闪退,请确定复现方式并联系开发处理")
null
} else {
this[index]
}
}
/**
* 拦截 TextView 中的 Url Span用应用内页面的形式打开链接
* @param shrankText 未展开时的文字
@ -849,4 +904,18 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)?
onStopTrackingTouch?.invoke()
}
})
}
fun <T> observableToMain(): ObservableTransformer<T, T> {
return ObservableTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
fun <T> singleToMain(): SingleTransformer<T, T> {
return SingleTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}

View File

@ -1,55 +0,0 @@
package com.gh.common.util
import android.app.Application
/**
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
*
* 更换帐号 [https://gitlab.ghzs.com/pm/yunying/issues/893]
*/
object GdtHelper {
const val NETWORK_TYPE = "NETWORK_TYPE"
const val PAGE_TYPE = "PAGE_TYPE"
const val CONTENT_TYPE = "CONTENT_TYPE"
const val CONTENT_ID = "CONTENT_ID"
const val KEYWORD = "KEYWORD"
const val GAME_ID = "GAME_ID"
const val SCORE = "SCORE"
const val PLATFORM = "PLATFORM"
fun init(application: Application, channel: String) {
// if (channel == "GH_728") {
// GDTAction.init(application, "1111012969", "9d3d9da5b0948a317c03d08f14d445dc")
// } else if (channel == "GH_729") {
// GDTAction.init(application, "1111013063", "f53dabf458a356b101d99fc4069eb7f1")
// } else {
// GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
// }
}
fun logAction(type: String) {
// GDTAction.logAction(type)
// Utils.log("GDT", type)
}
fun logAction(type: String, vararg kv: String?) {
// try {
// val actionParam = JSONObject()
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// actionParam.put(key, value)
// }
// }
// }
// Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
// GDTAction.logAction(type, actionParam)
// } catch (e: Exception) {
// e.printStackTrace()
// }
}
}

View File

@ -15,7 +15,7 @@ object HomePluggableHelper {
if (apkList.isNotEmpty()) {
val apk = apkList.first()
val tag = if (isNever) "never" else apk.version ?: ""
mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever))
tryCatchInRelease { mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever)) }
}
}
@ -44,7 +44,7 @@ object HomePluggableHelper {
for (entity in filterList) {
entity.active = true
}
mHomePluggableFilterDao.addData(filterList)
tryCatchInRelease { mHomePluggableFilterDao.addData(filterList) }
}
}
}

View File

@ -67,4 +67,15 @@ public class HtmlUtils {
return htmlStr.trim(); //返回文本字符串
}
/**
* 过滤掉标签,保留标签内容
*/
public static String filterHtmlLabel(String htmlStr) {
String regEx_html = "<[^>]+>([\\s\\S]*?)<\\/[^>]+>"; //定义HTML标签的正则表达式
Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
Matcher m_html = p_html.matcher(htmlStr);
htmlStr = m_html.replaceAll("$1"); //过滤html标签
return htmlStr.trim(); //返回文本字符串
}
}

View File

@ -279,68 +279,74 @@ object ImageUtils {
})
}
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
display(view, url, true)
}
/**
* 规则 width>0 Wifi/4G:x2 traffic:x1
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
* @param isAutoPlayGif 是否禁止播放动图
*/
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
url?.let {
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
fun display(view: SimpleDraweeView?, url: String?, isAutoPlayGif: Boolean = true) {
if (url == null) return
var lowResUrl = ""
var highResUrl = ""
val width = view?.layoutParams?.width
val height = view?.layoutParams?.height
// 找同一图片地址已加载过的图片作为低质量预览图
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
for (cachedImageUrl in mImageUrlCacheSet) {
if (cachedImageUrl.contains(url)) {
lowResUrl = cachedImageUrl
break
}
var lowResUrl = ""
var highResUrl = ""
// 找同一图片地址已加载过的图片作为低质量预览图
// TODO 根据实际请求大小(w_width)来避免小图用大图作为低质量图片
for (cachedImageUrl in mImageUrlCacheSet) {
if (url.isNotEmpty() && cachedImageUrl.contains(url)) {
lowResUrl = cachedImageUrl
break
}
}
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
view?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(hUrl))
.apply {
if (lUrl.isNotEmpty()
&& lUrl != hUrl
&& hUrl != view?.getTag(R.string.highResImageTag)) {
lowResImageRequest = ImageRequest.fromUri(lUrl)
}
autoPlayAnimations = autoPlay
val loadImageClosure: (autoPlay: Boolean, highResUrl: String, lowResUrl: String) -> Unit = { autoPlay, hUrl, lUrl ->
view?.controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(hUrl))
.apply {
if (lUrl.isNotEmpty()
&& lUrl != hUrl
&& hUrl != view?.getTag(R.string.highResImageTag)) {
lowResImageRequest = ImageRequest.fromUri(lUrl)
}
.build()
autoPlayAnimations = autoPlay
}
.build()
view?.setTag(R.string.highResImageTag, highResUrl)
view?.setTag(R.string.highResImageTag, highResUrl)
}
val shouldLoadAsGif = url.endsWith(".gif") && isAutoPlayGif && view?.getTag(R.id.tag_show_gif) != false
if (shouldLoadAsGif && view?.tag == url) return
if (width != null && width > 0) {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, width, height ?: 0)
} else {
getTransformLimitUrl(url, width, view.context) ?: ""
}
val shouldLoadAsGif = it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false
if (shouldLoadAsGif && view?.tag == url) return
if (width != null && width > 0) {
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, width, height ?: 0)
resizeGif(url, view.width, height ?: 0)
} else {
getTransformLimitUrl(url, width, view.context) ?: ""
getTransformLimitUrl(url, view.width, view.context) ?: ""
}
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
} else {
view?.post {
highResUrl = if (shouldLoadAsGif) {
resizeGif(url, view.width, height ?: 0)
} else {
getTransformLimitUrl(url, view.width, view.context) ?: ""
}
loadImageClosure(shouldLoadAsGif, highResUrl, lowResUrl)
}
}
view?.tag = url
}
view?.tag = url
}
// Wifi/4G:x2 traffic:x1

View File

@ -48,7 +48,7 @@ public class InstallUtils {
public void handleMessage(Message msg) {
if (msg.what == INSTALL_WHAT && packageManager != null) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
List<PackageInfo> packageInfos = PackageUtils.getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);

View File

@ -1,7 +1,6 @@
package com.gh.common.util;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Color;
@ -11,6 +10,8 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
@ -36,7 +37,6 @@ import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import androidx.core.content.ContextCompat;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -237,85 +237,160 @@ public class LibaoUtils {
// 领取限制
CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(context, () -> {
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform());
}
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform());
}
boolean isExistPlatform = false;
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
for (ApkEntity apkEntity : apk) {
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
isExistPlatform = true;
break;
}
boolean isExistPlatform = false;
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
for (ApkEntity apkEntity : apk) {
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
isExistPlatform = true;
break;
}
}
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
boolean finalIsExistPlatform = isExistPlatform;
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
isExistPlatform ? "立即安装" : "关闭",
() -> {
if (finalIsExistPlatform) {
adapter.openDownload(libaoEntity.getPlatform());
}
}, null);
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
boolean finalIsExistPlatform = isExistPlatform;
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
isExistPlatform ? "立即安装" : "关闭",
() -> {
if (finalIsExistPlatform) {
adapter.openDownload(libaoEntity.getPlatform());
}
}, null);
return;
}
}
switch (btnStatus) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
}
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucceed(Object response) {
switch (btnStatus) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
}
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucceed(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
try {
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
if (TextUtils.isEmpty(libaoCode)) {
try {
libaoCode = responseBody.getString("code");
String detail = responseBody.getString("detail");
switch (detail) {
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
if (TextUtils.isEmpty(libaoCode)) {
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
String detail = responseBody.getString("detail");
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
@ -323,101 +398,24 @@ public class LibaoUtils {
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
Utils.toast(context, "操作失败");
break;
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
}
Utils.toast(context, "发生异常");
}
});
break;
}
});
Utils.toast(context, "发生异常");
}
});
break;
}
});
});
}
@ -458,7 +456,7 @@ public class LibaoUtils {
adapter.notifyDataSetChanged();
final String finalLibaoCode = libaoCode;
NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> {
if (!isShow){
if (!isShow) {
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode))
, "关闭", " 复制礼包码"
, () -> {
@ -547,8 +545,7 @@ public class LibaoUtils {
}
public static boolean isAppInstalled(Context context, String packageName) {
final android.content.pm.PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
@ -576,10 +573,7 @@ public class LibaoUtils {
//复制文字
public static void copyLink(String copyContent, Context context) {
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
Utils.toast(context, copyContent + " 复制成功");
ExtensionsKt.copyTextAndToast(copyContent, copyContent + " 复制成功");
}

View File

@ -33,6 +33,7 @@ import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
@ -637,4 +638,49 @@ public class LogUtils {
}
LoghubUtils.log(object, "event", false);
}
public static void logNewCatalogAppearanceEvent(String entrance, String key) {
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
}
public static void logSubCatalogClickEvent(String entrance, String key, int seq1) {
logCatalogEvent("click_first_classification", entrance, key, seq1, -1, -1, -1);
}
public static void logSubCatalogContentClickEvent(String entrance, String key, int seq1, int seq2) {
logCatalogEvent("click_secondary_classification", entrance, key, seq1, seq2, -1, -1);
}
public static void logSpecialCatalogContentClickEvent(String entrance, String key, int seq1, int seqContent) {
logCatalogEvent("click_content", entrance, key, seq1, -1, seqContent, -1);
}
public static void logSpecialCatalogSpecificContentClickEvent(String entrance, String key, int seq1, int seqContent, int seqContentList) {
logCatalogEvent("click_content_list", entrance, key, seq1, -1, seqContent, seqContentList);
}
private static void logCatalogEvent(String event, String entrance, String key, int seq1, int seq2, int seqContent, int seqContentList) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
try {
object.put("event", event);
object.put("meta", getMetaObject());
object.put("timestamp", System.currentTimeMillis() / 1000);
payload.put("entrance", entrance); //入口分类, 分为 首页或版块,
payload.put("key", key); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
payload.put("seq_1st", seq1); //从0开始,默认-1表示没有
payload.put("seq_2nd", seq2); //从0开始,默认-1表示没有
payload.put("seq_content", seqContent); //精选页上 图片、专题-全部按钮、专题合集-全部按钮 的排序;从0开始,默认-1表示没有
payload.put("seq_content_list", seqContentList);
object.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
}

View File

@ -1,52 +1,61 @@
package com.gh.common.util
import android.os.Build
import android.text.TextUtils
import com.gh.common.exposure.meta.MetaUtil
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.tencent.stat.StatService
import java.util.*
object MtaHelper {
@JvmStatic
fun onEvent(eventId: String, vararg kv: String?) {
// val prop = Properties()
//
// if (kv.size == 1) {
// prop.setProperty(kv[0], kv[0])
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// return
// }
//
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value)
// }
// }
// }
//
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
val prop = Properties()
if (kv.size == 1) {
prop.setProperty(kv[0], kv[0])
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
return
}
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
@JvmStatic
fun onEventWithTime(eventId: String, time: Int, vararg kv: String?) {
// val prop = Properties()
// for (i in kv.indices) {
// if (i % 2 != 0 || i != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value)
// }
// }
// }
//
// if (prop.size == 0 && kv.size == 1) {
// prop.setProperty(kv[0], kv[0])
// }
//
// if (prop.size == 0) return
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
// StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
val prop = Properties()
for (i in kv.indices) {
if (i % 2 != 0 || i != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
if (prop.size == 0 && kv.size == 1) {
prop.setProperty(kv[0], kv[0])
}
if (prop.size == 0) return
Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
}
/**
@ -54,29 +63,29 @@ object MtaHelper {
*/
@JvmStatic
fun onEventWithBasicDeviceInfo(eventId: String, vararg kv: String) {
// val prop = Properties()
// for (i in kv.indices) {
// if (i % 2 != 0) {
// val key = kv[i - 1]
// val value = kv[i]
// if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
// prop.setProperty(key, value)
// }
// }
// }
//
// prop.setProperty("光环版本", BuildConfig.VERSION_NAME)
// prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
// prop.setProperty("IMEI", MetaUtil.getIMEI())
// prop.setProperty("机型", Build.MODEL)
// prop.setProperty("厂商", Build.MANUFACTURER)
// prop.setProperty("Android版本", Build.VERSION.RELEASE)
// if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) {
// prop.setProperty("GID", HaloApp.getInstance().gid)
// }
//
// Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
// StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
val prop = Properties()
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
prop.setProperty("光环版本", BuildConfig.VERSION_NAME)
prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
prop.setProperty("IMEI", MetaUtil.getIMEI())
prop.setProperty("机型", Build.MODEL)
prop.setProperty("厂商", Build.MANUFACTURER)
prop.setProperty("Android版本", Build.VERSION.RELEASE)
if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) {
prop.setProperty("GID", HaloApp.getInstance().gid)
}
Utils.log("MTA", "$eventId + [${kv.joinToString(" , ")}]")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
}

View File

@ -63,7 +63,7 @@ object PackageHelper {
private fun getAllPackageName(context: Context): HashSet<String> {
val set = HashSet<String>()
return try {
val packageInfos = context.applicationContext.packageManager.getInstalledPackages(0)
val packageInfos = PackageUtils.getInstalledPackages(context, 0)
for (packageInfo in packageInfos) {
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
if (context.packageName != packageInfo.packageName) {

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
@ -38,13 +39,14 @@ object PackageInstaller {
*/
@JvmStatic
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity) {
val pkgPath = downloadEntity.path
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()
InstallPermissionDialogFragment.show(AppManager.getInstance().currentActivity() as AppCompatActivity, downloadEntity) {
// 取消状态栏下载完成的通知,若存在
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
val pkgPath = downloadEntity.path
if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) {
if (isXapk) {
XapkInstaller.install(context, downloadEntity, showUnzipToast)
} else {
install(context, downloadEntity.path)
@ -113,6 +115,9 @@ object PackageInstaller {
val uninstallIntent = Intent()
uninstallIntent.action = Intent.ACTION_DELETE
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
if (context !is Activity) {
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val packageName = PackageUtils.getPackageNameByPath(context, path)
uninstallIntent.data = Uri.parse("package:$packageName")
InstallUtils.getInstance(context).addUninstall(packageName)

View File

@ -30,8 +30,11 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@ -286,7 +289,7 @@ public class PackageUtils {
*/
public static String getPackageNameByPath(Context context, String path) {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
PackageInfo info = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
@ -370,7 +373,7 @@ public class PackageUtils {
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = context.getApplicationContext().getPackageManager().getInstalledPackages(0);
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
@ -385,7 +388,7 @@ public class PackageUtils {
JSONArray jsonArray = new JSONArray();
try {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
JSONObject jsonObject = new JSONObject();
@ -557,4 +560,42 @@ public class PackageUtils {
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-to-get-a-list-of-applications-installed/30062632#30062632
*/
public static List<PackageInfo> getInstalledPackages(Context context, int flags) {
final PackageManager pm = context.getPackageManager();
try {
return pm.getInstalledPackages(flags);
} catch (Exception ignored) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
Process process;
List<PackageInfo> result = new ArrayList<>();
BufferedReader bufferedReader = null;
try {
process = Runtime.getRuntime().exec("pm list packages");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
final String packageName = line.substring(line.indexOf(':') + 1);
final PackageInfo packageInfo = pm.getPackageInfo(packageName, flags);
result.add(packageInfo);
}
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedReader != null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}

View File

@ -13,7 +13,7 @@ import com.tbruyelle.rxpermissions2.RxPermissions
object PermissionHelper {
const val INSTALL_PERMISS_CODE = 100
const val INSTALL_PERMISSION_CODE = 100
@JvmStatic
fun requestReadPhoneStateAndStoragePermissionFromStartUp(context: Context) {
@ -232,7 +232,7 @@ object PermissionHelper {
} else {
val packageURI = Uri.fromParts("package", activity.packageName, null)
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
activity.startActivityForResult(intent, INSTALL_PERMISS_CODE)
activity.startActivityForResult(intent, INSTALL_PERMISSION_CODE)
}
}

View File

@ -0,0 +1,47 @@
package com.gh.common.util
import android.text.TextUtils
import com.lightgame.utils.Utils
import io.sentry.core.Sentry
import io.sentry.core.SentryEvent
import io.sentry.core.SentryLevel
import io.sentry.core.protocol.Message
object SentryHelper {
/**
* 注意 tag-key 不支持中文
*/
fun onEvent(eventId: String, vararg kv: String?) {
val sentryEvent = SentryEvent()
val message = Message()
message.message = eventId
sentryEvent.message = message
sentryEvent.level = SentryLevel.LOG
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
sentryEvent.setTag(key, value)
debugOnly {
throwExceptionInDebug("tag-key 不支持中文", isContainChinese(key))
}
}
}
}
Utils.log("Sentry", "$eventId + [${kv.joinToString(" , ")}]")
Sentry.captureEvent(sentryEvent)
}
// 判断一个字符串是否含有中文
private fun isContainChinese(str: String?): Boolean {
if (str == null) return false
for (c in str.toCharArray()) {
if (c.toInt() in 0x4E00..0x9FA5) return true
}
return false
}
}

View File

@ -1,11 +1,9 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -24,6 +22,9 @@ import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WeiBoShareActivity;
@ -50,9 +51,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
/**
@ -159,8 +157,7 @@ public class ShareUtils {
//检查是否安装手机QQ
public static boolean isQQClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
List<PackageInfo> pinfo = PackageUtils.getInstalledPackages(context, 0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
@ -634,13 +631,11 @@ public class ShareUtils {
private void copyLink(String copyContent) {
shareType = "copy_link";
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
ClipboardManager cmb = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
if (mShareEntrance != ShareEntrance.shareGh) {
Utils.toast(mContext, "复制成功");
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
safelyDismiss();
} else {
Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享");
ExtensionsKt.copyTextAndToast(copyContent, "复制成功,请到微信/QQ粘贴分享");
}
}

View File

@ -13,7 +13,7 @@ import androidx.core.content.ContextCompat
import com.gh.common.view.CenterImageSpan
import com.halo.assistant.HaloApp
class SpanBuilder(content: String) {
class SpanBuilder(content: CharSequence) {
private var spannableString: SpannableStringBuilder = SpannableStringBuilder(content)
fun color(context: Context, start: Int, end: Int, colorRes: Int): SpanBuilder {
@ -70,12 +70,12 @@ class SpanBuilder(content: String) {
return this
}
fun click(start: Int, end: Int, colorRes: Int, onClick: () -> Unit): SpanBuilder {
fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder {
val clickSpan = object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, colorRes)
ds.isUnderlineText = false
ds.isUnderlineText = isUnderlineText
}
override fun onClick(widget: View) {

View File

@ -1,32 +0,0 @@
package com.gh.common.util
import android.content.Context
/**
* 今日头条的激活统计 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/567
*
* 更新 SDK https://gitlab.ghzs.com/pm/halo-app-issues/issues/743
*/
object TeaHelper {
@JvmStatic
fun init(context: Context, channel: String) {
// val config = InitConfig("163824", channel)
// config.setUriConfig(UriConfig.DEFAULT)
// config.appName = "guanghuan1"
// config.setEnablePlay(true)
// AppLog.setEnableLog(false)
// AppLog.init(context, config)
//
// AppLog.setOaidObserver {
// HaloApp.getInstance().oaid = it.id
// Utils.log("oaid is $it.id")
// MetaUtil.refreshMeta()
// }
//
// // gameReportHelper ?!
// GameReportHelper.onEventRegister("wechat", true)
// GameReportHelper.onEventPurchase("gift", "flower", "008", 1, "wechat", "¥", true, 1)
}
}

View File

@ -3,7 +3,6 @@ package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.*
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
@ -14,7 +13,6 @@ import com.gh.common.util.ImageUtils
import com.gh.common.util.rxTimer
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SettingsEntity
import com.squareup.picasso.Picasso
import io.reactivex.disposables.Disposable
import kotlin.math.abs

View File

@ -0,0 +1,301 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.gh.common.util.toColor
import com.gh.common.util.visibleIf
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.google.android.flexbox.FlexboxLayout
class CatalogFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) {
private var mTypeTv: TextView
private var mCatalogTv: TextView
private var mSizeTv: TextView
private var mTypeContainer: View
private var mCatalogContainer: View
private var mSizeContainer: View
private var mTypeFilterArray = ArrayList<SortType>()
private var mCatalogFilterArray = ArrayList<CatalogEntity.SubCatalogEntity>()
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
private var mOnCatalogFilterSetupListener: OnCatalogFilterSetupListener? = null
init {
View.inflate(context, R.layout.layout_catalog_filter, this)
mTypeTv = findViewById(R.id.type_tv)
mCatalogTv = findViewById(R.id.catalog_tv)
mSizeTv = findViewById(R.id.size_tv)
mTypeContainer = findViewById(R.id.container_type)
mCatalogContainer = findViewById(R.id.container_catalog)
mSizeContainer = findViewById(R.id.container_size)
mTypeContainer.setOnClickListener {
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
}
mCatalogContainer.setOnClickListener {
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
}
mSizeContainer.setOnClickListener {
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
}
fun setTypeList(switch: CatalogEntity.CatalogSwitch) {
switch.run {
if ("on" == hotSort) mTypeFilterArray.add(SortType.RECOMMENDED)
if ("on" == newSort) mTypeFilterArray.add(SortType.NEWEST)
if ("on" == starSort) mTypeFilterArray.add(SortType.RATING)
}
if (mTypeFilterArray.isNotEmpty()) mTypeTv.text = mTypeFilterArray[0].value
}
fun setCatalogList(subCatalogList: List<CatalogEntity.SubCatalogEntity>, initCatalogName: String) {
mCatalogFilterArray = ArrayList(subCatalogList)
mCatalogTv.text = initCatalogName
}
fun setOnConfigSetupListener(onCatalogFilterSetupListener: OnCatalogFilterSetupListener) {
mOnCatalogFilterSetupListener = onCatalogFilterSetupListener
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
targetTextView.background = null
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
}
}
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
val drawableUp = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(typeTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
typeTv.setTextColor(R.color.theme_font.toColor())
typeTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(typeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (type in mTypeFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = typeTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = type.value
toggleHighlightedTextView(tv, typeText == type.value)
tv.tag = type.value
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
typeTv.text = type.value
mOnCatalogFilterSetupListener?.onSetupSortType(type)
}
}
popupWindow.setOnDismissListener {
typeTv.setTextColor(R.color.text_757575.toColor())
typeTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) {
val drawableUp = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(catalogTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
catalogTv.setTextColor(R.color.theme_font.toColor())
catalogTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(catalogTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (entity in mCatalogFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = catalogTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
val iv = item.findViewById<ImageView>(R.id.recommend_iv)
tv.text = entity.name
iv.visibleIf(entity.recommended)
toggleHighlightedTextView(tv, catalogText == entity.name)
tv.tag = entity.name
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
catalogTv.text = entity.name
mOnCatalogFilterSetupListener?.onSetupSortCatalog(entity)
}
}
popupWindow.setOnDismissListener {
catalogTv.setTextColor(R.color.text_757575.toColor())
catalogTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
val drawableUp = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_up)
val drawableDown = ContextCompat.getDrawable(sizeTv.context, R.drawable.ic_filter_arrow_down)
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setCompoundDrawables(null, null, drawableUp, null)
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
sizeFilterArray = if (sizeFilterArray == null) {
getDefaultSizeFilterArray()
} else {
sizeFilterArray?.apply {
if (firstOrNull()?.text != "全部大小") {
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
}
}
}
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (size in sizeFilterArray!!) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = sizeTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = size.text
toggleHighlightedTextView(tv, sizeText == size.text)
tv.tag = size.text
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
sizeTv.text = size.text
mOnCatalogFilterSetupListener?.onSetupSortSize(size)
}
}
popupWindow.setOnDismissListener {
sizeTv.setTextColor(R.color.text_757575.toColor())
sizeTv.setCompoundDrawables(null, null, drawableDown, null)
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
}
}
interface OnCatalogFilterSetupListener {
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
fun onSetupSortType(sortType: SortType)
fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity)
}
enum class SortType(val value: String) {
RECOMMENDED("热门推荐"),
NEWEST("最新上线"),
RATING("最高评分")
}
}

View File

@ -12,7 +12,7 @@ import android.widget.PopupWindow
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.gh.common.util.DisplayUtils
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.google.android.flexbox.FlexboxLayout
@ -69,16 +69,13 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
mOnConfigFilterSetupListener = onConfigFilterSetupListener
}
fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.text_blue_background)
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
val colorDrawable = GradientDrawable()
colorDrawable.setColor(Color.WHITE)
colorDrawable.cornerRadius = DisplayUtils.dip2px(1.5f).toFloat()
targetTextView.background = colorDrawable
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_3a3a3a))
targetTextView.background = null
targetTextView.setTextColor(ContextCompat.getColor(targetTextView.context, R.color.text_757575))
}
}
@ -88,8 +85,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
drawableUp?.setBounds(0, 0, drawableUp.minimumWidth, drawableUp.minimumHeight)
drawableDown?.setBounds(0, 0, drawableDown.minimumWidth, drawableDown.minimumHeight)
sizeTv.setTextColor(R.color.theme_font.toColor())
sizeTv.setCompoundDrawables(null, null, drawableUp, null)
sizeTv.text = "收起"
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
@ -146,25 +143,24 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
}
popupWindow.setOnDismissListener {
sizeTv.setTextColor(R.color.text_757575.toColor())
sizeTv.setCompoundDrawables(null, null, drawableDown, null)
if (sizeTv.text == "收起") {
sizeTv.text = sizeText
}
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
add(SubjectSettingEntity.Size(min = -1, max = 20, text = "20M以下"))
add(SubjectSettingEntity.Size(min = 20, max = 50, text = "20-50M"))
add(SubjectSettingEntity.Size(min = 50, max = 100, text = "50-100M"))
add(SubjectSettingEntity.Size(min = 100, max = 500, text = "100-500M"))
add(SubjectSettingEntity.Size(min = 500, max = -1, text = "500M以上"))
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
}
}

View File

@ -5,6 +5,7 @@ import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.DisplayUtils
@ -18,6 +19,7 @@ class GameIconView : ConstraintLayout {
private var mCornerRadius = 10
private var mBorderColor = 0
private var mGameIconOverlayColor = 0
private var mBorderWidth = 1
private var mFadeDuration = -1
@ -36,11 +38,15 @@ class GameIconView : ConstraintLayout {
val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView)
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F))
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
mGameIconOverlayColor = ta.getColor(R.styleable.GameIconView_gameIconOverlayColor, 0)
mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1)
mFadeDuration = ta.getInt(R.styleable.GameIconView_gameIconFadeDuration, -1)
ta.recycle()
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
if (mGameIconOverlayColor != 0) {
roundingParams.overlayColor = mGameIconOverlayColor
}
if (mBorderColor != 0) {
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())

View File

@ -32,7 +32,7 @@ class ReserveDialog : BaseDialogFragment() {
binding.more.setOnClickListener {
val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2)
startActivity(intent)
dismiss()
dismissAllowingStateLoss()
}
binding.recyclerView.layoutManager = if (mReserveList.size > 4) {
GridLayoutManager(context, 4)
@ -54,7 +54,7 @@ class ReserveDialog : BaseDialogFragment() {
holder.binding.game = entity
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(预约弹窗)")
dismiss()
dismissAllowingStateLoss()
}
}
}

View File

@ -0,0 +1,70 @@
package com.gh.common.view
import android.text.Selection
import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.URLSpan
import android.view.MotionEvent
import android.view.ViewGroup
import android.view.ViewParent
import android.widget.TextView
import com.gh.common.DefaultUrlHandler
/**
* 拦截处理以 "ghzhushou://" 起始的 URLSpan
*/
class UrlInterceptedLinkMovementMethod : LinkMovementMethod() {
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
val action = event.action
var isTouchEventConsumed = false
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
var x = event.x.toInt()
var y = event.y.toInt()
x -= widget.totalPaddingLeft
y -= widget.totalPaddingTop
x += widget.scrollX
y += widget.scrollY
val layout = widget.layout
val line = layout.getLineForVertical(y)
val off = layout.getOffsetForHorizontal(line, x.toFloat())
val links = buffer.getSpans(off, off, ClickableSpan::class.java)
if (links.size != 0) {
val link = links[0]
if (action == MotionEvent.ACTION_UP) {
if (link is URLSpan && link.url.contains("ghzhushou")) {
DefaultUrlHandler.interceptUrl(widget.context, link.url, "")
} else {
link.onClick(widget)
}
} else if (action == MotionEvent.ACTION_DOWN) {
// do nothing
}
isTouchEventConsumed = true
} else {
Selection.removeSelection(buffer)
}
}
//解决点击事件冲突问题
if (!isTouchEventConsumed && event.action == MotionEvent.ACTION_UP) {
val parent: ViewParent? = iterateViewParentForClicking(widget.parent) //处理widget的父控件点击事件
if (parent is ViewGroup) {
return parent.performClick()
}
}
return false
}
private fun iterateViewParentForClicking(parent: ViewParent): ViewParent? {
return if (parent is ViewGroup) {
if (parent.hasOnClickListeners()) {
parent
} else {
iterateViewParentForClicking(parent.getParent())
}
} else null
}
}

View File

@ -86,7 +86,7 @@ class WelcomeDialog : BaseDialogFragment() {
mDismissByClickImage = true
dismiss()
dismissAllowingStateLoss()
}
binding.ivOpeningCover.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
@ -102,15 +102,24 @@ class WelcomeDialog : BaseDialogFragment() {
}
binding.ivCloseBackup.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
}
binding.ivClose.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
}
binding.welcome = mWelcomeEntity
return binding.root
}
override fun dismissAllowingStateLoss() {
try {
mDismissByClickImage = false
super.dismissAllowingStateLoss()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun dismiss() {
try {
mDismissByClickImage = false

View File

@ -1,12 +1,9 @@
package com.gh.common.xapk
import android.content.Context
import android.os.Build
import com.gh.common.AppExecutor
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.download.DataChanger
import com.lightgame.download.DownloadEntity
@ -124,14 +121,9 @@ object XapkInstaller : IXapkUnzipListener {
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
}
MtaHelper.onEvent("解压失败"
, "安卓版本", Build.VERSION.RELEASE
, "IMEI", MetaUtil.getIMEI()
, "光环版本", BuildConfig.VERSION_NAME
, "厂商", Build.MANUFACTURER
, "机型", Build.MODEL
, "游戏", downloadEntity.name
, "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
SentryHelper.onEvent("XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage)
debugOnly {
Utils.log("unzip", "onFailure->$exception")
@ -142,7 +134,14 @@ object XapkInstaller : IXapkUnzipListener {
mXapkUnzipThreadMap.remove(downloadEntity.path)
AppExecutor.uiExecutor.execute {
val pkgPath = checkNotNull(downloadEntity.meta[XAPK_PACKAGE_PATH_TAG])
val pkgPath = downloadEntity.meta[XAPK_PACKAGE_PATH_TAG]
if (pkgPath == null) {
Utils.toast(mContext, "下载出错,请重新下载!")
return@execute
}
PackageInstaller.install(mContext, pkgPath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"

View File

@ -56,7 +56,7 @@ object DownloadDataHelper {
return "下载完成"
}
val pm = HaloApp.getInstance().application.applicationContext.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0)
if (packageInfo == null && XapkInstaller.PACKAGE_EXTENSION_NAME == downloadEntity.path.getExtension()) {
"解析包错误"
} else {

View File

@ -150,6 +150,8 @@ public class DownloadManager implements DownloadStatusListener {
// 只有下载模块需要这坨东西,因此移动到这里初始化
ConnectionUtils.initHttpsUrlConnection(context);
updateMetaMap();
// DownloadNotification.showDownloadingNotification(mContext);
lastTimeMap = new ArrayMap<>();
@ -292,8 +294,6 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setUpdate(true);
}
updateMetaMap();
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
@ -340,6 +340,8 @@ public class DownloadManager implements DownloadStatusListener {
* @param downloadEntity
*/
public void add(DownloadEntity downloadEntity) {
updateMetaMap();
if (downloadEntity != null) {
String url = downloadEntity.getUrl();
checkDownloadEntryRecordValidate(url);
@ -397,6 +399,8 @@ public class DownloadManager implements DownloadStatusListener {
* @param downloadEntity
*/
public void subscribe(DownloadEntity downloadEntity) {
updateMetaMap();
if (downloadEntity != null) {
String url = downloadEntity.getUrl();
checkDownloadEntryRecordValidate(url);
@ -992,7 +996,7 @@ public class DownloadManager implements DownloadStatusListener {
map.put(HttpDnsManager.GID, HaloApp.getInstance().getGid());
map.put(HttpDnsManager.OAID, HaloApp.getInstance().getOAID());
map.put(HttpDnsManager.USER_ID, UserManager.getInstance().getUserId());
map.put(HttpDnsManager.IMEI, MetaUtil.INSTANCE.getIMEI());
map.put(HttpDnsManager.IMEI, MetaUtil.getBase64EncodedIMEI());
HttpDnsManager.metaMap = map;
}

View File

@ -0,0 +1,201 @@
package com.gh.download
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.content.Context
import android.preference.PreferenceManager
import android.text.TextUtils
import com.gh.common.constant.Constants
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.*
import com.gh.gamecenter.entity.GameDigestEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.retrofit.EmptyResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.SettingsFragment
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import org.json.JSONException
import org.json.JSONObject
import java.util.*
object PackageObserver {
private val mPackageViewModel: PackageViewModel
by lazy { PackageViewModel(HaloApp.getInstance().application, PackageRepository) }
@JvmStatic
fun onPackageChanged(busFour: EBPackage) {
val application = HaloApp.getInstance().application
val packageName = busFour.packageName
val versionName = busFour.versionName
var gameId = ""
var mDownloadEntity: DownloadEntity? = null
val sp = PreferenceManager.getDefaultSharedPreferences(application)
for (downloadEntity in DownloadManager.getInstance(application).allDownloadEntity) {
if (packageName == downloadEntity.packageName) {
mDownloadEntity = downloadEntity
gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
if (TextUtils.isEmpty(busFour.versionName)) {
// 没有版本号的事件直接选用第一个找到的 downloadEntity
break
} else {
// 有版本号的事件直接尽量找到版本一致的 downloadEntity
if (versionName == downloadEntity.versionName) {
break
}
}
}
}
if ("安装" == busFour.type) {
mPackageViewModel.addInstalledGame(packageName)
// TODO 这个取消通知栏看起来没什么用,没在其它地方看到它,暂且保留一个版本
// 删除下载完成 弹窗
val nManager = application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.cancel(packageName.hashCode())
if (mDownloadEntity != null) {
if (mDownloadEntity.isPluggable) {
val kv6: MutableMap<String, Any> = HashMap()
kv6["安装或卸载"] = "安装完成"
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "安装完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
}
// 没有光环 ID 的都记录一下游戏 ID供'我的游戏'区分同包名不同插件用
val gh_id = PackageUtils.getMetaData(application, mDownloadEntity.packageName, "gh_id")
if (gh_id == null) {
ThirdPartyPackageHelper.saveGameId(mDownloadEntity.packageName, mDownloadEntity.gameId)
}
DownloadManager.getInstance(application).cancel(
mDownloadEntity.url, false, true) // 默认不删除安装包 mSp.getBoolean("autodelete", true)
}
if (sp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
// 安装后关注游戏
val finalDownloadEntity = mDownloadEntity
RetrofitManager.getInstance(application).sensitiveApi
.getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<GameDigestEntity?>?>() {
override fun onResponse(response: List<GameDigestEntity?>?) {
for (gameDigestEntity in response!!) {
if (!TextUtils.isEmpty(gameDigestEntity?.id)) { // 关注游戏
if (finalDownloadEntity != null && gameDigestEntity?.id == finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)) {
ConcernUtils.postConcernGameId(application, gameDigestEntity?.id ?: "", null, false)
}
}
}
}
})
}
postNewlyInstalledApp(gameId, packageName)
}
if ("卸载" == busFour.type) {
mPackageViewModel.addUninstalledGame(packageName)
if (mDownloadEntity != null && mDownloadEntity.isPluggable) {
val kv6: MutableMap<String, Any> = HashMap()
kv6["安装或卸载"] = "卸载完成"
DataUtils.onEvent(application, "插件化", mDownloadEntity.name, kv6)
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "卸载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
PackageInstaller.install(application, mDownloadEntity)
}
// 更新已安装游戏
deleteInstalledPackage(packageName)
}
DataCollectionUtils.uploadInorunstall(application, busFour.type, busFour.packageName)
}
@SuppressLint("CheckResult")
private fun postNewlyInstalledApp(gameId: String, packageName: String) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList()
// 更新已安装游戏
val packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName)
val dataObject = JSONObject()
val wrapperObject = JSONObject()
try {
dataObject.put("type", "POST")
dataObject.put("device_id", HaloApp.getInstance().gid)
dataObject.put("app", packageObject)
dataObject.put("time", Utils.getTime(HaloApp.getInstance().application))
wrapperObject.put("content", dataObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true)
val requestBody = RequestBody.create(MediaType.parse("application/json"),
packageObject.toString())
// 更新已安装游戏
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.postNewlyInstalledApp(HaloApp.getInstance().gid, requestBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(EmptyResponse())
if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn) {
val jsonObject = JSONObject()
try {
jsonObject.put("game_id", gameId)
jsonObject.put("package", packageName)
val rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.postPlayedGame(UserManager.getInstance().userId, rBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(EmptyResponse())
} catch (e: JSONException) {
e.printStackTrace()
}
}
}
@SuppressLint("CheckResult")
private fun deleteInstalledPackage(packageName: String) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList()
// 删除已安装游戏
val dataObject = JSONObject()
val wrapperObject = JSONObject()
try {
dataObject.put("type", "DELETE")
dataObject.put("device_id", HaloApp.getInstance().gid)
dataObject.put("package", packageName)
dataObject.put("time", Utils.getTime(HaloApp.getInstance().application))
wrapperObject.put("content", dataObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true)
}
}

View File

@ -140,7 +140,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
}
})
mViewModel.dismissLiveData.observe(this, Observer {
dismiss()
dismissAllowingStateLoss()
})
mElapsedHelper = TimeElapsedHelper()
@ -173,7 +173,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
postBrowseMta()
mViewModel.collectionLiveData.postValue(null)
} else {
dismiss()
dismissAllowingStateLoss()
}
}
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
@ -332,7 +332,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
MotionEvent.ACTION_UP,
MotionEvent.ACTION_OUTSIDE -> {
if (mBinding.root.y >= mBinding.root.height / 2) {
dismiss()
dismissAllowingStateLoss()
} else {
resetDialogPosition(300)
}

View File

@ -2,11 +2,13 @@ package com.gh.download.dialog
import android.content.Context
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.gh.base.BaseActivity
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.dialog.CertificationDialog
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.dialog.PackageCheckDialogFragment
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToLinkPage
@ -24,6 +26,7 @@ import com.lightgame.download.DownloadStatus
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import io.sentry.core.protocol.App
class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
@ -278,19 +281,21 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
if (msg.isNullOrEmpty()) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
override fun onCallback() {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
PackageCheckDialogFragment.show(context as AppCompatActivity, gameEntity.packageDialog, DialogUtils.ConfirmListener {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
})
}
})

View File

@ -28,7 +28,7 @@ class DownloadLinkDialog : BaseDialogFragment() {
mLinkEntity.content, "text/html", "utf-8", null)
binding.confirm.setOnClickListener {
dismiss()
dismissAllowingStateLoss()
}
return binding.root
}

View File

@ -19,6 +19,7 @@ import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.lifecycle.ViewModelProviders;
import com.gh.base.AppUncaughtHandler;
@ -71,6 +72,7 @@ import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.eventbus.EBSkip;
import com.gh.gamecenter.fragment.MainWrapperFragment;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.manager.UpdateManager;
import com.gh.gamecenter.manager.UserManager;
@ -78,12 +80,14 @@ import com.gh.gamecenter.normal.NormalFragment;
import com.gh.gamecenter.packagehelper.PackageRepository;
import com.gh.gamecenter.packagehelper.PackageViewModel;
import com.gh.gamecenter.qa.CommunityFragment;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.EmptyResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.suggest.SuggestSelectFragment;
import com.gh.gamecenter.suggest.SuggestType;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.halo.assistant.HaloApp;
import com.halo.assistant.fragment.SettingsFragment;
@ -96,6 +100,7 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
@ -125,9 +130,11 @@ import static com.gh.common.util.EntranceUtils.HOST_QQ;
import static com.gh.common.util.EntranceUtils.HOST_QQ_GROUP;
import static com.gh.common.util.EntranceUtils.HOST_WEB;
import static com.gh.common.util.EntranceUtils.KEY_DATA;
import static com.gh.common.util.EntranceUtils.KEY_MARKET_DETAILS;
import static com.gh.common.util.EntranceUtils.KEY_NEXT_TO;
import static com.gh.common.util.EntranceUtils.KEY_TO;
import static com.gh.common.util.EntranceUtils.KEY_TYPE;
import static com.gh.common.util.ExtensionsKt.singleToMain;
import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL;
import static com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG;
import static com.gh.gamecenter.personal.PersonalFragment.LOGOUT_TAG;
@ -399,6 +406,9 @@ public class MainActivity extends BaseActivity {
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
}
break;
case KEY_MARKET_DETAILS:
redirectGameDetail(bundle.getString(KEY_DATA));
break;
}
}
}
@ -412,6 +422,28 @@ public class MainActivity extends BaseActivity {
}, 500);
}
/**
* 应用跳转
* @param packageName
*/
@SuppressLint("CheckResult")
private void redirectGameDetail(String packageName) {
RetrofitManager.getInstance(this).getApi().redirectGameDetail(packageName)
.compose(singleToMain())
.subscribe(new BiResponse<JsonObject>() {
@Override
public void onSuccess(JsonObject data) {
String gameId = data.get("game_id").getAsString();
DirectUtils.directToGameDetail(MainActivity.this, gameId, GameDetailFragment.INDEX_DESC, "应用跳转");
}
@Override
public void onFailure(@NotNull Exception exception) {
super.onFailure(exception);
}
});
}
private void checkNotificationPermission() {
// 仅登录后再启动光环时请求一次权限
if (UserManager.getInstance().isLoggedIn()) {
@ -713,184 +745,6 @@ public class MainActivity extends BaseActivity {
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBPackage busFour) {
final String packageName = busFour.getPackageName();
final String versionName = busFour.getVersionName();
String gameId = "";
DownloadEntity mDownloadEntity = null;
for (DownloadEntity downloadEntity : DownloadManager.getInstance(getApplicationContext()).getAllDownloadEntity()) {
if (packageName.equals(downloadEntity.getPackageName())) {
mDownloadEntity = downloadEntity;
gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER);
if (TextUtils.isEmpty(busFour.getVersionName())) {
// 没有版本号的事件直接选用第一个找到的 downloadEntity
break;
} else {
// 有版本号的事件直接尽量找到版本一致的 downloadEntity
if (versionName.equals(downloadEntity.getVersionName())) {
break;
}
}
}
}
if ("安装".equals(busFour.getType())) {
mPackageViewModel.addInstalledGame(packageName);
// 删除下载完成 弹窗
NotificationManager nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nManager.cancel(packageName.hashCode());
if (mDownloadEntity != null) {
if (mDownloadEntity.isPluggable()) {
Map<String, Object> kv6 = new HashMap<>();
kv6.put("安装或卸载", "安装完成");
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "安装完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
}
// 没有光环 ID 的都记录一下游戏 ID供'我的游戏'区分同包名不同插件用
Object gh_id = PackageUtils.getMetaData(this, mDownloadEntity.getPackageName(), "gh_id");
if (gh_id == null) {
ThirdPartyPackageHelper.saveGameId(mDownloadEntity.getPackageName(), mDownloadEntity.getGameId());
}
DownloadManager.getInstance(getApplicationContext()).cancel(
mDownloadEntity.getUrl(), false, true); // 默认不删除安装包 mSp.getBoolean("autodelete", true)
}
if (mSp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
// 安装后关注游戏
DownloadEntity finalDownloadEntity = mDownloadEntity;
RetrofitManager.getInstance(this).getSensitiveApi().getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<GameDigestEntity>>() {
@Override
public void onResponse(List<GameDigestEntity> response) {
for (GameDigestEntity gameDigestEntity : response) {
if (!TextUtils.isEmpty(gameDigestEntity.getId())) { // 关注游戏
if (finalDownloadEntity != null && gameDigestEntity.getId().equals(finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER))) {
ConcernUtils.INSTANCE.postConcernGameId(MainActivity.this, gameDigestEntity.getId(), null, false);
}
}
}
}
});
}
postNewlyInstalledApp(gameId, packageName);
}
if ("卸载".equals(busFour.getType())) {
mPackageViewModel.addUninstalledGame(packageName);
if (mDownloadEntity != null && mDownloadEntity.isPluggable()) {
Map<String, Object> kv6 = new HashMap<>();
kv6.put("安装或卸载", "卸载完成");
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "卸载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
PackageInstaller.install(this, mDownloadEntity);
}
// 更新已安装游戏
deleteInstalledPackage(packageName);
}
DataCollectionUtils.uploadInorunstall(this, busFour.getType(), busFour.getPackageName());
}
@SuppressWarnings("ResultOfMethodCallIgnored")
@SuppressLint("CheckResult")
private void postNewlyInstalledApp(String gameId, String packageName) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList();
// 更新已安装游戏
JSONObject packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName);
JSONObject dataObject = new JSONObject();
JSONObject wrapperObject = new JSONObject();
try {
dataObject.put("type", "POST");
dataObject.put("device_id", HaloApp.getInstance().getGid());
dataObject.put("app", packageObject);
dataObject.put("time", Utils.getTime(getApplicationContext()));
wrapperObject.put("content", dataObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"),
packageObject.toString());
// 更新已安装游戏
RetrofitManager.getInstance(MainActivity.this).getApi()
.postNewlyInstalledApp(HaloApp.getInstance().getGid(), requestBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn()) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("game_id", gameId);
jsonObject.put("package", packageName);
RequestBody rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString());
RetrofitManager.getInstance(MainActivity.this).getApi()
.postPlayedGame(UserManager.getInstance().getUserId(), rBody)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
@SuppressLint("CheckResult")
private void deleteInstalledPackage(String packageName) {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList();
// 删除已安装游戏
JSONObject dataObject = new JSONObject();
JSONObject wrapperObject = new JSONObject();
try {
dataObject.put("type", "DELETE");
dataObject.put("device_id", HaloApp.getInstance().getGid());
dataObject.put("package", packageName);
dataObject.put("time", Utils.getTime(getApplicationContext()));
wrapperObject.put("content", dataObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true);
// 删除已安装游戏
RetrofitManager.getInstance(MainActivity.this).getApi()
.deleteInstalledApp(HaloApp.getInstance().getGid(), packageName)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new EmptyResponse<>());
}
// 接收登录和登出更新事件统计的 Meta
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBReuse reuse) {

View File

@ -7,6 +7,7 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import com.gh.base.BaseActivity
@ -21,12 +22,15 @@ import com.lightgame.utils.Util_System_Keyboard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.subjects.PublishSubject
import kotlinx.android.synthetic.main.toolbar_search.*
import kotterknife.bindView
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeUnit
open class SearchActivity : BaseActivity() {
private val searchEt by bindView<EditText>(R.id.searchEt)
private var mDao: SearchHistoryDao? = null
protected var mSearchKey: String? = null
@ -53,6 +57,7 @@ open class SearchActivity : BaseActivity() {
super.onCreate(savedInstanceState)
val hint = intent.getStringExtra(EntranceUtils.KEY_HINT)
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)
var ignoreTextChanges = savedInstanceState != null
mDao = SearchHistoryDao(this)
mPublishSubject = PublishSubject.create()
@ -62,21 +67,27 @@ open class SearchActivity : BaseActivity() {
.distinctUntilChanged()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (searchEt.text.isNotEmpty()) {
if (searchEt.text.isNotEmpty()
&& searchEt.text != searchEt.hint
&& !ignoreTextChanges) {
search(SearchType.AUTO, it)
}
ignoreTextChanges = false
}
initSearchBar()
if (savedInstanceState != null) {
mDisplayType = DisplayType.fromInt(savedInstanceState.getInt(KEY_DISPLAY_TYPE, 0))
mSearchKey = savedInstanceState.getString(EntranceUtils.KEY_SEARCHKEY, null)
mSearchType = SearchType.fromString(savedInstanceState.getString(KEY_SEARCH_TYPE, null))
if (mDisplayType != DisplayType.DEFAULT && !TextUtils.isEmpty(mSearchKey)) {
search(mSearchType, mSearchKey)
}
} else if (!TextUtils.isEmpty(hint)) {
// 子 Fragment 自己恢复状态
// if (savedInstanceState != null) {
// mDisplayType = DisplayType.fromInt(savedInstanceState.getInt(KEY_DISPLAY_TYPE, 0))
// mSearchKey = savedInstanceState.getString(EntranceUtils.KEY_SEARCHKEY, null)
// mSearchType = SearchType.fromString(savedInstanceState.getString(KEY_SEARCH_TYPE, null))
// if (mDisplayType != DisplayType.DEFAULT && !TextUtils.isEmpty(mSearchKey)) {
// search(mSearchType, mSearchKey)
// }
// } else
if (!TextUtils.isEmpty(hint)) {
searchEt.hint = hint
if (searchImmediately) {
mDisplayType = GAME_DETAIL
@ -87,7 +98,8 @@ open class SearchActivity : BaseActivity() {
searchEt.hint = "搜索游戏..."
}
if (mDisplayType == DisplayType.DEFAULT) {
if (savedInstanceState == null
&& mDisplayType == DisplayType.DEFAULT) {
updateDisplayType(DisplayType.DEFAULT)
}
}
@ -233,7 +245,7 @@ open class SearchActivity : BaseActivity() {
}
companion object {
private const val KEY_SEARCH_TYPE = "search_type"
const val KEY_SEARCH_TYPE = "search_type"
private const val KEY_DISPLAY_TYPE = "display_type"
private const val KEY_SEARCH_IMMEDIATELY = "search_immediately"
@ -274,11 +286,13 @@ enum class SearchType(var value: String) {
* [DEFAULT] 默认搜索页
* [GAME_DIGEST] 游戏为部分文字样式的列表
* [GAME_DETAIL] 游戏全为标准样式的列表
* [FORUM_OR_USER] 论坛内容和用户
*/
enum class DisplayType(var value: Int) {
DEFAULT(0),
GAME_DIGEST(1),
GAME_DETAIL(2);
GAME_DETAIL(2),
FORUM_OR_USER(3);
companion object {
fun fromInt(typeInt: Int) = values().find { typeInt == it.value } ?: DEFAULT

View File

@ -1,6 +1,5 @@
package com.gh.gamecenter;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@ -10,15 +9,16 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.gh.base.ToolBarActivity;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.MessageShareUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.QRCodeUtils;
import com.gh.common.util.ShareUtils;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
import androidx.annotation.NonNull;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
@ -73,9 +73,6 @@ public class ShareGhActivity extends ToolBarActivity {
@OnClick(R.id.gh_address_tv)
public void copyAddress() {
MtaHelper.onEvent("我的光环_新", "分享光环", "复制官网");
ClipboardManager cmb = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(getString(R.string.gh_website_url_100));
Utils.toast(this, "网址复制成功,请到微信/QQ粘贴分享");
ExtensionsKt.copyTextAndToast(getString(R.string.gh_website_url_100), "网址复制成功,请到微信/QQ粘贴分享");
}
}

View File

@ -80,310 +80,325 @@ public class SkipActivity extends BaseActivity {
Uri uri = getIntent().getData();
Bundle bundle;
if (uri != null) {
if (CommonDebug.IS_DEBUG) {
Utils.log("SkipActivity:: Uri=>" + uri.toString());
}
String host = uri.getHost();
String path = uri.getPath();
if ("ghzhushou".equals(uri.getScheme())) {
if (CommonDebug.IS_DEBUG) {
Utils.log("SkipActivity:: Uri=>" + uri.toString());
}
String host = uri.getHost();
String path = uri.getPath();
String to = uri.getQueryParameter("to");
String type = uri.getQueryParameter("type");
String name = uri.getQueryParameter("name");
String referer = uri.getQueryParameter("referer");
String id = uri.getQueryParameter("id");
if (!TextUtils.isEmpty(path)) {
path = path.substring(1);
}
String to = uri.getQueryParameter("to");
String type = uri.getQueryParameter("type");
String name = uri.getQueryParameter("name");
String referer = uri.getQueryParameter("referer");
String id = uri.getQueryParameter("id");
if (!TextUtils.isEmpty(path)) {
path = path.substring(1);
}
if (host != null) {
Intent intent;
switch (host) {
case HOST_ARTICLE:
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
break;
case HOST_GAME:
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
break;
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID);
String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5);
String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ?
String.format("%s-%s-V%s",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION)) :
String.format("%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION), gameId, packageMd5);
String qaId = uri.getQueryParameter("qa_id");
String qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE);
if (!TextUtils.isEmpty(qaId)) {
DirectUtils.directToQa(this, qaTitle, qaId);
} else {
DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER);
}
break;
case HOST_DOWNLOAD:
DirectUtils.directToDownloadManagerAndStartUpdate(this, path, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER);
break;
case HOST_ANSWER:
DirectUtils.directToAnswerDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QUESTION:
DirectUtils.directToQuestionDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_TOOLBOX:
DirectUtils.directToToolbox(this, uri.getQueryParameter("gameId"), uri.getQueryParameter("toolboxUrl"), ENTRANCE_BROWSER);
break;
case HOST_COMMUNITY:
UserManager.getInstance().setCommunityData(new CommunityEntity(path, name));
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_COMMUNITY, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_COMMUNITY, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
// 社区文章格式一
case "community.article":
DirectUtils.directToCommunityArticle(this, uri.getQueryParameter("articleId"), uri.getQueryParameter("communityId"), ENTRANCE_BROWSER, "浏览器");
break;
// 社区文章格式二
case "communities":
String communityId = "";
String typeId = "";
String[] split = path.split("/");
for (String text : split) {
if (TextUtils.isEmpty(communityId)) {
communityId = text;
continue;
}
if (TextUtils.isEmpty(type)) {
type = text;
continue;
}
if (TextUtils.isEmpty(typeId)) {
typeId = text;
}
}
if ("articles".equals(type)) {
DirectUtils.directToCommunityArticle(this, typeId, communityId, ENTRANCE_BROWSER, "浏览器");
if (host != null) {
Intent intent;
switch (host) {
case HOST_ARTICLE:
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
break;
}
break;
case HOST_VIDEO:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.HOTTEST_GAME_VIDEO.getValue(),
false, id, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_UPLOAD_VIDEO://跳转上传视频
String titleParameter = uri.getQueryParameter("title");
String title = TextUtils.isEmpty(titleParameter) ? "" : "#" + titleParameter + "#";
String categoryId = uri.getQueryParameter("category_id");
String link = uri.getQueryParameter("link");
gameId = uri.getQueryParameter("gameId");
String gameName = uri.getQueryParameter("gameName");
String tagActivityId = uri.getQueryParameter("tagActivityId");
String tagActivityName = uri.getQueryParameter("tagActivityName");
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName);
SimpleGameEntity simpleGameEntity = new SimpleGameEntity(gameId != null ? gameId : "", gameName != null ? gameName : "", "");
Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "");
CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, () ->
DirectUtils.directToVideoManager(SkipActivity.this, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "浏览器"));
break;
case HOST_VIDEO_SINGLE:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(),
false, "", ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_VIDEO_MORE:
gameId = uri.getQueryParameter("gameId");
String act = uri.getQueryParameter("act");
String fieldId = uri.getQueryParameter("fieldId");
String sectionName = uri.getQueryParameter("sectionName");
String paginationType = uri.getQueryParameter("paginationType");//活动分页方式 page filter
String location;
if (!TextUtils.isEmpty(act)) {
location = VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.getValue();
} else if (!TextUtils.isEmpty(fieldId)) {
location = VideoDetailContainerViewModel.Location.GAME_ZONE.getValue();
} else {
location = path;
}
DirectUtils.directToVideoDetail(this, path, location,
false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer,
TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId,
TextUtils.isEmpty(sectionName) ? "" : sectionName);
break;
case HOST_VIDEO_STREAMING_HOME:
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_VIDEO, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
case HOST_VIDEO_STREAMING_DESC:
DirectUtils.directToGameDetailVideoStreaming(this, path, ENTRANCE_BROWSER);
break;
case HOST_VIDEO_COLLECTION:
DirectUtils.directToGameVideo(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QQ:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_GROUP:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_QUN:
String key = uri.getQueryParameter("key");
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, key);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_WEB:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_WEB);
bundle.putString(KEY_DATA, to);
bundle.putString(KEY_TYPE, type);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_LIBAO:
DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER);
break;
case HOST_USERHOME:
String position = uri.getQueryParameter("position");
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN:
CommunityEntity community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String columnId = uri.getQueryParameter("column_id");
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_QUESTION_LABEL_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String tag = uri.getQueryParameter("tag");
DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
columnId = uri.getQueryParameter("column_id");
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_BLOCK:
name = uri.getQueryParameter("name");
SubjectRecommendEntity entity = new SubjectRecommendEntity();
entity.setLink(path);
entity.setName(name);
entity.setText(name);
DirectUtils.directToBlock(this, entity, mEntrance);
break;
case EntranceUtils.HOST_SERVER_BLOCK:
DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_AMWAY_BLOCK:
DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_HELP:
name = uri.getQueryParameter("name");
DirectUtils.directToQa(this, name, path);
break;
case EntranceUtils.HOST_HELP_COLLECTION:
name = uri.getQueryParameter("name");
DirectUtils.directToQaCollection(this, name, path);
break;
case EntranceUtils.HOST_GAME_UPLOAD:
DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_GAME_ZONE:
String zoneUrl = uri.getQueryParameter("url");
DirectUtils.directGameZone(this, path, zoneUrl, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_LINK:
try {
String dataString = uri.getQueryParameter("data");
if (!TextUtils.isEmpty(dataString)) {
byte[] linkData = Base64.decode(dataString, Base64.DEFAULT);
String linkDataString = new String(linkData, "UTF-8");
LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class);
DirectUtils.directToLinkPage(this, le, ENTRANCE_BROWSER, "");
case HOST_GAME:
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
break;
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID);
String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5);
String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ?
String.format("%s-%s-V%s",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION)) :
String.format("%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION), gameId, packageMd5);
String qaId = uri.getQueryParameter("qa_id");
String qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE);
if (!TextUtils.isEmpty(qaId)) {
DirectUtils.directToQa(this, qaTitle, qaId);
} else {
DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER);
}
} catch (Exception e) {
e.printStackTrace();
toast(e.getMessage());
}
break;
case EntranceUtils.HOST_GAME_NEWS:
DirectUtils.directToGameNews(
this,
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
EntranceUtils.ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_CALENDAR:
DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_HISTORY_APK:
DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_FORUM_DETAIL:
DirectUtils.directForumDetail(this, id, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_RATING_DETAIL:
DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_FORUM:
DirectUtils.directToForum(this);
break;
case EntranceUtils.HOST_HELP_AND_FEEDBACK:
position = uri.getQueryParameter("position");
DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
break;
default:
break;
case HOST_DOWNLOAD:
DirectUtils.directToDownloadManagerAndStartUpdate(this, path, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER);
break;
case HOST_ANSWER:
DirectUtils.directToAnswerDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QUESTION:
DirectUtils.directToQuestionDetail(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_TOOLBOX:
DirectUtils.directToToolbox(this, uri.getQueryParameter("gameId"), uri.getQueryParameter("toolboxUrl"), ENTRANCE_BROWSER);
break;
case HOST_COMMUNITY:
UserManager.getInstance().setCommunityData(new CommunityEntity(path, name));
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_COMMUNITY, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_COMMUNITY, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
// 社区文章格式一
case "community.article":
DirectUtils.directToCommunityArticle(this, uri.getQueryParameter("articleId"), uri.getQueryParameter("communityId"), ENTRANCE_BROWSER, "浏览器");
break;
// 社区文章格式二
case "communities":
String communityId = "";
String typeId = "";
String[] split = path.split("/");
for (String text : split) {
if (TextUtils.isEmpty(communityId)) {
communityId = text;
continue;
}
if (TextUtils.isEmpty(type)) {
type = text;
continue;
}
if (TextUtils.isEmpty(typeId)) {
typeId = text;
}
}
if ("articles".equals(type)) {
DirectUtils.directToCommunityArticle(this, typeId, communityId, ENTRANCE_BROWSER, "浏览器");
break;
}
break;
case HOST_VIDEO:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.HOTTEST_GAME_VIDEO.getValue(),
false, id, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_UPLOAD_VIDEO://跳转上传视频
String titleParameter = uri.getQueryParameter("title");
String title = TextUtils.isEmpty(titleParameter) ? "" : "#" + titleParameter + "#";
String categoryId = uri.getQueryParameter("category_id");
String link = uri.getQueryParameter("link");
gameId = uri.getQueryParameter("gameId");
String gameName = uri.getQueryParameter("gameName");
String tagActivityId = uri.getQueryParameter("tagActivityId");
String tagActivityName = uri.getQueryParameter("tagActivityName");
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName);
SimpleGameEntity simpleGameEntity = new SimpleGameEntity(gameId != null ? gameId : "", gameName != null ? gameName : "", "");
Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "");
CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, () ->
DirectUtils.directToVideoManager(SkipActivity.this, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "浏览器"));
break;
case HOST_VIDEO_SINGLE:
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(),
false, "", ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer);
break;
case HOST_VIDEO_MORE:
gameId = uri.getQueryParameter("gameId");
String act = uri.getQueryParameter("act");
String fieldId = uri.getQueryParameter("fieldId");
String sectionName = uri.getQueryParameter("sectionName");
String paginationType = uri.getQueryParameter("paginationType");//活动分页方式 page filter
String location;
if (!TextUtils.isEmpty(act)) {
location = VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.getValue();
} else if (!TextUtils.isEmpty(fieldId)) {
location = VideoDetailContainerViewModel.Location.GAME_ZONE.getValue();
} else {
location = path;
}
DirectUtils.directToVideoDetail(this, path, location,
false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer,
TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId,
TextUtils.isEmpty(sectionName) ? "" : sectionName);
break;
case HOST_VIDEO_STREAMING_HOME:
// 把切换放到 MainActivity 处理
if (RunningUtils.isRunning(this)
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(this))) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true);
} else {
bundle = new Bundle();
bundle.putBoolean(MainActivity.SWITCH_TO_VIDEO, true);
intent = SplashScreenActivity.getSplashScreenIntent(this, bundle);
}
startActivity(intent);
break;
case HOST_VIDEO_STREAMING_DESC:
DirectUtils.directToGameDetailVideoStreaming(this, path, ENTRANCE_BROWSER);
break;
case HOST_VIDEO_COLLECTION:
DirectUtils.directToGameVideo(this, path, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_QQ:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_GROUP:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, path);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_QQ_QUN:
String key = uri.getQueryParameter("key");
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_QQ_GROUP);
bundle.putString(KEY_DATA, key);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_WEB:
bundle = new Bundle();
bundle.putString(KEY_TO, HOST_WEB);
bundle.putString(KEY_DATA, to);
bundle.putString(KEY_TYPE, type);
EntranceUtils.jumpActivity(this, bundle);
break;
case HOST_LIBAO:
DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER);
break;
case HOST_USERHOME:
String position = uri.getQueryParameter("position");
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN:
CommunityEntity community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String columnId = uri.getQueryParameter("column_id");
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_QUESTION_LABEL_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String tag = uri.getQueryParameter("tag");
DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
columnId = uri.getQueryParameter("column_id");
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_BLOCK:
name = uri.getQueryParameter("name");
SubjectRecommendEntity entity = new SubjectRecommendEntity();
entity.setLink(path);
entity.setName(name);
entity.setText(name);
DirectUtils.directToBlock(this, entity, mEntrance);
break;
case EntranceUtils.HOST_SERVER_BLOCK:
DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_AMWAY_BLOCK:
DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_HELP:
name = uri.getQueryParameter("name");
DirectUtils.directToQa(this, name, path);
break;
case EntranceUtils.HOST_HELP_COLLECTION:
name = uri.getQueryParameter("name");
DirectUtils.directToQaCollection(this, name, path);
break;
case EntranceUtils.HOST_GAME_UPLOAD:
DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_GAME_ZONE:
String zoneUrl = uri.getQueryParameter("url");
DirectUtils.directGameZone(this, path, zoneUrl, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_LINK:
try {
String dataString = uri.getQueryParameter("data");
if (!TextUtils.isEmpty(dataString)) {
byte[] linkData = Base64.decode(dataString, Base64.DEFAULT);
String linkDataString = new String(linkData, "UTF-8");
LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class);
DirectUtils.directToLinkPage(this, le, ENTRANCE_BROWSER, "");
}
} catch (Exception e) {
e.printStackTrace();
toast(e.getMessage());
}
break;
case EntranceUtils.HOST_GAME_NEWS:
DirectUtils.directToGameNews(
this,
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
EntranceUtils.ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_CALENDAR:
DirectUtils.directToGameServerCalendar(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_HISTORY_APK:
DirectUtils.directToHistoryApk(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID));
break;
case EntranceUtils.HOST_FORUM_DETAIL:
DirectUtils.directForumDetail(this, id, ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_GAME_RATING_DETAIL:
DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER);
break;
case EntranceUtils.HOST_FORUM:
DirectUtils.directToForum(this);
break;
case EntranceUtils.HOST_HELP_AND_FEEDBACK:
position = uri.getQueryParameter("position");
DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;
}
}
} else if ("market".equals(uri.getScheme())) {
String host = uri.getHost();
String id = uri.getQueryParameter("id");
if (host != null) {
if ("details".equals(host)) {
bundle = new Bundle();
bundle.putString(KEY_TO, EntranceUtils.KEY_MARKET_DETAILS);
bundle.putString(KEY_DATA, id);
EntranceUtils.jumpActivity(this, bundle);
} else {
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;
}
}
}
}

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -15,6 +16,12 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.g00fy2.versioncompare.Version;
import com.gh.base.BaseActivity;
import com.gh.common.AppExecutor;
@ -23,6 +30,7 @@ import com.gh.common.constant.Constants;
import com.gh.common.dialog.PrivacyDialogFragment;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DeviceTokenUtils;
import com.gh.common.util.DeviceUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.EmptyCallback;
import com.gh.common.util.GameSubstituteRepositoryHelper;
@ -32,7 +40,6 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.TagUtils;
import com.gh.common.util.TeaHelper;
import com.gh.common.util.UsageStatsHelper;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.entity.AuthDialogEntity;
@ -50,17 +57,14 @@ import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
@ -74,7 +78,8 @@ public class SplashScreenActivity extends BaseActivity {
private SharedPreferences mSharedPreferences;
private boolean isNewFirstLaunch;
private boolean mIsNewForThisVersion;
private boolean mStartMainActivityDirectly = false; // 是否不需要用户点击立即体验就直接跳转首页
private static final int REQUEST_PERMISSION_TAG = 30001;
private String[] mPermissions = {
@ -94,7 +99,7 @@ public class SplashScreenActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
isNewFirstLaunch = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
mIsNewForThisVersion = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
super.onCreate(savedInstanceState);
@ -105,13 +110,14 @@ public class SplashScreenActivity extends BaseActivity {
}
// 判断是不是这个版本的新用户
if (isNewFirstLaunch) {
if (mIsNewForThisVersion) {
mContentView.setPadding(0, 0, 0, 0);
ViewPager guideLayout = findViewById(R.id.splash_intro_vp_guide);
guideLayout.setAdapter(new GuidePagerAdapter());
// 判断是不是光环的新用户
if (SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)) {
mStartMainActivityDirectly = true;
SPUtils.setLong(Constants.SP_INITIAL_USAGE_TIME, System.currentTimeMillis());
HaloApp.getInstance().isBrandNewInstall = true;
showPrivacyDialog(guideLayout);
@ -124,6 +130,9 @@ public class SplashScreenActivity extends BaseActivity {
} else {
launchMainActivity();
}
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
}
private void showPrivacyDialog(ViewPager guideLayout) {
@ -136,7 +145,7 @@ public class SplashScreenActivity extends BaseActivity {
requestPermission();
});
} else {
DialogUtils.showPrivacyPolicyDisallowDialog(this, PrivacyPolicyEntity.createDefaultData(),()->{
DialogUtils.showPrivacyPolicyDisallowDialog(this, PrivacyPolicyEntity.createDefaultData(), () -> {
showPrivacyDialog(guideLayout);
});
}
@ -245,7 +254,7 @@ public class SplashScreenActivity extends BaseActivity {
@Override
protected int getLayoutId() {
if (isNewFirstLaunch) {
if (mIsNewForThisVersion) {
return R.layout.activity_splash_intro;
} else {
return 0;
@ -255,7 +264,7 @@ public class SplashScreenActivity extends BaseActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
if (isNewFirstLaunch && EasyPermissions.hasPermissions(this, mPermissions)) {
if (mIsNewForThisVersion && EasyPermissions.hasPermissions(this, mPermissions)) {
launchMainActivity();
} else {
return true;
@ -282,9 +291,7 @@ public class SplashScreenActivity extends BaseActivity {
prefetchData();
// 在可能获取了相关权限后才初始化SDK/发送激活数据
TeaHelper.init(getApplication(), HaloApp.getInstance().getChannel());
// GdtHelper.INSTANCE.logAction(ActionType.START_APP, GdtHelper.NETWORK_TYPE, DeviceUtils.getNetwork(this));
uploadTeaAndGdtData();
Bundle bundle = getIntent().getExtras();
Intent intent = new Intent(SplashScreenActivity.this, MainActivity.class);
@ -293,6 +300,33 @@ public class SplashScreenActivity extends BaseActivity {
finish();
}
private void uploadTeaAndGdtData(){
// 在可能获取了相关权限后才初始化SDK/发送激活数据
// TeaHelper.init(getApplication(), HaloApp.getInstance().getChannel());
try {
Class<?> clazz = Class.forName("com.gh.gamecenter.TeaHelper");
Method method = clazz.getMethod("init", Context.class, String.class);
method.invoke(null, getApplication(), HaloApp.getInstance().getChannel());
} catch (Exception e) {
e.printStackTrace();
}
// GdtHelper.INSTANCE.logAction(ActionType.START_APP, GdtHelper.NETWORK_TYPE, DeviceUtils.getNetwork(this));
try {
Class<?> clazz = Class.forName("com.gh.gamecenter.GdtHelper");
Field field = clazz.getDeclaredField("NETWORK_TYPE");
String type = (String) field.get(null);
Method method = clazz.getMethod("logAction", String.class, String[].class);
Class<?> actionTypeClazz = Class.forName("com.qq.gdt.action.ActionType");
Field typeField = actionTypeClazz.getDeclaredField("START_APP");
String actionType = (String) typeField.get(null);
method.invoke(null, actionType, new String[]{type, DeviceUtils.getNetwork(this)});
} catch (Exception e) {
e.printStackTrace();
}
}
private void getUniqueId() {
DataUtils.getGid();
}
@ -336,6 +370,9 @@ public class SplashScreenActivity extends BaseActivity {
MtaHelper.onEvent("授权情况", "启动授权", "都授权");
// 检查是否有旧版本光环,有就删掉
AppExecutor.getIoExecutor().execute(this::deleteOutdatedUpdatePackage);
if (mStartMainActivityDirectly) {
launchMainActivity();
}
} else {
ActivityCompat.requestPermissions(this, mPermissions, REQUEST_PERMISSION_TAG);
}
@ -350,12 +387,22 @@ public class SplashScreenActivity extends BaseActivity {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}, () -> logGrantedPermission(perms));
}, () -> {
logGrantedPermission(perms);
if (mStartMainActivityDirectly) {
launchMainActivity();
}
});
} else {
DialogUtils.showPermissionDialog(this, "权限申请",
"在设置-应用-光环助手-权限中开启存储和手机信息权限,以保证能正常使用相关功能", "重试", "放弃",
this::checkAndRequestPermission,
() -> logGrantedPermission(perms));
() -> {
logGrantedPermission(perms);
if (mStartMainActivityDirectly) {
launchMainActivity();
}
});
}
}

View File

@ -17,6 +17,7 @@ import androidx.core.content.ContextCompat;
import com.gh.common.util.BitmapUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.KcSelectGameViewHolder;
import com.gh.gamecenter.entity.InstallGameEntity;
@ -106,7 +107,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
for (String apk_path : mApkPath) {
InstallGameEntity apkEntity = new InstallGameEntity();
PackageManager pm = mContext.getApplicationContext().getPackageManager();
PackageInfo packageInfo = pm.getPackageArchiveInfo(apk_path, PackageManager.GET_ACTIVITIES);
PackageInfo packageInfo = pm.getPackageArchiveInfo(apk_path, 0);
if (packageInfo == null) continue;
ApplicationInfo appInfo = packageInfo.applicationInfo;
@ -132,7 +133,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
/**安装处理类型*/
/** 得到包名 */
String packageName = packageInfo.packageName;
int type = doType(pm, packageName);
int type = doType(packageName);
apkEntity.setInstallStatus(type);
mApkList.add(apkEntity);
@ -176,8 +177,8 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
}
}
private int doType(PackageManager pm, String packageName) {
List<PackageInfo> pakageinfos = pm.getInstalledPackages(0);
private int doType(String packageName) {
List<PackageInfo> pakageinfos = PackageUtils.getInstalledPackages(mContext, 0);
for (PackageInfo pi : pakageinfos) {
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
String pi_packageName = pi.packageName;

View File

@ -5,9 +5,14 @@ import android.content.Intent;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.GameOffServiceDialogFragment;
import com.gh.common.dialog.PackageCheckDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.history.HistoryHelper;
@ -39,16 +44,13 @@ import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
/**
* Created by khy on 27/06/17.
* 详情页面下载ViewHolder
@ -165,16 +167,18 @@ public class DetailViewHolder {
PermissionHelper.checkStoragePermissionBeforeAction(mViewHolder.context, () -> {
if (mGameEntity.getApk().size() == 1) {
ApkEntity apk = mGameEntity.getApk().get(0);
DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk,
() -> {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.checkDownload(mViewHolder.context, apk.getSize(), this::download);
});
PackageCheckDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity.getPackageDialog(), () -> {
DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showOverseaDownloadDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.checkDownload(mViewHolder.context, apk.getSize(), this::download);
});
});
});
});
});
} else {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
DialogUtils.showVersionNumberDialog(mViewHolder.context, mGameEntity, () -> {
@ -248,15 +252,13 @@ public class DetailViewHolder {
break;
case RESERVABLE:
CheckLoginUtils.checkLogin(mViewHolder.context, mEntrance, () -> {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(mViewHolder.context, () -> {
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
mGameEntity,
() -> {
LogUtils.logReservation(mGameEntity, mTraceEvent);
DetailDownloadUtils.detailInitDownload(mViewHolder, false);
});
dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve");
});
ReserveDialogFragment dialogFragment = ReserveDialogFragment.getInstance(
mGameEntity,
() -> {
LogUtils.logReservation(mGameEntity, mTraceEvent);
DetailDownloadUtils.detailInitDownload(mViewHolder, false);
});
dialogFragment.show(((AppCompatActivity) mViewHolder.context).getSupportFragmentManager(), "reserve");
});
break;
case RESERVED:

View File

@ -63,7 +63,7 @@ class AmwaySearchActivity : SearchActivity() {
val transaction = supportFragmentManager.beginTransaction()
when (type) {
DisplayType.DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(AmwaySearchDefaultFragment::class.java.simpleName)
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.simpleName)
?: AmwaySearchDefaultFragment()
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.simpleName)
}

View File

@ -44,14 +44,10 @@ class AmwaySearchViewHolder(var binding: AmwaySearchItemBinding, val mViewModel:
it.context.showRegulationTestDialogIfNeeded {
val installPackageName = mViewModel.canUserCommentThisGame(gameEntity)
if (gameEntity.directComment || !installPackageName.isNullOrEmpty()) {
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(activity, object : EmptyCallback {
override fun onCallback() {
MtaHelper.onEvent("发表评论", "进入", "选中游戏_${gameEntity.name}")
val intent = RatingEditActivity.getIntent(binding.root.context, gameEntity, 0.0F, installPackageName, true)
activity.startActivity(intent)
activity.finish()
}
})
MtaHelper.onEvent("发表评论", "进入", "选中游戏_${gameEntity.name}")
val intent = RatingEditActivity.getIntent(binding.root.context, gameEntity, 0.0F, installPackageName, true)
activity.startActivity(intent)
activity.finish()
} else {
Utils.toast(activity, "安装游戏后才能评论哦")
}

View File

@ -0,0 +1,34 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R
class CatalogActivity : NormalActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, CatalogActivity::class.java, CatalogFragment::class.java)
}
companion object {
fun getIntent(context: Context, catalogId: String, catalogTitle: String, entrance: String): Intent {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_CATALOG_ID, catalogId)
bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance)
return getTargetIntent(context, CatalogActivity::class.java, CatalogFragment::class.java, bundle)
}
}
}

View File

@ -0,0 +1,51 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class CatalogAdapter(context: Context,
private val mFragment: CatalogFragment,
private val mViewModel: CatalogViewModel,
private val mList: List<CatalogEntity.SubCatalogEntity>)
: BaseRecyclerAdapter<CatalogAdapter.CatalogItemViewHolder>(context) {
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
CatalogItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_item,parent, false))
override fun onBindViewHolder(holder: CatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
entity = catalogEntity
executePendingBindings()
if (catalogEntity.name == mViewModel.selectedCatalogName) {
selectedTag.visibility = View.VISIBLE
catalogName.setTextColor(R.color.theme_font.toColor())
root.setBackgroundColor(R.color.white.toColor())
} else {
selectedTag.visibility = View.GONE
catalogName.setTextColor(R.color.text_333333.toColor())
root.setBackgroundColor(R.color.text_F5F5F5.toColor())
}
root.setOnClickListener {
if (catalogEntity.name != mViewModel.selectedCatalogName) {
mViewModel.selectedCatalogName = catalogEntity.name
mViewModel.logSubCatalogClick(position)
mFragment.changeCatalog(position)
notifyDataSetChanged()
}
}
}
}
class CatalogItemViewHolder(val binding: CatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,116 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import com.gh.common.util.EntranceUtils
import com.gh.common.util.viewModelProviderFromParent
import com.gh.common.view.FixLinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.normal.NormalFragment
class CatalogFragment : NormalFragment() {
private lateinit var mBinding: FragmentCatalogBinding
private lateinit var mViewModel: CatalogViewModel
private lateinit var mEntity: CatalogEntity
private lateinit var mSpecialCatalogFragment: SpecialCatalogFragment
private lateinit var mSubCatalogFragment: SubCatalogFragment
private var mCatalogId: String = ""
private var mCatalogTitle: String = ""
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: ""
mCatalogTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: ""
mViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle))
mViewModel.validEntranceName = if (mEntrance.contains("首页")) "首页" else "板块"
mViewModel.logAppearance()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mCatalogTitle)
mViewModel.catalogs.observe(viewLifecycleOwner, Observer {
mBinding.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
containerCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
if (mEntity.hasSpecial) {
val specialEntity = CatalogEntity.SubCatalogEntity(name = "精选")
(mEntity.subCatalog as ArrayList).add(0, specialEntity)
}
initView()
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel.getCatalogs()
}
}
}
})
}
private fun initView() {
mEntity.run {
if (subCatalog.isNotEmpty()) {
mViewModel.selectedCatalogName = subCatalog[0].name
mBinding.rvCatalog.layoutManager = FixLinearLayoutManager(requireContext())
mBinding.rvCatalog.adapter = CatalogAdapter(requireContext(), this@CatalogFragment, mViewModel, subCatalog)
if (hasSpecial) {
mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment()
mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
} else {
mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment()
mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[0].id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
}
}
}
}
fun changeCatalog(position: Int) {
mEntity.run {
if (hasSpecial) {
if (mViewModel.selectedCatalogPosition == 0) {
mSubCatalogFragment = childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.simpleName) as? SubCatalogFragment ?: SubCatalogFragment()
mSubCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id, EntranceUtils.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSubCatalogFragment, SubCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
} else {
if (position == 0) {
mSpecialCatalogFragment = childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName) as? SpecialCatalogFragment ?: SpecialCatalogFragment()
mSpecialCatalogFragment.arguments = bundleOf(EntranceUtils.KEY_CATALOG_ID to mEntity.id)
childFragmentManager.beginTransaction().replace(R.id.container_sub_catalog, mSpecialCatalogFragment, SpecialCatalogFragment::class.java.simpleName).commitAllowingStateLoss()
} else {
mSubCatalogFragment.changeSubCatalog(subCatalog[position].id)
}
}
} else {
mSubCatalogFragment.changeSubCatalog(subCatalog[position].id)
}
mViewModel.selectedCatalogPosition = position
}
}
}

View File

@ -0,0 +1,77 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.exposure.ExposureSource
import com.gh.common.util.LogUtils
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class CatalogViewModel(application: Application, private val catalogId: String, val catalogTitle: String)
: AndroidViewModel(application) {
private val api = RetrofitManager.getInstance(getApplication()).api
var catalogs = MutableLiveData<CatalogEntity>()
var selectedCatalogName: String = ""
var selectedCatalogPosition: Int = 0
var validEntranceName: String = ""
val basicExposureSource by lazy { ExposureSource("分类", catalogTitle) }
init {
getCatalogs()
}
@SuppressLint("CheckResult")
fun getCatalogs() {
api.getCatalogs(catalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
fun logAppearance() {
LogUtils.logNewCatalogAppearanceEvent(validEntranceName, catalogTitle)
}
fun logSubCatalogClick(position: Int) {
LogUtils.logSubCatalogClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}", position)
}
fun logSubCatalogContentClick(itemName: String, listPosition: Int) {
LogUtils.logSubCatalogContentClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}_${itemName}", selectedCatalogPosition, listPosition)
}
fun logSpecialCatalogContentClick(contentType: String, contentName: String, listPosition: Int) {
LogUtils.logSpecialCatalogContentClickEvent(validEntranceName, "${catalogTitle}_${contentType}_${contentName}", selectedCatalogPosition, listPosition)
}
fun logSpecialCatalogSpecificContentClick(contentType: String, contentName: String, targetName: String, listPosition: Int, specificListPosition: Int) {
LogUtils.logSpecialCatalogSpecificContentClickEvent(validEntranceName, "${catalogTitle}_${contentType}_${contentName}_${targetName}", selectedCatalogPosition, listPosition, specificListPosition)
}
class Factory(private val catalogId: String, private val catalogTitle: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CatalogViewModel(HaloApp.getInstance().application, catalogId, catalogTitle) as T
}
}
}

View File

@ -0,0 +1,38 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.CatalogEntity
class NewCatalogListActivity : NormalActivity() {
companion object {
fun getIntent(context: Context,
primaryCatalogName: String, // 一级分类名
catalogTitle: String,
catalog: CatalogEntity,
initTitle: String): Intent {
val bundle = Bundle()
bundle.putParcelable(EntranceUtils.KEY_DATA, catalog)
bundle.putString(EntranceUtils.KEY_PRIMARY_CATALOG_NAME, primaryCatalogName)
bundle.putString(EntranceUtils.KEY_NAME, catalog.name)
bundle.putString(EntranceUtils.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceUtils.KEY_CATALOG_INIT_TITLE, initTitle)
return getTargetIntent(context, NewCatalogListActivity::class.java, NewCatalogListFragment::class.java, bundle)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
}
override fun showDownloadMenu(): Boolean {
return true
}
}

View File

@ -0,0 +1,173 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.util.SparseArray
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
import com.gh.common.exposure.ExposureType
import com.gh.common.exposure.IExposable
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.GameViewUtils
import com.gh.common.util.StringUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.game.GameItemViewHolder
import com.lightgame.download.DownloadEntity
import java.util.*
class NewCatalogListAdapter(context: Context,
private val mBaseExposureSource: ExposureSource,
private val mViewModel: NewCatalogListViewModel,
private val mEntrance: String?) : ListAdapter<GameEntity>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
val positionAndPackageMap = HashMap<String, Int>()
override fun setListData(updateData: MutableList<GameEntity>?) {
// 记录游戏位置
if (updateData != null) {
for (i in 0 until updateData.size) {
val gameEntity = updateData[i]
var packages = gameEntity.id
for (apkEntity in gameEntity.getApk()) {
packages += apkEntity.packageName
}
positionAndPackageMap[packages + i] = i
}
}
super.setListData(updateData)
}
fun clearPositionAndPackageMap() {
positionAndPackageMap.clear()
}
override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
return oldItem?.id == newItem?.id
}
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) {
return ItemViewType.ITEM_FOOTER
}
return ItemViewType.GAME_NORMAL
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.GAME_NORMAL -> {
GameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.game_item, parent, false))
}
else -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
}
}
override fun getItemCount(): Int {
return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameItemViewHolder) {
val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px()
holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px())
val gameEntity = mEntityList[position]
holder.binding.game = gameEntity
holder.initServerType(gameEntity)
holder.binding.hideSize = true
holder.binding.executePendingBindings()
GameViewUtils.setLabelList(mContext, holder.binding.labelList, gameEntity.tagStyle)
gameEntity.sequence = position + 1
val sortType = mViewModel.sortType.value
val sortSize = mViewModel.sortSize.text
val toolbarTitle = mViewModel.title
val selectedCatalogName = mViewModel.selectedCatalog.name
val exposureSources = ArrayList<ExposureSource>()
exposureSources.add(mBaseExposureSource)
exposureSources.add(ExposureSource(toolbarTitle))
exposureSources.add(ExposureSource("二级分类详情", "$selectedCatalogName+$sortType+$sortSize"))
gameEntity.sequence = position + 1
val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
mExposureEventSparseArray.put(position, event)
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])"),
event)
}
DownloadItemUtils.setOnClickListener(mContext,
holder.binding.downloadBtn,
gameEntity,
position,
this,
StringUtils.buildString(StringUtils.buildString(mEntrance, "+(", toolbarTitle, ":列表[", selectedCatalogName, "=", sortType, "=", (position + 1).toString(), "])")),
StringUtils.buildString(selectedCatalogName, ":", gameEntity.name),
event)
DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), true, "star&brief")
} else if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint)
holder.itemView.setOnClickListener {
if (mIsNetworkError) {
mViewModel.load(LoadType.RETRY)
}
}
}
}
fun notifyItemByDownload(download: DownloadEntity) {
for (key in positionAndPackageMap.keys) {
if (key.contains(download.packageName) && key.contains(download.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap()[download.platform] = download
notifyItemChanged(position)
}
}
}
}
fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
for (key in positionAndPackageMap.keys) {
if (key.contains(status.packageName) && key.contains(status.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap().remove(status.platform)
notifyItemChanged(position)
}
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return mExposureEventSparseArray.get(pos)
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}

View File

@ -0,0 +1,182 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import com.ethanhua.skeleton.Skeleton
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.ExposureSource
import com.gh.common.util.DialogUtils
import com.gh.common.util.EntranceUtils
import com.gh.common.util.observeNonNull
import com.gh.common.util.viewModelProvider
import com.gh.common.view.CatalogFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.databinding.FragmentCatalogListBinding
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class NewCatalogListFragment : ListFragment<GameEntity, NewCatalogListViewModel>() {
private var mPrimaryCatalogName: String = "" // 一级分类名
private var mPrimeCatalog: CatalogEntity? = null
private var mSubCatalogList = arrayListOf<CatalogEntity.SubCatalogEntity>()
private var mInitCatalogName = ""
private var mAdapter: NewCatalogListAdapter? = null
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
showUnzipFailureDialog(downloadEntity)
}
}
}
private lateinit var mBinding: FragmentCatalogListBinding
private lateinit var mExposureListener: ExposureListener
private lateinit var mViewModel: NewCatalogListViewModel
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentCatalogListBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun provideListViewModel() = viewModelProvider<NewCatalogListViewModel>()
override fun provideListAdapter() = mAdapter
?: NewCatalogListAdapter(
requireContext(),
ExposureSource(mPrimaryCatalogName),
mViewModel,
mEntrance).apply { mAdapter = this }
override fun getItemDecoration() = null
override fun onCreate(savedInstanceState: Bundle?) {
mViewModel = provideListViewModel()
mViewModel.title = arguments?.getString(EntranceUtils.KEY_NAME) ?: ""
mViewModel.categoryTitle = arguments?.getString(EntranceUtils.KEY_CATALOG_TITLE) ?: ""
mEntrance = arguments?.getString(EntranceUtils.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN
mPrimeCatalog = arguments?.getParcelable(EntranceUtils.KEY_DATA)
mSubCatalogList = mPrimeCatalog?.subCatalog as ArrayList<CatalogEntity.SubCatalogEntity>
mInitCatalogName = arguments?.getString(EntranceUtils.KEY_CATALOG_INIT_TITLE) ?: ""
mPrimaryCatalogName = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_NAME) ?: ""
mViewModel.selectedCatalog = mSubCatalogList.find { entity -> entity.name == mInitCatalogName }
?: CatalogEntity.SubCatalogEntity()
initSortType()
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mViewModel.title)
initFilterView()
mViewModel.refresh.observeNonNull(this) { onRefresh() }
mExposureListener = ExposureListener(this, mAdapter!!)
mListRv.addOnScrollListener(mExposureListener)
mSkeletonScreen = Skeleton.bind(mBinding.listSkeleton).shimmer(false).load(R.layout.fragment_subject_skeleton).show()
}
private fun initSortType() {
mPrimeCatalog?.switch?.run {
if (hotSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RECOMMENDED
return@run
}
if (newSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.NEWEST
return@run
}
if (starSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RATING
return@run
}
}
}
private fun initFilterView() {
mBinding.filterContainer.run {
visibility = View.VISIBLE
setTypeList(mPrimeCatalog?.switch ?: CatalogEntity.CatalogSwitch())
setCatalogList(mSubCatalogList, mInitCatalogName)
setOnConfigSetupListener(object : CatalogFilterView.OnCatalogFilterSetupListener {
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
mViewModel.updateSortConfig(sortSize = sortSize)
}
override fun onSetupSortType(sortType: CatalogFilterView.SortType) {
mViewModel.updateSortConfig(sortType = sortType)
}
override fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity) {
mViewModel.updateSortConfig(sortCatalog = sortCatalog)
}
})
}
}
override fun onResume() {
if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged()
super.onResume()
DownloadManager.getInstance(context).addObserver(mDataWatcher)
}
override fun onPause() {
super.onPause()
DownloadManager.getInstance(context).removeObserver(mDataWatcher)
}
override fun onRefresh() {
mAdapter?.clearPositionAndPackageMap()
super.onRefresh()
}
// 下载被删除事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus) {
if ("delete" == status.status) {
mAdapter?.notifyItemAndRemoveDownload(status)
}
}
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if ("安装" == busFour.type || "卸载" == busFour.type) {
mAdapter?.notifyDataSetChanged()
}
}
fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
val data = mAdapter?.positionAndPackageMap ?: return
for (gameAndPosition in data) {
if (gameAndPosition.key.contains(downloadEntity.packageName)) {
val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
if (targetView != null) {
DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
return
}
}
}
}
}

View File

@ -0,0 +1,82 @@
package com.gh.gamecenter.catalog
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.gh.common.util.UrlFilterUtils
import com.gh.common.view.CatalogFilterView
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class NewCatalogListViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {
var title = "" // 显示在 Toolbar 的标题
var categoryTitle = "" // 跳转进来的分类的标题
val refresh = MutableLiveData<Boolean>()
var selectedCatalog = CatalogEntity.SubCatalogEntity()
var sortType = CatalogFilterView.SortType.RECOMMENDED
var sortSize = SubjectSettingEntity.Size()
private val api = RetrofitManager.getInstance(getApplication()).api
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? = null
override fun provideDataSingle(page: Int): Single<List<GameEntity>> {
return if (selectedCatalog.link.type == "column") { // column(专题)/tag(标签)
api.getColumn(selectedCatalog.link.link, getSortType(), getSortSize(), page) // 专题
} else {
api.getGamesWithSpecificTag(getSortSize(), getSortType(), page) // 标签
}
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
}
fun updateSortConfig(sortSize: SubjectSettingEntity.Size? = null,
sortType: CatalogFilterView.SortType? = null,
sortCatalog: CatalogEntity.SubCatalogEntity? = null) {
when {
sortSize != null && sortSize != this.sortSize -> {
this.sortSize = sortSize
refresh.postValue(true)
}
sortType != null && sortType != this.sortType -> {
this.sortType = sortType
refresh.postValue(true)
}
sortCatalog != null && sortCatalog != selectedCatalog -> {
selectedCatalog = sortCatalog
refresh.postValue(true)
}
}
}
private fun getSortSize(): String? {
return if (selectedCatalog.link.type == "column") {
UrlFilterUtils.getFilterQuery(
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString())
} else {
UrlFilterUtils.getFilterQuery(
"tag_id", selectedCatalog.link.link,
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString())
}
}
private fun getSortType(): String? {
return when (sortType) {
CatalogFilterView.SortType.RECOMMENDED -> if (selectedCatalog.link.type == "column") "position:1" else "download:-1"
CatalogFilterView.SortType.NEWEST -> "publish:-1"
CatalogFilterView.SortType.RATING -> "star:-1"
}
}
}

View File

@ -0,0 +1,239 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
import com.gh.common.exposure.IExposable
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.databinding.CatalogHeaderItemBinding
import com.gh.gamecenter.databinding.CatalogImageItemBinding
import com.gh.gamecenter.databinding.CatalogSubjectCollectionItemBinding
import com.gh.gamecenter.databinding.CatalogSubjectItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.subject.SubjectActivity.Companion.startSubjectActivity
class SpecialCatalogAdapter(context: Context, private val mCatalogViewModel: CatalogViewModel)
: ListAdapter<SpecialCatalogItemData>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
override fun getItemCount() = if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT
override fun areItemsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean {
return when {
oldItem?.header != null && newItem?.header != null -> {
oldItem.header.id == newItem.header.id
}
oldItem?.bigImage != null && newItem?.bigImage != null -> {
oldItem.bigImage.id == newItem.bigImage.id
}
oldItem?.subject != null && newItem?.subject != null -> {
oldItem.subject.id == newItem.subject.id
}
oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> {
oldItem.subjectCollection.id == newItem.subjectCollection.id
}
else -> super.areItemsTheSame(oldItem, newItem)
}
}
override fun areContentsTheSame(oldItem: SpecialCatalogItemData?, newItem: SpecialCatalogItemData?): Boolean {
return when {
oldItem?.header != null && newItem?.header != null -> {
oldItem.header.id == newItem.header.id
}
oldItem?.bigImage != null && newItem?.bigImage != null -> {
oldItem.bigImage.id == newItem.bigImage.id
}
oldItem?.subject != null && newItem?.subject != null -> {
oldItem.subject.id == newItem.subject.id
}
oldItem?.subjectCollection != null && newItem?.subjectCollection != null -> {
oldItem.subjectCollection.id == newItem.subjectCollection.id
}
else -> super.areItemsTheSame(oldItem, newItem)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View
return when (viewType) {
ItemViewType.ITEM_FOOTER -> {
view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)
FooterViewHolder(view)
}
TYPE_HEADER -> CatalogHeaderItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_header_item, parent, false))
TYPE_BIG_IMAGE -> CatalogImageItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_image_item, parent, false))
TYPE_SUBJECT -> CatalogSubjectItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_item, parent, false))
TYPE_SUBJECT_COLLECTION -> CatalogSubjectCollectionItemHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_item, parent, false))
else -> throw NullPointerException()
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CatalogImageItemHolder -> {
val imageEntity = mEntityList[position].bigImage!!
holder.binding.run {
entity = imageEntity.image
var exposureEvent: ExposureEvent? = null
if (imageEntity.link.type == "game") {
exposureEvent = ExposureEvent.createEvent(
GameEntity(id = imageEntity.link.link),
listOf(mCatalogViewModel.basicExposureSource, ExposureSource("精选页图片", "")))
mExposureEventSparseArray.append(position, exposureEvent)
}
root.setOnClickListener {
DirectUtils.directToLinkPage(mContext, imageEntity.link, "新分类-精选分类", "图片", exposureEvent)
mCatalogViewModel.logSpecialCatalogContentClick("图片", imageEntity.image.title, mEntityList[position].position)
}
}
}
is CatalogHeaderItemHolder -> {
val entity = mEntityList[position].header!!
val specialLink = entity.link
holder.binding.run {
link = specialLink
headMore.setOnClickListener {
if (entity.type == "专题合集") {
DirectUtils.directToColumnCollection(mContext, specialLink.link
?: "", -1, "(游戏-专题:" + specialLink.text + "-全部)")
} else {
startSubjectActivity(mContext, specialLink.link, specialLink.text, false, "(游戏-专题:" + specialLink.text + "-全部)")
}
mCatalogViewModel.logSpecialCatalogContentClick(entity.type, specialLink.text
?: "", mEntityList[position].position)
}
}
}
is CatalogSubjectItemHolder -> {
val subject = mEntityList[position].subject!!
val exposureList = arrayListOf<ExposureEvent>()
for (game in subject.link.data) {
val exposureEvent = ExposureEvent.createEvent(game,
listOf(mCatalogViewModel.basicExposureSource, ExposureSource("精选页专题", subject.link.text ?: "")))
exposureList.add(exposureEvent)
game.exposureEvent = exposureEvent
game.subjectName = subject.link.text
}
mEntityList[position].exposureEventList = exposureList
holder.bindSubject(subject.link.data, mEntityList[position].position)
}
is CatalogSubjectCollectionItemHolder -> {
val subjectCollection = mEntityList[position].subjectCollection!!
for (subject in subjectCollection.link.data) {
subject.subjectName = subjectCollection.link.text
}
holder.bindSubjectCollection(subjectCollection.link.data, mEntityList[position].position)
}
is FooterViewHolder -> {
holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint)
}
}
}
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) {
ItemViewType.ITEM_FOOTER
} else {
val item = mEntityList[position]
when {
item.header != null -> TYPE_HEADER
item.bigImage != null -> TYPE_BIG_IMAGE
item.subject != null -> TYPE_SUBJECT
item.subjectCollection != null -> TYPE_SUBJECT_COLLECTION
else -> TYPE_SUBJECT_COLLECTION
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? = mExposureEventSparseArray.get(pos)
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = mEntityList[pos].exposureEventList
class CatalogImageItemHolder(val binding: CatalogImageItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
class CatalogHeaderItemHolder(val binding: CatalogHeaderItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
inner class CatalogSubjectItemHolder(val binding: CatalogSubjectItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindSubject(gameList: List<GameEntity>, position: Int) {
binding.gameList.run {
var subjectAdapter = adapter
if (subjectAdapter is SpecialCatalogSubjectAdapter) {
subjectAdapter.checkResetData(gameList)
subjectAdapter.updatePosition(position)
return
}
subjectAdapter = SpecialCatalogSubjectAdapter(context, mCatalogViewModel, gameList).apply {
updatePosition(position)
}
layoutManager = GridLayoutManager(context, 3)
adapter = subjectAdapter
}
}
}
inner class CatalogSubjectCollectionItemHolder(val binding: CatalogSubjectCollectionItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindSubjectCollection(subjectCollection: List<GameEntity>, position: Int) {
binding.subjectCollectionList.run {
var collectionAdapter = adapter
if (collectionAdapter is SpecialCatalogSubjectCollectionAdapter) {
collectionAdapter.checkResetData(subjectCollection)
collectionAdapter.updatePosition(position)
return
}
collectionAdapter = SpecialCatalogSubjectCollectionAdapter(context, mCatalogViewModel, subjectCollection).apply {
updatePosition(position)
}
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = collectionAdapter
}
}
}
companion object {
private const val TYPE_HEADER = 900
private const val TYPE_BIG_IMAGE = 901
private const val TYPE_SUBJECT = 902
private const val TYPE_SUBJECT_COLLECTION = 903
}
}

View File

@ -0,0 +1,45 @@
package com.gh.gamecenter.catalog
import android.graphics.Color
import android.os.Bundle
import android.view.View
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.EntranceUtils
import com.gh.common.util.viewModelProvider
import com.gh.common.util.viewModelProviderFromParent
import com.gh.gamecenter.baselist.ListFragment
class SpecialCatalogFragment : ListFragment<SpecialCatalogItemData, SpecialCatalogViewModel>() {
private var mCatalogId = ""
private var mAdapter: SpecialCatalogAdapter? = null
private lateinit var mCatalogViewModel: CatalogViewModel
private lateinit var mExposureListener: ExposureListener
override fun provideListViewModel() = viewModelProvider<SpecialCatalogViewModel>(SpecialCatalogViewModel.Factory(mCatalogId))
override fun provideListAdapter() = mAdapter ?: SpecialCatalogAdapter(requireContext(), mCatalogViewModel).apply {
mAdapter = this
mExposureListener = ExposureListener(this@SpecialCatalogFragment, this)
}
override fun getItemDecoration() = null
override fun onCreate(savedInstanceState: Bundle?) {
mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: ""
// 按理来说在这里获取不需要再传值给构造函数,但保守起见还是传了
mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, ""))
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mListRv.setBackgroundColor(Color.WHITE)
mListRv.addOnScrollListener(mExposureListener)
}
}

View File

@ -0,0 +1,14 @@
package com.gh.gamecenter.catalog
import com.gh.common.exposure.ExposureEvent
import com.gh.gamecenter.entity.SpecialCatalogEntity
data class SpecialCatalogItemData(
val header: SpecialCatalogEntity? = null,
val bigImage: SpecialCatalogEntity? = null,
val subject: SpecialCatalogEntity? = null,
val subjectCollection: SpecialCatalogEntity? = null,
var position: Int = 0,
var exposureEventList: ArrayList<ExposureEvent>? = null
)

View File

@ -0,0 +1,82 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.dip2px
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogSubjectGameItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SpecialCatalogSubjectAdapter(context: Context,
private val mCatalogViewModel: CatalogViewModel,
private var mList: List<GameEntity>)
: BaseRecyclerAdapter<SpecialCatalogSubjectAdapter.CatalogSubjectGameItemViewHolder>(context) {
private val mEntrance = "精选分类"
private var countAndKey: Pair<Int, String>? = null
private var mPosition: Int = -1
init {
var dataIds = ""
mList.forEach {
dataIds += it.id
}
if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds)
}
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= CatalogSubjectGameItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_game_item, parent, false))
override fun onBindViewHolder(holder: CatalogSubjectGameItemViewHolder, position: Int) {
holder.binding.run {
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
topMargin = if (position > 2) 24F.dip2px() else 16F.dip2px()
}
val entity = mList[position]
game = entity
executePendingBindings()
if (!gameName.isSelected) {
gameName.postDelayed({ gameName.isSelected = true }, 500)
}
root.setOnClickListener {
GameDetailActivity.startGameDetailActivity(mContext, entity.id, "(${mEntrance})", entity.exposureEvent)
mCatalogViewModel.logSpecialCatalogSpecificContentClick(
"专题",
game?.subjectName ?: "",
game?.name ?: "",
mPosition,
position)
}
}
}
fun checkResetData(update: List<GameEntity>) {
var dataIds = ""
mList.forEach { dataIds += it.id }
mList = update
if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
notifyItemRangeChanged(0, itemCount)
} else if (countAndKey?.first != update.size) { // 数量发生改变
notifyDataSetChanged()
}
// 重新刷新数据标识
countAndKey = Pair(update.size, dataIds)
}
fun updatePosition(position: Int) {
mPosition = position
}
class CatalogSubjectGameItemViewHolder(val binding: CatalogSubjectGameItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,77 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.DirectUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogSubjectCollectionListItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.LinkEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SpecialCatalogSubjectCollectionAdapter(context: Context,
private val mCatalogViewModel: CatalogViewModel,
private var mList: List<GameEntity>)
: BaseRecyclerAdapter<SpecialCatalogSubjectCollectionAdapter.CatalogSubjectCollectionListItemViewHolder>(context) {
private var countAndKey: Pair<Int, String>? = null
private var mPosition: Int = -1
init {
var dataIds = ""
mList.forEach {
dataIds += it.id
}
if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds)
}
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= CatalogSubjectCollectionListItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.catalog_subject_collection_list_item, parent, false))
override fun onBindViewHolder(holder: CatalogSubjectCollectionListItemViewHolder, position: Int) {
holder.binding.run {
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
leftMargin = if (position == 0) 16F.dip2px() else 0
}
val entity = mList[position]
ImageUtils.display(subjectCollectionImage, entity.image)
root.setOnClickListener {
DirectUtils.directToLinkPage(mContext, LinkEntity(link = entity.link, type = entity.type), "精选分类", "专题合集")
mCatalogViewModel.logSpecialCatalogSpecificContentClick(
"专题合集",
entity.subjectName ?: "",
entity.name ?: "",
mPosition,
position)
}
}
}
fun checkResetData(update: List<GameEntity>) {
var dataIds = ""
mList.forEach { dataIds += it.id }
mList = update
if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
notifyItemRangeChanged(0, itemCount)
} else if (countAndKey?.first != update.size) { // 数量发生改变
notifyDataSetChanged()
}
// 重新刷新数据标识
countAndKey = Pair(update.size, dataIds)
}
fun updatePosition(position: Int) {
mPosition = position
}
class CatalogSubjectCollectionListItemViewHolder(val binding: CatalogSubjectCollectionListItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,50 @@
package com.gh.gamecenter.catalog
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.SpecialCatalogEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.Observable
import io.reactivex.Single
class SpecialCatalogViewModel(application: Application, private val catalogId: String) : ListViewModel<SpecialCatalogEntity, SpecialCatalogItemData>(application) {
override fun provideDataObservable(page: Int): Observable<List<SpecialCatalogEntity>>? = null
override fun provideDataSingle(page: Int): Single<List<SpecialCatalogEntity>> {
return RetrofitManager.getInstance(getApplication())
.sensitiveApi
.getSpecialCatalogs(catalogId, page)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
val itemDataList = arrayListOf<SpecialCatalogItemData>()
list.forEachIndexed { index, it ->
when (it.type) {
"图片" -> itemDataList.add(SpecialCatalogItemData(bigImage = it).apply { position = index })
"专题" -> {
itemDataList.add(SpecialCatalogItemData(header = it).apply { position = index })
itemDataList.add(SpecialCatalogItemData(subject = it).apply { position = index })
}
"专题合集" -> {
itemDataList.add(SpecialCatalogItemData(header = it).apply { position = index })
itemDataList.add(SpecialCatalogItemData(subjectCollection = it).apply { position = index })
}
}
}
mResultLiveData.postValue(itemDataList)
}
}
class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SpecialCatalogViewModel(HaloApp.getInstance().application, catalogId) as T
}
}
}

View File

@ -0,0 +1,43 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.DialogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.SubCatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SubCatalogAdapter(context: Context,
private val mCatalogViewModel: CatalogViewModel,
private val mPrimaryCatalog: CatalogEntity,
private var mList: List<CatalogEntity.SubCatalogEntity>)
: BaseRecyclerAdapter<SubCatalogAdapter.SubCatalogItemViewHolder>(context) {
private val mTypes = listOf("专题", "标签")
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
SubCatalogItemViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.sub_catalog_item, parent, false))
override fun onBindViewHolder(holder: SubCatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
entity = catalogEntity
executePendingBindings()
root.setOnClickListener {
mCatalogViewModel.logSubCatalogContentClick(catalogEntity.name, position)
if (mTypes.contains(catalogEntity.type)) {
root.context.startActivity(NewCatalogListActivity.getIntent(mContext, mCatalogViewModel.catalogTitle, catalogEntity.name, mPrimaryCatalog, catalogEntity.name))
} else {
DialogUtils.showLowVersionDialog(mContext)
}
}
}
}
class SubCatalogItemViewHolder(val binding: SubCatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,84 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import com.gh.common.util.EntranceUtils
import com.gh.common.util.viewModelProvider
import com.gh.common.util.viewModelProviderFromParent
import com.gh.gamecenter.databinding.FragmentSubCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.normal.NormalFragment
class SubCatalogFragment : NormalFragment() {
private lateinit var mBinding: FragmentSubCatalogBinding
private lateinit var mViewModel: SubCatalogViewModel
private lateinit var mCatalogViewModel: CatalogViewModel
private lateinit var mEntity: CatalogEntity
private var mCatalogId: String = ""
private var mPrimaryCatalogId: String = ""
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentSubCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCatalogId = arguments?.getString(EntranceUtils.KEY_CATALOG_ID) ?: ""
mPrimaryCatalogId = arguments?.getString(EntranceUtils.KEY_PRIMARY_CATALOG_ID) ?: ""
mViewModel = viewModelProvider(SubCatalogViewModel.Factory(mCatalogId))
mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, ""))
mViewModel.getSubCatalogs(mPrimaryCatalogId)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel.catalogs.observe(viewLifecycleOwner, Observer {
mBinding.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
rvSubCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
initView()
} else {
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel.getSubCatalogs(mPrimaryCatalogId)
}
}
}
})
}
private fun initView() {
mEntity.run {
mBinding.rvSubCatalog.layoutManager = GridLayoutManager(requireContext(), 3)
mBinding.rvSubCatalog.adapter = SubCatalogAdapter(requireContext(), mCatalogViewModel, mEntity, subCatalog)
}
}
fun changeSubCatalog(primaryCatalogId: String) {
mBinding.run {
mPrimaryCatalogId = primaryCatalogId
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.GONE
reuseLoading.root.visibility = View.VISIBLE
mViewModel.getSubCatalogs(mPrimaryCatalogId)
}
}
}

View File

@ -0,0 +1,44 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class SubCatalogViewModel(application: Application, private val catalogId: String): AndroidViewModel(application) {
private val api = RetrofitManager.getInstance(getApplication()).api
var catalogs = MutableLiveData<CatalogEntity>()
@SuppressLint("CheckResult")
fun getSubCatalogs(primaryCatalogId: String) {
api.getSubCatalogs(catalogId, primaryCatalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SubCatalogViewModel(HaloApp.getInstance().application, catalogId) as T
}
}
}

View File

@ -4,7 +4,6 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.NormalActivity
import com.gh.gamecenter.R

View File

@ -27,21 +27,16 @@ class NewCategoryHorizontalAdapter(context: Context,
override fun onBindViewHolder(holder: TagsViewHolder, position: Int) {
val categoryEntity = mCategoryList[position]
val gradientDrawable = GradientDrawable()
gradientDrawable.shape = GradientDrawable.RECTANGLE
if (mViewModel.selectedCategory.name == categoryEntity.name) {
gradientDrawable.setColor(ContextCompat.getColor(mContext, R.color.theme))
gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat()
holder.tagTv.background = ContextCompat.getDrawable(mContext, R.drawable.bg_tag_text)
holder.tagTv.setTextColor(Color.WHITE)
} else {
gradientDrawable.setColor(Color.WHITE)
gradientDrawable.cornerRadius = DisplayUtils.dip2px(999f).toFloat()
holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_3a3a3a))
holder.tagTv.background = null
holder.tagTv.setTextColor(ContextCompat.getColor(mContext, R.color.text_757575))
}
holder.tagTv.text = categoryEntity.name
holder.tagTv.background = gradientDrawable
holder.tagTv.setOnClickListener {
mViewModel.changeSelectedCategory(categoryEntity)
notifyDataSetChanged()

View File

@ -11,6 +11,7 @@ import com.gh.common.exposure.ExposureType
import com.gh.common.exposure.IExposable
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.StringUtils
import com.gh.common.util.dip2px
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
@ -85,6 +86,9 @@ class NewCategoryListAdapter(context: Context,
holder.initServerType(gameEntity)
holder.binding.executePendingBindings()
val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px()
holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px())
gameEntity.sequence = position + 1
val sortType = if ("download:-1" == mViewModel.getSortType()) "最热" else "最新"

View File

@ -114,6 +114,8 @@ class NewCategoryListFragment : ListFragment<GameEntity, NewCategoryListViewMode
DownloadManager.getInstance(context).removeObserver(mDataWatcher)
}
override fun getItemDecoration() = null
override fun getLayoutId(): Int {
return R.layout.fragment_tags
}

View File

@ -17,7 +17,7 @@ public class DataCollectionDao {
try {
helper = DatabaseHelper.getHelper(context);
dao = helper.getDao(DataCollectionInfo.class);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
}
@ -28,7 +28,7 @@ public class DataCollectionDao {
public List<DataCollectionInfo> findByType(String type) {
try {
return dao.queryForEq("type", type);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
return null;
@ -40,7 +40,8 @@ public class DataCollectionDao {
public void add(DataCollectionInfo entity) {
try {
dao.create(entity);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
// java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:
e.printStackTrace();
}
}
@ -51,7 +52,8 @@ public class DataCollectionDao {
public void delete(String id) {
try {
dao.deleteById(id);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
// java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:
e.printStackTrace();
}
}
@ -62,7 +64,7 @@ public class DataCollectionDao {
public void delete(List<String> ids) {
try {
dao.deleteIds(ids);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
}
@ -73,7 +75,7 @@ public class DataCollectionDao {
public DataCollectionInfo find(String id) {
try {
return dao.queryForId(id);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
return null;
@ -85,7 +87,7 @@ public class DataCollectionDao {
public List<DataCollectionInfo> getAll() {
try {
return dao.queryForAll();
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
return null;
@ -97,7 +99,7 @@ public class DataCollectionDao {
public List<DataCollectionInfo> getClickData() {
try {
return dao.queryForEq("type", "click-item");
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
return null;
@ -109,7 +111,7 @@ public class DataCollectionDao {
public void update(DataCollectionInfo entity) {
try {
dao.update(entity);
} catch (SQLException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
}

View File

@ -1,6 +1,7 @@
package com.gh.gamecenter.db;
import android.content.Context;
import android.database.sqlite.SQLiteException;
import com.gh.gamecenter.db.info.PackageInfo;
import com.j256.ormlite.dao.Dao;
@ -18,7 +19,7 @@ public class FilterDao {
try {
helper = DatabaseHelper.getHelper(context);
dao = helper.getDao(PackageInfo.class);
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
}
@ -31,7 +32,7 @@ public class FilterDao {
if (list != null && list.size() != 0) {
return list.get(0).getTime();
}
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
return 0;
@ -43,7 +44,7 @@ public class FilterDao {
if (filterEntity != null) {
return true;
}
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
return false;
@ -55,7 +56,7 @@ public class FilterDao {
public void add(PackageInfo entity) {
try {
dao.create(entity);
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
}
@ -67,7 +68,7 @@ public class FilterDao {
public void addAll(List<PackageInfo> list) {
try {
dao.create(list);
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
}
@ -75,7 +76,7 @@ public class FilterDao {
public void deleteAll(List<PackageInfo> list) {
try {
dao.delete(list);
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
}
@ -86,7 +87,7 @@ public class FilterDao {
public void delete(String packageName) {
try {
dao.deleteById(packageName);
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
}
@ -97,7 +98,7 @@ public class FilterDao {
public List<PackageInfo> getAll() {
try {
return dao.queryForAll();
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
return null;
@ -109,7 +110,7 @@ public class FilterDao {
public long getCount() {
try {
return dao.countOf();
} catch (SQLException e) {
} catch (SQLiteException | SQLException e) {
e.printStackTrace();
}
return 0;

View File

@ -541,8 +541,6 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
GameEntity gameEntity = new GameEntity(updateEntity.getId(), updateEntity.getName());
gameEntity.setGameVersion(updateEntity.getVersion());
DownloadManager.updateMetaMap();
ExposureEvent event = ExposureUtils.logADownloadExposureEvent(gameEntity, updateEntity.getPlatform(), updateEntity.getExposureEvent(), downloadType);
downloadEntity.setExposureTrace(GsonUtils.toJson(event));

View File

@ -0,0 +1,63 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
@Parcelize
data class CatalogEntity(
@SerializedName("_id")
var id: String = "",
var name: String = "",
var switch: CatalogSwitch = CatalogSwitch(),
@SerializedName("has_special")
var hasSpecial: Boolean = false,
@SerializedName("sub_catalogs")
var subCatalog: List<SubCatalogEntity> = emptyList()
): Parcelable {
@Parcelize
data class SubCatalogEntity(
@SerializedName("_id")
var id: String = "",
var name: String = "",
var icon: String = "",
var type: String = "",
var link: LinkEntity = LinkEntity(),
var recommended: Boolean = false
): Parcelable
@Parcelize
data class CatalogSwitch(
@SerializedName("sort_hot")
var hotSort: String = "",
@SerializedName("sort_new")
var newSort: String = "",
@SerializedName("sort_star")
var starSort: String = ""
): Parcelable
}
@Parcelize
data class SpecialCatalogEntity(
@SerializedName("_id")
var id: String = "",
var type: String = "",
var link: SpecialLink = SpecialLink(),
var image: Image = Image()
): Parcelable {
@Parcelize
data class SpecialLink(
@SerializedName("_id")
var id: String = "",
var data: List<GameEntity> = emptyList()
): LinkEntity(), Parcelable
@Parcelize
data class Image(
var url: String = "",
var title: String = ""
): Parcelable
}

View File

@ -22,13 +22,15 @@ data class CommentEntity(@SerializedName("_id")
var priority: Int = 0,
@SerializedName("me")
var me: MeEntity? = null,
@SerializedName("is_top")
var isTop: Boolean = false,//是否置顶
// 楼数,本地字段
var floor: Int = 0,
@SerializedName("attached") // 楼中楼
var subCommentList: ArrayList<CommentEntity>? = null) : Parcelable {
fun clone() : CommentEntity {
return CommentEntity(id, user, parent, parentUser, content, vote, reply, time, priority, me, floor, subCommentList)
fun clone(): CommentEntity {
return CommentEntity(id, user, parent, parentUser, content, vote, reply, time, priority, me, isTop, floor, subCommentList)
}
companion object {

View File

@ -17,7 +17,8 @@ data class FollowersOrFansEntity(
data class Count(
val vote: Int = 0,
val answer: Int = 0)
val answer: Int = 0,
val fans :Int= 0)
}

View File

@ -8,8 +8,9 @@ data class ForumEntity(
var game: SimpleGame = SimpleGame(),
var name: String = "",
@SerializedName("is_follow")
var isFollow: Boolean = false
var isFollow: Boolean = false,
//本地字段,判断是否是推荐论坛
var isRecommend: Boolean = false
)
data class ForumCategoryEntity(

View File

@ -223,8 +223,10 @@ data class GameEntity(
@SerializedName("is_recently_played")
var isRecentlyPlayed: Boolean = false,
var active: Boolean = true,
@SerializedName("package_dialog")
val packageDialog: PackageDialogEntity? = null,
// 本地字段,使用镜像信息
// 本地字段,使用镜像信息
var useMirrorInfo: Boolean = false,
// 从启动弹窗跳转到对应游戏列表时候记录的启动弹窗数据 (ugly ugly ugly)
var welcomeDialogId: String? = null,

View File

@ -65,6 +65,18 @@ class MessageUnreadEntity {
@SerializedName("game_comment_reply_vote")
var gameCommentReplyVote = 0
@SerializedName("activity_comment")
var activityComment = 0
@SerializedName("reply_activity_comment")
var replyActivityComment = 0
@SerializedName("activity_comment_vote")
var activityCommentVote = 0
@SerializedName("activity_comment_reply_vote")
var activityCommentReplyVote = 0
var fans: Int = 0 // 与其他未读区分 用于我的主页
var meta: Meta? = null
@ -84,8 +96,7 @@ class MessageUnreadEntity {
tryWithDefaultCatch {
val fields = this.javaClass.declaredFields
for (field in fields) {
// TODO 处理 vote 可能不是 int 的情况
if (field.name.toLowerCase(Locale.getDefault()).contains("vote")) {
if (field.name.toLowerCase(Locale.getDefault()).contains("vote") && field.type == Integer.TYPE) {
voteCount += field.getInt(this)
}
}
@ -99,8 +110,7 @@ class MessageUnreadEntity {
tryWithDefaultCatch {
for (field in fields) {
// TODO 处理 vote 可能不是 int 的情况
if (field.name.toLowerCase(Locale.getDefault()).contains("vote")) {
if (field.name.toLowerCase(Locale.getDefault()).contains("vote") && field.type == Integer.TYPE) {
field.setInt(this, 0)
}
}

View File

@ -0,0 +1,44 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
@Parcelize
data class PackageDialogEntity(
val title: String = "",
val content: String = "",
@SerializedName("detection_objects")
val detectionObjects: ArrayList<DetectionObjectEntity> = arrayListOf(),
@SerializedName("link_hint_text")
val linkHintText: String = "",
val links: ArrayList<PackageLink> = arrayListOf(),
val level: String = "HINT_SKIP"// 弹窗级别HINT_SKIP(提示且跳转)、ALWAYS_HINT(仅提示(每次提示))、OPTIONAL_HINT(仅提示(可不再提示))
) : Parcelable
@Parcelize
data class DetectionObjectEntity(
val text: String = "",
val packages: ArrayList<String> = arrayListOf()
) : Parcelable
@Parcelize
data class PackageLink(
val text: String = "",
@SerializedName("link_type")
val linkType: String = "",
@SerializedName("link_id")
val linkId: String = "",
@SerializedName("link_text")
val linkText: String = "",
@SerializedName("button_link")
val buttonLink: Boolean = false
) : Parcelable {
fun transform(): LinkEntity {
val entity = LinkEntity()
entity.linkText = linkText
entity.type = linkType
entity.link = linkId
return entity
}
}

View File

@ -29,7 +29,10 @@ data class PersonalHistoryEntity(
val images: List<String> = ArrayList(),
val me: MeEntity = MeEntity(),
var comment: Comment = Comment(),
var commentable: Boolean = true) : Parcelable {
var commentable: Boolean = true,
@SerializedName("is_edit")
var isEdit: Boolean = false
) : Parcelable {
fun getPassVideos(): List<CommunityVideoEntity> {
val passVideos = arrayListOf<CommunityVideoEntity>()

View File

@ -26,7 +26,7 @@ data class PrivacyPolicyEntity(
permissions.add(PermissionsEntity(
icon = "res:///" + R.drawable.permission_phone_state,
name = "设备信息",
intro = "获取设备型号等信息,保证功能的适配与完整性"))
intro = "为保障您的账号安全及使用软件与服务可安全运行"))
// permissions.add(PermissionsEntity(
// icon = "res:///" + R.drawable.permission_sdk,
// name = "第三方SDK使用信息提醒",

View File

@ -32,7 +32,9 @@ data class SettingsEntity(
@SerializedName("game_dome_switch")
var gameDomeSwitch: String = "",//试玩显示开关on打开
@SerializedName("permission_popup_switch")
var permissionPopupSwitch: String = "off"//权限引导弹窗开关on/off
var permissionPopupSwitch: String = "off",//权限引导弹窗开关on/off
@SerializedName("permission_popup_applied_versions")
var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions()
) {
fun setCommunityEntrance(communityEntrance: String) {
@ -211,4 +213,10 @@ data class SettingsEntity(
var display: Display? = Display()
)
data class PermissionPopupAppliedVersions(
val install: ArrayList<String> = arrayListOf(),
@SerializedName("xapk_unzip")
val xapkUnzip: ArrayList<String> = arrayListOf()
)
}

View File

@ -43,7 +43,7 @@ data class SubjectSettingEntity(
@Parcelize
data class Size(var min: Int? = -1,
var max: Int? = -1,
var text: String? = "") : Parcelable
var text: String? = "全部大小") : Parcelable
}

View File

@ -0,0 +1,5 @@
package com.gh.gamecenter.eventbus;
public class EBCommentSuccess {
}

View File

@ -66,11 +66,11 @@ class ForumArticleAskListAdapter(context: Context, val bbsId: String, val mEntra
val binding = answerViewHolder.binding
binding.forumNameLl.visibility = View.GONE
val params = binding.includeVoteAndComment.layoutParams as LinearLayout.LayoutParams
val params = binding.includeVoteAndComment.root.layoutParams as LinearLayout.LayoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.leftMargin = 0
params.rightMargin = 0
binding.includeVoteAndComment.layoutParams = params
binding.includeVoteAndComment.root.layoutParams = params
answerViewHolder.bindForumAnswerItem(answer, mEntrance, path)
answerViewHolder.itemView.setOnClickListener {

Some files were not shown because too many files have changed in this diff Show More