Merge remote-tracking branch 'origin/dev' into dev-5.20.0

This commit is contained in:
chenjuntao
2023-02-09 10:33:20 +08:00
19 changed files with 173 additions and 59 deletions

View File

@ -1,6 +1,7 @@
package com.gh.common.filter
import androidx.annotation.Keep
import com.gh.gamecenter.feature.entity.IpInfo
import com.google.gson.annotations.SerializedName
@Keep
@ -14,7 +15,9 @@ class RegionSetting(
@SerializedName("game_h5_download")
var gameH5DownloadList: List<GameH5Download>,
@SerializedName("game_special_download")
var gameSpecialDownloadInfoList: List<GameSpecialDownloadInfo>
var gameSpecialDownloadInfoList: List<GameSpecialDownloadInfo>,
@SerializedName("ip_info")
var ipInfo: IpInfo? = null
) {
@Keep

View File

@ -9,6 +9,7 @@ import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.IpInfo
import com.gh.gamecenter.feature.entity.SimpleGame
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
@ -22,6 +23,7 @@ object RegionSettingHelper {
private var mDisplayMirrorIfoGameIdSet: HashSet<String>? = hashSetOf()
private var mGameH5DownloadList: List<RegionSetting.GameH5Download>? = listOf()
private var mGameSpecialDownloadInfoList: List<RegionSetting.GameSpecialDownloadInfo>? = listOf()
private var mIpInfo: IpInfo? = null
private const val SP_SETTING = "region_setting"
const val SP_SETTING_FAILURE = "region_setting_failure"
@ -41,6 +43,8 @@ object RegionSettingHelper {
@JvmStatic
fun getGameSpecialDownloadInfo(gameId: String) = mGameSpecialDownloadInfoList?.find { it.gameId == gameId }
fun getIpInfo(): IpInfo? = mIpInfo
@JvmStatic
fun filterGame(list: List<GameEntity>?): ArrayList<GameEntity> {
if (list == null) return arrayListOf()
@ -118,6 +122,7 @@ object RegionSettingHelper {
mChannelControl = data.channelControl
mGameH5DownloadList = data.gameH5DownloadList
mGameSpecialDownloadInfoList = data.gameSpecialDownloadInfoList
mIpInfo = data.ipInfo
}
/**

View File

@ -5,10 +5,11 @@ import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.IpInfo
import com.gh.gamecenter.feature.provider.IRegionSettingHelperProvider
@Route(path = RouteConsts.provider.regionSettingHelper, name = "RegionSettingHelper暴露服务")
class RegionSettingHelperProviderImpl: IRegionSettingHelperProvider {
class RegionSettingHelperProviderImpl : IRegionSettingHelperProvider {
override fun shouldThisGameDisplayMirrorInfo(gameId: String): Boolean {
return RegionSettingHelper.shouldThisGameDisplayMirrorInfo(gameId)
}
@ -21,6 +22,10 @@ class RegionSettingHelperProviderImpl: IRegionSettingHelperProvider {
return RegionSettingHelper.filterGame(list)
}
override fun getIpInfo(): IpInfo? {
return RegionSettingHelper.getIpInfo()
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.common.json.JsonObjectBuilder
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.loghub.LoghubUtils
@ -541,10 +542,28 @@ object NewFlatLogUtils {
log(json)
}
//进入游戏详情/离开游戏详情
fun logGameDetailEnterOrExit(event: String, gameName: String, gameId: String) {
//进入游戏详情
fun logGameDetailEnter(gameName: String, gameId: String, isMirrorData: Boolean) {
val ipInfo = RegionSettingHelper.getIpInfo()
val json = json {
KEY_EVENT to event
KEY_EVENT to "game_detail_enter"
KEY_GAME_NAME to gameName
KEY_GAME_ID to gameId
"is_mirror_data" to isMirrorData
if (ipInfo != null) {
"country" to ipInfo.country
"province" to ipInfo.province
"city" to ipInfo.city
}
parseAndPutMeta().invoke(this)
}
log(json)
}
//离开游戏详情
fun logGameDetailExit(gameName: String, gameId: String) {
val json = json {
KEY_EVENT to "game_detail_exit"
KEY_GAME_NAME to gameName
KEY_GAME_ID to gameId
parseAndPutMeta().invoke(this)

View File

@ -7,6 +7,7 @@ import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.throwException
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.core.utils.MD5Utils
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
@ -53,8 +54,9 @@ class XapkUnzipThread(
val outputFile = if (zipEntry.name.getExtension() == XapkInstaller.XAPK_DATA_EXTENSION_NAME) {
File(absolutePath + File.separator + zipEntry.name)
} else if (zipEntry.name.getExtension() == XapkInstaller.PACKAGE_EXTENSION_NAME) {
// apk文件名称 = xapk文件名+本身的文件名称
val fileName = xapkFile.nameWithoutExtension + "_" + zipEntry.name
// apk文件名称 = xapk文件名 + MD5(本身的文件名称) + ".apk"
// 如 abc_com.gh.gamecenter.apk 这样的文件名,在使用浏览器安装时系统浏览器可能会抹掉文件类型,导致无法唤起下载完自动安装,这里去掉多个 "." 号,保证浏览器安装正常使用
val fileName = xapkFile.nameWithoutExtension + "_" + MD5Utils.getContentMD5(zipEntry.name) + "." + XapkInstaller.PACKAGE_EXTENSION_NAME
File(FileUtils.getDownloadPath(HaloApp.getInstance().application, fileName))
} else continue // 暂时只需要解压xpk/obb文件

View File

@ -54,6 +54,7 @@ class GameHeadViewHolder(var binding: GameHeadItemBinding) :
&& subject.type != "column_collection"
&& subject.type != "gallery_slide"
&& subject.type != "game_list_collection"
&& subject.type != "top_game_comment"
) {
binding.headMore.visibility = View.GONE
} else if (subject.home == "hide") {

View File

@ -157,6 +157,16 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
viewHolder.binding.dmItemTvTitle.postDelayed(() -> viewHolder.binding.dmItemTvTitle.setSelected(true), 2000);
}
if (downloadEntity.getUrl().equals(url)) {
viewHolder.binding.getRoot().setBackgroundColor(ContextCompat.getColor(mContext, R.color.select));
} else {
viewHolder.binding.getRoot().setBackgroundResource(R.drawable.reuse_listview_item_style);
}
viewHolder.binding.getRoot().setOnLongClickListener(v -> {
showDeleteDialog(viewHolder.binding.dmItemTvStartorpause, downloadEntity, viewHolder.getPosition());
return true;
});
DownloadStatus status = downloadEntity.getStatus();
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
if (status.equals(DownloadStatus.done)) {
@ -334,17 +344,6 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
}
// DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "下载管理", "游戏下载", str);
});
if (downloadEntity.getUrl().equals(url)) {
viewHolder.binding.getRoot().setBackgroundColor(ContextCompat.getColor(mContext, R.color.select));
} else {
viewHolder.binding.getRoot().setBackgroundResource(R.drawable.reuse_listview_item_style);
}
viewHolder.binding.getRoot().setOnLongClickListener(v -> {
showDeleteDialog(viewHolder.binding.dmItemTvStartorpause, downloadEntity, viewHolder.getPosition());
return true;
});
} else if (holder instanceof DownloadHeadViewHolder) {
final DownloadHeadViewHolder viewHolder = (DownloadHeadViewHolder) holder;

View File

@ -3,7 +3,6 @@ package com.gh.gamecenter.game.horizontal
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.NewLogUtils
@ -16,6 +15,7 @@ import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toPx
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.download.DownloadEntity
@ -110,13 +110,13 @@ class GameHorizontalAdapter(
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
gameEntity.id,
entranceResult,
exposureEventList?.get(position)
)
}
if (mSubjectEntity.showDownload) {
if (mSubjectEntity.showDownload && type != GameHorizontalListType.GameDetailHorizontalType) {
DownloadItemUtils.setOnClickListener(
mContext,
holder.binding.simpleGameContainer.downloadBtn,

View File

@ -101,6 +101,7 @@ import java.lang.ref.WeakReference
import java.util.*
import kotlin.math.abs
// TODO 更改现有的使用 INDEX_DESC, INDEX_BBS 等固定数值来确定 tab 位置的做法,避免后续更改 tab 位置出现奇怪的异常
class GameDetailFragment : ToolbarFragment(), IScrollable {
private var mDownloadMenuIcon: ImageView? = null
@ -697,10 +698,10 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
if (mEntrance.contains(EntranceConsts.ENTRANCE_WELCOME) && mEntrance.countOccurrences("+") <= 1) {
mGameEntity?.setWelcomeDialogInfoIfAvailable()
}
NewFlatLogUtils.logGameDetailEnterOrExit(
"game_detail_enter",
NewFlatLogUtils.logGameDetailEnter(
mGameEntity?.name ?: "",
mGameEntity?.id ?: ""
mGameEntity?.id ?: "",
mGameEntity?.shouldUseMirrorInfo() ?: false
)
} else if (gameResource.status == Status.ERROR) {
loadErrorControl(gameResource.exception)
@ -1798,11 +1799,11 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private fun logTabClick(position: Int) {
val entrance = if (mEntrance.contains("论坛详情")) "论坛" else "游戏"
mGameEntity?.run {
when (position) {
INDEX_DESC -> {
when (getTabContentForReal(position)) {
TAB_DESC -> {
NewLogUtils.logGameDetailTabClick(name ?: "", id, "详情")
}
INDEX_TRENDES -> {
TAB_TRENDS -> {
NewLogUtils.logGameDetailTabClick(
"view_game_detail_special_area_tab",
entrance,
@ -1812,24 +1813,46 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
)
NewLogUtils.logGameDetailTabClick(name ?: "", id, "专区")
}
INDEX_ARCHIVE -> {
TAB_ARCHIVE -> {
NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
"cloud_save_tab_click",
mGameEntity?.id ?: "",
mGameEntity?.name ?: ""
)
}
INDEX_RATING -> {
TAB_RATING -> {
NewLogUtils.logGameDetailTabClick("view_game_detail_comment_tab", entrance, id, gameType, bbsId)
NewLogUtils.logGameDetailTabClick(name ?: "", id, "评论")
}
INDEX_BBS -> {
TAB_BBS -> {
NewLogUtils.logGameDetailTabClick(name ?: "", id, "论坛")
}
}
}
}
/**
* 获取真实的 tab 内容类型
* @param position tab 的位置
* @return 真实的
*/
private fun getTabContentForReal(position: Int): String {
return when (mTabTitleList[position]) {
getString(R.string.game_detail_dongtai),
mNewGameDetailEntity?.zone?.customName -> TAB_TRENDS
getString(R.string.game_detail_cloud_archive) -> TAB_ARCHIVE
getString(R.string.game_detail_comment) -> TAB_RATING
getString(R.string.game_detail_bbs) -> TAB_BBS
getString(R.string.game_detail_desc) -> TAB_DESC
else -> TAB_DESC
}
}
private fun handleTabTouchEvent(title: String) {
if (title == mTabClickEvent.second && System.currentTimeMillis() - mTabClickEvent.first < 300) {
val fragment = mFragmentsList[mBodyBinding.gamedetailVp.currentItem]
@ -2109,11 +2132,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
override fun onParentActivityFinish() {
NewFlatLogUtils.logGameDetailEnterOrExit(
"game_detail_exit",
mGameEntity?.name ?: "",
mGameEntity?.id ?: ""
)
NewFlatLogUtils.logGameDetailExit(mGameEntity?.name ?: "", mGameEntity?.id ?: "")
}
override fun onDestroy() {
@ -2252,6 +2271,13 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
const val INDEX_ARCHIVE = 2
const val INDEX_RATING = 3
const val INDEX_BBS = 4
const val TAB_DESC = "详情"
const val TAB_TRENDS = "专区"
const val TAB_ARCHIVE = "云存档"
const val TAB_RATING = "评价"
const val TAB_BBS = "论坛"
const val SKIP_DESC = "skipDesc"
const val SKIP_FULI = "skipFuli"
const val SKIP_RATING = "skipRatting"

View File

@ -952,7 +952,12 @@ class DescAdapter(
setShrankTextAndExpandedText(shrankSpanned, expandedSpanned)
}
goneIf(TextUtils.isEmpty(customColumn.des))
setSelfCalculateMaxLinesCallback { mExpandableTextViewMaxLinesSparseIntArray.put(position, it) }
setSelfCalculateMaxLinesCallback {
mExpandableTextViewMaxLinesSparseIntArray.put(position, it)
if (maxDesLines != it) {
post { notifyItemChanged(position) }
}
}
setExpandCallback {
mExpandableTextExpandStatusSparseBooleanArray.put(position, true)
if (customColumn.name == "游戏简介") {

View File

@ -103,6 +103,7 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
}
mReadyReplyData = it
mBaseHandler.postDelayed({
popInputLayout(true)
showKeyboard(true)
}, 100)
})
@ -154,6 +155,7 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
replyTv.setDebouncedClickListener {
mReadyReplyData = null
mInputBinding.answerCommentEt.hint = "回复 @${mListViewModel.comment?.user?.name}"
popInputLayout(true)
showKeyboard(true)
logGameDetailCommentDetailCommentClick("回复评价")
}
@ -209,11 +211,13 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
})
if (intent?.getBooleanExtra(EntranceConsts.KEY_OPEN_KEYBOARD, false) == true) {
popInputLayout(true)
showKeyboard(true)
}
mKeyboardHeightProvider = KeyboardHeightProvider(this)
mListRv.post { mKeyboardHeightProvider?.start() }
mBinding.shadowView.setOnClickListener {
popInputLayout(false)
showKeyboard(false)
}
}
@ -232,6 +236,7 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
successCallback = {
mInputBinding.answerCommentEt.setText("")
mInputBinding.answerCommentEt.clearFocus()
popInputLayout(false)
showKeyboard(false)
}
) { mInputBinding.answerCommentSendBtn.performClick() }
@ -342,10 +347,16 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
}
override fun onKeyboardHeightChanged(height: Int, orientation: Int) {
popInputLayout(height > 0, height)
if (height <= 0) {
mOffset = abs(height)
}
val mLayoutParams = mInputBinding.answerCommentContentContainer.layoutParams as RelativeLayout.LayoutParams
mLayoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT
mLayoutParams.bottomMargin = if (height > 0) height + mOffset else 0
mInputBinding.answerCommentContentContainer.layoutParams = mLayoutParams
}
private fun popInputLayout(isPopup: Boolean, height: Int) {
private fun popInputLayout(isPopup: Boolean) {
mInputPlaceholderBinding.root.goneIf(isPopup)
mInputBinding.root.goneIf(!isPopup)
mInputBinding.commentLine.goneIf(isPopup)
@ -356,7 +367,6 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
ContextCompat.getDrawable(this, R.drawable.bg_shape_white_radius_10_top_only)
} else {
mInputBinding.answerContent.setBackgroundColor(ContextCompat.getColor(this, R.color.background_white))
mOffset = abs(height)
}
DisplayUtils.setLightStatusBar(this, !isPopup && !mIsDarkModeOn)
@ -367,11 +377,6 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
mScrollViewParams.height = if (isPopup) 76f.dip2px() else 28f.dip2px()
mScrollViewParams.topMargin = if (isPopup) 8f.dip2px() else 0
mInputBinding.scrollView.layoutParams = mScrollViewParams
val mLayoutParams = mInputBinding.answerCommentContentContainer.layoutParams as RelativeLayout.LayoutParams
mLayoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT
mLayoutParams.bottomMargin = if (isPopup) height + mOffset else 0
mInputBinding.answerCommentContentContainer.layoutParams = mLayoutParams
}
private fun showKeyboard(isShow: Boolean) {

View File

@ -273,10 +273,6 @@ class RatingReplyAdapter(
likeCountTv.setDrawableStart(R.drawable.comment_vote_unselect)
}
likeCountTv.text = if (replyEntity.vote > 0) NumberUtils.transSimpleCount(replyEntity.vote) else ""
contentTv.setTextWithHighlightedTextWrappedInsideWrapper(
text = replyEntity.content,
copyClickedText = true
)
userIconIv.display(
replyEntity.user.border,
replyEntity.user.icon,
@ -292,6 +288,7 @@ class RatingReplyAdapter(
badgeTv.visibility = View.GONE
}
val parent = replyEntity.parent
var contentCharSequence: CharSequence = replyEntity.content
if (parent != null) {
val prefix = "回复"
val colon = " "
@ -321,14 +318,17 @@ class RatingReplyAdapter(
R.color.text_title
).build()
contentTv.text = SpannableStringBuilder()
contentCharSequence = SpannableStringBuilder()
.append(prefixSpan)
.append(parentUserNameSpan)
.append(colonSpan)
.append(replyEntity.content)
} else {
contentTv.text = replyEntity.content
}
contentTv.setTextWithHighlightedTextWrappedInsideWrapper(
text = contentCharSequence,
copyClickedText = true
)
badgeIv.setOnClickListener {
DialogUtils.showViewBadgeDialog(mContext, replyEntity.user.badge, object : ConfirmListener {
override fun onConfirm() {

View File

@ -772,10 +772,10 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
mSnapshotItemList.add(homeItemData)
mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
mDiscoveryGameCard?.games?.forEach {
addGamePositionAndPackage(it)
}
mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
}
} else {
val unknown = HomeItemData()

View File

@ -129,7 +129,7 @@ object VHelper {
VArchiveHelper.init()
val config = Config.getVSettingEntity()?.va
if (config?.arch64 != null && PackageUtils.isInstalled(context, config.arch64.packageName)) {
if (config?.arch64 != null && PackageUtils.isInstalledFromAllPackage(context, config.arch64.packageName)) {
if (isVIsUsed()) {
connectService(true)
}
@ -222,7 +222,7 @@ object VHelper {
*/
fun isVSpaceInstalled(context: Context): Boolean {
val config = Config.getVSettingEntity()?.va
return config?.arch64 != null && PackageUtils.isInstalled(context, config.arch64.packageName)
return config?.arch64 != null && PackageUtils.isInstalledFromAllPackage(context, config.arch64.packageName)
}
/**
@ -710,7 +710,7 @@ object VHelper {
}
// TODO 检测 32 位
if (!PackageUtils.isInstalled(context, vaConfig.arch64?.packageName)) {
if (!PackageUtils.isInstalledFromAllPackage(context, vaConfig.arch64?.packageName)) {
VSpaceDialogFragment.showDownloadDialog(context, getVSpaceDownloadEntity(false))
Utils.log(LOG_TAG, "显示下载畅玩空间弹窗")
return true