Compare commits

...

62 Commits

Author SHA1 Message Date
5de629cfdd feat: 更新插件1.0.3 正式版本 url 2024-10-17 15:42:59 +08:00
f026623600 Merge branch 'refactor/sync-va' into 'dev'
chore: va组件升级到2.0.6

See merge request halo/android/assistant-android!1937
2024-10-17 11:24:35 +08:00
2f5ee0eb91 chore: va组件升级到2.0.6
refactor: update commit id
2024-10-17 11:24:12 +08:00
e7651e8092 Merge branch 'feat/GHZSCY-6708-patch' into 'dev'
feat: CPM微信小游戏API接入兼容OkHttp 4.x

See merge request halo/android/assistant-android!1936
2024-10-17 11:23:47 +08:00
82d51d6375 feat: CPM微信小游戏API接入兼容OkHttp 4.x 2024-10-17 11:23:24 +08:00
6080edfd8a Merge branch 'feat/GHZSCY-6708' into 'dev'
feat: CPM微信小游戏API接入工作—客户端 https://jira.shanqu.cc/browse/GHZSCY-6708

See merge request halo/android/assistant-android!1911
2024-10-17 10:17:19 +08:00
d9713571c9 feat: CPM微信小游戏API接入工作—客户端 https://jira.shanqu.cc/browse/GHZSCY-6708 2024-10-17 10:17:19 +08:00
b466525e8b Merge branch 'feat/GHZSCY-6790' into 'dev'
feat: 更新 OkHttp 至 4.X 最新版本并启用 brotli 压缩 https://jira.shanqu.cc/browse/GHZSCY-6790

See merge request halo/android/assistant-android!1935
2024-10-16 16:56:07 +08:00
2a25675dce feat: 更新 OkHttp 至 4.X 最新版本并启用 brotli 压缩 https://jira.shanqu.cc/browse/GHZSCY-6790 2024-10-16 16:56:06 +08:00
5486ad8818 Merge branch 'fix/home_appbar_style' into 'dev'
fix: 修复多tab导航页在无Tab样式下AppBar变色异常的问题

See merge request halo/android/assistant-android!1934
2024-10-16 13:47:17 +08:00
5552fcf7bc Merge branch 'fix/stop_banner_play_on_pause' into 'dev'
fix: 修复部分轮播图没有在页面暂停时停止播放的问题

See merge request halo/android/assistant-android!1933
2024-10-16 13:47:10 +08:00
782a0af13c fix: 修复多tab导航页在无Tab样式下AppBar变色异常的问题 2024-10-16 11:44:44 +08:00
c6c2d9cd12 fix: 修复部分轮播图没有在页面暂停时停止播放的问题 2024-10-16 10:09:51 +08:00
f929a08e46 Merge branch 'fix/GHZSCY-6685' into 'dev'
fix: 修复 Fresco 不能根据 ViewPager/ViewPager2 页面可见性变更动图播放状态的问题 https://jira.shanqu.cc/browse/GHZSCY-6685

See merge request halo/android/assistant-android!1930
2024-10-15 18:16:41 +08:00
e48f96d7d7 fix: 修复 Fresco 不能根据 ViewPager/ViewPager2 页面可见性变更动图播放状态的问题 https://jira.shanqu.cc/browse/GHZSCY-6685 2024-10-15 18:16:41 +08:00
3cc95dbc08 Merge branch 'fix/system-properties-sensitive' into 'dev'
fix: 修复xcrash敏感行为【读取系统属性】

See merge request halo/android/assistant-android!1929
2024-10-15 15:08:29 +08:00
f75396d7ae fix: 修复xcrash敏感行为【读取系统属性】 2024-10-15 15:07:57 +08:00
72c3df7fa6 Merge branch 'fix/GHZSCY-6773' into 'dev'
fix:【光环助手】游戏专题-右上角显示问题 https://jira.shanqu.cc/browse/GHZSCY-6773

See merge request halo/android/assistant-android!1928
2024-10-15 09:35:38 +08:00
2d4920cfb0 fix:【光环助手】游戏专题-右上角显示问题 https://jira.shanqu.cc/browse/GHZSCY-6773 2024-10-15 09:31:13 +08:00
2d30b97cca Merge branch 'fix/hiddenapibypass-bug' into 'dev'
fix: 更新hiddenapibypass库,观察native crash的hiddenapi相关问题是否解决。

See merge request halo/android/assistant-android!1927
2024-10-14 17:09:30 +08:00
40346e3c9a fix: 更新hiddenapibypass库,观察native crash的hiddenapi相关问题是否解决。 2024-10-14 17:08:20 +08:00
7f601c856a Merge branch 'fix/illegal_state_exception' into 'dev'
fix: 尝试修复游戏专题合集详情页闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/388936

See merge request halo/android/assistant-android!1924
2024-10-12 11:36:49 +08:00
6e56f2e3a0 fix: 尝试修复游戏专题合集详情页闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/388936 2024-10-12 10:40:26 +08:00
e2fbda1e4c Merge branch 'fix/GHZSCY-6778' into 'dev'
fix: 分类页面展示异常 https://jira.shanqu.cc/browse/GHZSCY-6778

See merge request halo/android/assistant-android!1921
2024-10-11 16:45:57 +08:00
1e88ba8539 fix: 分类页面展示异常 https://jira.shanqu.cc/browse/GHZSCY-6778 2024-10-11 15:40:03 +08:00
0f43b5610d Merge branch 'feat/GHZSCY-6474' into 'dev'
feat: 【光环助手】搜索榜单的神策埋点问题 https://jira.shanqu.cc/browse/GHZSCY-6747

See merge request halo/android/assistant-android!1920
2024-10-11 15:10:51 +08:00
04dcfbab2e feat: 【光环助手】搜索榜单的神策埋点问题 https://jira.shanqu.cc/browse/GHZSCY-6747 2024-10-11 15:10:51 +08:00
8dd33cb599 Merge branch 'fix/GHZSCY-6777' into 'dev'
fix: 【光环助手】进入QA详情页埋点上报问题 https://jira.shanqu.cc/browse/GHZSCY-6777

See merge request halo/android/assistant-android!1917
2024-10-11 15:02:10 +08:00
af5826962b fix: 【光环助手】进入QA详情页埋点上报问题 https://jira.shanqu.cc/browse/GHZSCY-6777 2024-10-11 15:02:10 +08:00
9883f8d5c0 Merge branch 'fix/GHZSCY-6772' into 'dev'
fix: 分流器-验收问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6772

See merge request halo/android/assistant-android!1918
2024-10-11 15:01:59 +08:00
848207784e fix: 分流器-验收问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6772 2024-10-11 15:01:59 +08:00
fc294f9e7b Merge branch 'revert/GHZSCY-5572' into 'dev'
Revert: 搜索业务-新增搜索发现取代热门标签—客户端 https://jira.shanqu.cc/browse/GHZSCY-5572

See merge request halo/android/assistant-android!1916
2024-10-09 17:00:42 +08:00
96cd53a2c9 Revert: 搜索业务-新增搜索发现取代热门标签—客户端 https://jira.shanqu.cc/browse/GHZSCY-5572 2024-10-09 17:00:42 +08:00
5458c93475 fix: 处理合并冲突
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-10-09 15:53:40 +08:00
675d63c1d6 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	.gitlab-ci.yml
#	app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt
#	dependencies.gradle
#	vasdk
2024-10-09 15:34:08 +08:00
1040f5ff4d Merge branch 'sentry/407275' into 'release'
fix: Sentry 407275 修复Z10机型报BadTokenException的异常

See merge request halo/android/assistant-android!1915
2024-10-09 14:56:18 +08:00
97be320529 fix: Sentry 407275 修复Z10机型报BadTokenException的异常 2024-10-09 14:56:18 +08:00
0e086c9452 Merge branch 'fix/va-some-npe' into 'dev'
fix: 修复sentry捕获异常。

See merge request halo/android/assistant-android!1914
2024-10-09 14:13:09 +08:00
dc677d1b9f fix: 修复sentry捕获异常。
1.https://sentry.shanqu.cc/organizations/lightgame/issues/396947/?project=22
2.https://sentry.shanqu.cc/organizations/lightgame/issues/398572/events/0d99a320eee243efa7089b59cb10219c/?project=22
3.https://sentry.shanqu.cc/organizations/lightgame/issues/382462/events/30a62c7d5e0a40df80f36ff25b325728/?project=22
4.https://sentry.shanqu.cc/organizations/lightgame/issues/407819/?project=22
5.https://sentry.shanqu.cc/organizations/lightgame/issues/397248/?project=22
2024-10-09 14:10:54 +08:00
fa50c6e417 Merge branch 'fix/crashes' into 'dev'
修复Sentry闪退问题

See merge request halo/android/assistant-android!1913
2024-10-09 14:04:48 +08:00
dc96f2274f fix: 修复启动时QQ小游戏获取WebView的默认UserAgent导致的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/352547/?project=22 2024-10-09 11:32:36 +08:00
ad5f5048a6 Merge branch 'fix/auto-login-crash' into 'dev'
fix:自动登录页面闪退

See merge request halo/android/assistant-android!1912
2024-10-09 11:20:24 +08:00
e5491fb297 fix:自动登录页面闪退 2024-10-09 11:20:24 +08:00
ff96eaafee fix: 修复获取统计数据时出现的空指针闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/387745/?project=22 2024-10-08 17:33:43 +08:00
da0ace0aa6 Merge branch 'fix/get_packagename_culprit' into 'dev'
fix: 修复多线程同时请求已安装包名列表的问题

See merge request halo/android/assistant-android!1909
2024-09-27 14:14:41 +08:00
11a2d7aa53 fix: 修复因为获取已安装包名延迟造成的下载按钮状态更新问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-09-27 10:04:09 +08:00
d3444918dd fix: 修复多线程同时请求已安装包名列表的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-09-27 10:04:09 +08:00
59cde4e2bf Merge branch 'hotfix/v5.37.5-1095/privacy-policy' into 'release'
feat: 优化获取进程名的方式 https://jira.shanqu.cc/browse/GHZSCY-6690

See merge request halo/android/assistant-android!1898
2024-09-20 10:56:40 +08:00
cc0c7c7fae feat: 优化获取进程名的方式 https://jira.shanqu.cc/browse/GHZSCY-6690 2024-09-20 10:32:29 +08:00
9e9ce6a84f Merge branch 'hotfix/v5.37.5-1095/download_ad_crash' into 'release'
fix: 修复下载管理展示第三方广告失败回落展示自有广告时出现的闪退问题...

See merge request halo/android/assistant-android!1895
2024-09-14 17:23:26 +08:00
7d0b500ff9 fix: 修复下载管理展示第三方广告失败回落展示自有广告时出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/409586/?project=22 2024-09-14 17:13:23 +08:00
425456b263 Merge branch 'feat/v5.37.5-1095/va-2.0.5' into 'release'
Feat/v5.37.5 1095/va 2.0.5

See merge request halo/android/assistant-android!1890
2024-09-11 17:08:07 +08:00
f6abab9a2d Revert "chore: 组件升级 2.0.5-debug" 2024-09-11 17:05:56 +08:00
d194f969e4 chore: va组件2.0.5-debug 2024-09-10 16:43:57 +08:00
95f66344fb chore: va组件2.0.5 2024-09-10 13:46:15 +08:00
570e2fa9bc Revert "feat:同步商业版代码至:dbc3b8ecaca3e774b1e63f41e70b651f4acfaee1"
This reverts commit 811d42457c.
2024-09-05 15:22:32 +08:00
9e07080043 feat: 调整依赖源顺序 2024-09-04 17:03:37 +08:00
e10a329159 chore: 版本更新至 5.37.5 2024-09-04 16:00:00 +08:00
b3bc7b43f7 Merge branch 'feat/v5.37.5-1095/update-va' into 'release'
feat:同步商业版代码至:dbc3b8ecaca3e774b1e63f41e70b651f4acfaee1

See merge request halo/android/assistant-android!1875
2024-09-04 15:54:34 +08:00
811d42457c feat:同步商业版代码至:dbc3b8ecaca3e774b1e63f41e70b651f4acfaee1 2024-09-04 15:52:46 +08:00
ac0b819ea9 Merge branch 'feat/GHZSCY-6644' into 'release'
feat: 【光环助手】安装相关优化功能埋点事件的属性字段英文错误的问题 https://jira.shanqu.cc/browse/GHZSCY-6644

See merge request halo/android/assistant-android!1874
2024-09-04 15:43:47 +08:00
d931fb5940 feat: 【光环助手】安装相关优化功能埋点事件的属性字段英文错误的问题 https://jira.shanqu.cc/browse/GHZSCY-6644 2024-09-04 14:42:17 +08:00
158 changed files with 1855 additions and 680 deletions

View File

@ -101,6 +101,8 @@ android {
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT}\""
buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "WGAME_CPM_BUSIAPPID", "\"${WGAME_CPM_BUSIAPPID}\""
buildConfigField "String", "WGAME_CPM_API_HOST", "\"${WGAME_CPM_API_HOST}\""
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""

View File

@ -256,7 +256,7 @@ class DefaultJsApi(
@JavascriptInterface
fun isInstalled(event: Any): String {
val localInstalledPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
val localInstalledPackageList = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
val packageNameList: ArrayList<String> = event.toString().toObject() ?: ArrayList()
for (packageName in packageNameList) {
@ -555,7 +555,7 @@ class DefaultJsApi(
@JavascriptInterface
fun getInstallStatus(event: Any): String {
val localInstalledPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
val localInstalledPackageList = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
val packageNameList: ArrayList<String> = event.toString().toObject() ?: ArrayList()
val installStatusMap: HashMap<String, Boolean> = hashMapOf()

View File

@ -374,7 +374,7 @@ object DefaultUrlHandler {
val iconSubscript = uri.getQueryParameter("game_icon_subscript") ?: ""
val gameEntity =
if (forumType == BbsType.OFFICIAL_BBS.value && gameId.isNotEmpty() && gameName.isNotEmpty() && icon.isNotEmpty()) {
GameEntity(id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
GameEntity(_id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
} else null
val activityLabelEntity = if (activityId.isNotEmpty() && activityName.isNotEmpty()) {
ActivityLabelEntity(

View File

@ -63,6 +63,9 @@ public class Config {
public static final String NEW_API_HOST = EnvHelper.getNewHost();
public static final String VAPI_HOST = EnvHelper.getVHost();
public static final String WGAME_CPM_BUSIAPPID = BuildConfig.WGAME_CPM_BUSIAPPID;
public static final String WGAME_CPM_API_HOST = EnvHelper.getWGameCPMHost();
// Third-Party confs
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET;

View File

@ -6,6 +6,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.LayoutManager
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.feature.exposure.ExposureEvent
import io.reactivex.functions.Consumer
@ -16,8 +17,9 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
val throttleBus: ExposureThrottleBus by lazy {
ExposureThrottleBus(
Consumer { commitExposure(it) },
Consumer(Throwable::printStackTrace)
{ commitExposure(it) },
Consumer(Throwable::printStackTrace),
{ commitWXCPMExposure(it) }
)
}
var layoutManager: LayoutManager? = null
@ -93,4 +95,32 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
ExposureManager.log(eventList)
}
/**
* 微信小游戏CPM曝光事件接口上报由于普通曝光事件的上报通道存在节流特性不符合CPM接口对于数据上报的实时性和准确性的要求所以使用额外的通道进行上报
*/
private fun commitWXCPMExposure(visibleState: ExposureThrottleBus.VisibleState) {
val eventList = arrayListOf<ExposureEvent>()
for (pos in visibleState.firstVisiblePosition..visibleState.lastVisiblePosition) {
try {
exposable.getEventByPosition(pos)?.let {
if (it.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
eventList.add(it)
}
}
exposable.getEventListByPosition(pos)?.let { list ->
list.forEach {
if (it.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
eventList.add(it)
}
}
}
} catch (ignore: Exception) {
// Just ignore the error.
}
}
ExposureManager.logCPM(eventList)
}
}

View File

@ -1,11 +1,13 @@
package com.gh.common.exposure
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.loghub.TLogHubHelper
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.minigame.wechat.WGameSubjectCPMListReportHelper
import com.lightgame.utils.Utils
import com.volcengine.model.tls.LogItem
@ -32,6 +34,9 @@ object ExposureManager {
*/
fun log(event: ExposureEvent) {
AppExecutor.logExecutor.execute {
if (event.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
WGameSubjectCPMListReportHelper.reportExposure(event)
}
if (!exposureCache.contains(event.id)) {
exposureSet.add(event)
exposureCache.add(event.id)
@ -58,6 +63,17 @@ object ExposureManager {
}
}
/**
* Log a wechat mini game cpm collection of exposure event.
*/
fun logCPM(eventList: List<ExposureEvent>) {
AppExecutor.logExecutor.execute {
if (eventList.isNotEmpty()) {
WGameSubjectCPMListReportHelper.reportExposure(eventList.toSet())
}
}
}
/**
* @param forcedUpload Ignore all restrictions.
*/

View File

@ -3,16 +3,20 @@ package com.gh.common.exposure
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import io.reactivex.subjects.BehaviorSubject
import java.util.concurrent.TimeUnit
class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Consumer<Throwable>) {
class ExposureThrottleBus(
var onSuccess: Consumer<VisibleState>,
var onError: Consumer<Throwable>,
onPreSuccess: Consumer<VisibleState>
) {
companion object {
private const val THRESHOLD_TIME = 300L
}
private val mPublishSubject: PublishSubject<VisibleState> = PublishSubject.create()
private val mPublishSubject: BehaviorSubject<VisibleState> = BehaviorSubject.create()
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
init {
@ -24,6 +28,7 @@ class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Co
*/
val disposable = mPublishSubject
.distinctUntilChanged()
.doOnNext(onPreSuccess)
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.subscribe(onSuccess, onError)

View File

@ -33,5 +33,9 @@ class BuildConfigImpl : IBuildConfigProvider {
override fun getVDevApiHost(): String = BuildConfig.DEV_VAPI_HOST
override fun getWGameCPMApiHost(): String = BuildConfig.WGAME_CPM_API_HOST
override fun getWGameCPMBusiAppId(): String = BuildConfig.WGAME_CPM_BUSIAPPID
override fun getLogProducerProject(): String = BuildConfig.LOG_HUB_PROJECT
}

View File

@ -62,7 +62,13 @@ class DirectProviderImpl : IDirectProvider {
DirectUtils.directToCommunityArticle(context, articleId, communityId, entrance, path, sourceEntrance)
}
override fun directToVideoDetail(context: Context, videoId: String, entrance: String?, path: String?, sourceEntrance: String) {
override fun directToVideoDetail(
context: Context,
videoId: String,
entrance: String?,
path: String?,
sourceEntrance: String
) {
DirectUtils.directToVideoDetail(context, videoId, entrance, path, sourceEntrance)
}
@ -78,8 +84,13 @@ class DirectProviderImpl : IDirectProvider {
DirectUtils.directToQQGameById(activity, qqAppId)
}
override fun directToWechatGameById(activity: Activity, qqAppId: String) {
DirectUtils.directToWechatGameById(activity, qqAppId)
override fun directToWechatGameById(
activity: Activity,
wechatAppId: String,
wechatAppPath: String,
wechatAppExtData: String
) {
DirectUtils.directToWechatGameById(activity, wechatAppId, wechatAppPath, wechatAppExtData)
}
override fun directToExternalBrowser(context: Context, url: String) {

View File

@ -9,7 +9,7 @@ import com.gh.gamecenter.core.provider.IPackageHelperProvider
@Route(path = RouteConsts.provider.packageHelper, name = "PackageHelper暴露服务")
class PackageHelperProviderImpl : IPackageHelperProvider {
override fun getLocalPackageNameSet(): HashSet<String> {
override fun getLocalPackageNameSet(): Set<String> {
return PackageHelper.localPackageNameSet
}

View File

@ -485,11 +485,13 @@ object DirectUtils {
ColumnCollectionDetailFragment.TYPE_QQ_MINI_GAME_COLUMN -> directToQGameHome(context)
// QQ游戏专题详情页
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN -> {
val subjectType = if (linkEntity.type == ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN) {
SubjectData.SubjectType.QQ_GAME
} else {
SubjectData.SubjectType.WECHAT_GAME
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN,
ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN,
ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN -> {
val subjectType = when (linkEntity.type) {
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN -> SubjectData.SubjectType.WECHAT_GAME_CPM
else -> SubjectData.SubjectType.WECHAT_GAME
}
directToSubject(
context = context,
@ -2009,6 +2011,8 @@ object DirectUtils {
fun directToWechatGameById(
activity: Activity,
wechatAppId: String,
wechatAppPath: String = "",
wechatAppExtData: String = ""
) {
val wxApiProxy = WXAPIFactory.createWXAPI(
@ -2023,8 +2027,9 @@ object DirectUtils {
wxApiProxy.sendReq(
WXLaunchMiniProgram.Req().apply {
userName = wechatAppId
path = Constants.WECHAT_MINI_GAME_PCS
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;
path = wechatAppPath.ifEmpty { Constants.WECHAT_MINI_GAME_PCS }
extData = wechatAppExtData
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE
}
)

View File

@ -880,7 +880,7 @@ object DownloadItemUtils {
}
if (gameEntity.isMiniGame()) {
downloadBtn.setOnClickListener {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
clickCallback?.onCallback()
allStateClickCallback?.onCallback()
}

View File

@ -494,7 +494,7 @@ object DownloadObserver {
java.lang.Boolean.parseBoolean(downloadEntity.getMetaExtra(Constants.IS_PLATFORM_RECOMMEND))
val exposureEvent = ExposureUtils.logADownloadCompleteExposureEvent(
GameEntity(
id = downloadEntity.gameId,
_id = downloadEntity.gameId,
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = downloadEntity.versionName ?: "",
isPlatformRecommend = isPlatformRecommend,

View File

@ -65,7 +65,7 @@ public class InstallUtils {
if (!TextUtils.isEmpty(installVersion) && downloadEntity != null &&
installVersion.equals(downloadEntity.getVersionName())) {
if (!downloadEntity.isPluggable() || PackageUtils.isSignedByGh(context, packageName)) {
EventBus.getDefault().post(new EBPackage(EBPackage.TYPE_INSTALLED, packageName, installVersion));
EventBus.getDefault().post(new EBPackage(EBPackage.TYPE_INSTALLED, packageName, installVersion, false));
}
}
}
@ -82,7 +82,7 @@ public class InstallUtils {
keys.add(packageName);
} else if (!list.contains(packageName)) {
keys.add(packageName);
EventBus.getDefault().post(new EBPackage("卸载", packageName, ""));
EventBus.getDefault().post(new EBPackage("卸载", packageName, "", false));
}
}
for (String key : keys) {

View File

@ -105,14 +105,9 @@ object PackageHelper {
get() = _installedPackageApiSwitchStatusLiveData
// 本地已安装包的列表
var localPackageNameSet = hashSetOf<String>()
var localPackageNameSet = setOf<String>()
get() {
return if (field.isEmpty()) {
field = getAllPackageName(HaloApp.getInstance().application)
field
} else {
field
}
return HashSet(cachedInstalledPackageNameList)
}
/**
@ -461,9 +456,10 @@ object PackageHelper {
* 进行包名初始化相关的操作
*/
fun initPackageRelatedData() {
PackageRepository.initData()
refreshLocalPackageList()
refreshPackageNameList()
PackageRepository.initData {
refreshLocalPackageList()
refreshPackageNameList()
}
}
/**

View File

@ -577,8 +577,7 @@ public class PackageUtils {
}
return true;
} catch (Exception e) {
ArrayList<String> allPackageName = getAllPackageName(context);
boolean isInstalled = allPackageName.contains(packageName);
boolean isInstalled = PackageHelper.INSTANCE.getLocalPackageNameSet().contains(packageName);
if (isInstalled) {
// 能进这里说明上面的 try {} 结果有问题,记录一下
@ -703,25 +702,6 @@ public class PackageUtils {
return null;
}
/*
* 获取所有已安装的软件的包名(包括系统应用)
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
for (String packageName : packageNameList) {
if (!context.getPackageName().equals(packageName)) {
list.add(packageName);
}
}
return list;
}
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
return new ArrayList<>(packageNameList);
}
public static JSONArray getAppList(Context context) {
JSONArray jsonArray = new JSONArray();
try {

View File

@ -46,7 +46,7 @@ object RecommendPopupHelper {
//判断是否符合包名限制
val nameRule = entity.recommendPackage.nameRule
val packages = entity.recommendPackage.details
val installedPackages = PackageUtils.getAllPackageNameIncludeGh(HaloApp.getInstance())
val installedPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance(), 0)
var isMatchSuccess = true
val checkInstalled: (splitPackages: List<String>) -> Boolean = {
var isInstalled = false

View File

@ -27,7 +27,9 @@ import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.json.JSONArray
import org.json.JSONObject
@ -124,11 +126,12 @@ object UsageStatsHelper {
&& curEvent.className == nextEvent.className
) {
val diff = nextEvent.timeStamp - curEvent.timeStamp
val packageName = curEvent.packageName ?: continue
if (pakAndTime[curEvent.packageName] == null) {
pakAndTime[curEvent.packageName] = diff
if (pakAndTime[packageName] == null) {
pakAndTime[packageName] = diff
} else {
pakAndTime[curEvent.packageName] = pakAndTime[curEvent.packageName]!! + diff
pakAndTime[packageName] = pakAndTime[packageName]!! + diff
}
}
}
@ -175,7 +178,7 @@ object UsageStatsHelper {
return
}
val body = RequestBody.create(MediaType.parse("application/json"), postBody.toString())
val body = postBody.toString().toRequestBody("application/json".toMediaTypeOrNull())
mApi.postUsageStatus(body, UserManager.getInstance().userId)
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {

View File

@ -65,6 +65,7 @@ object ViewPagerFragmentHelper {
const val TYPE_COLUMN = "column" // 游戏专题详情页
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ小游戏专题详情页
const val TYPE_WECHAT_GAME_COLUMN = "wechat_game_column_detail" // 微信小游戏专题详情页
const val TYPE_WECHAT_GAME_CPM_COLUMN = "wechat_game_cpm_column_detail" // 微信小游戏CPM专题详情页
const val TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集详情页
const val TYPE_SERVER = "server" // 开服表
const val TYPE_COLUMN_TEST = "column_test_v2" // 新游开测
@ -163,10 +164,11 @@ object ViewPagerFragmentHelper {
className = GameCollectionSquareFragment::class.java.name
}
// 游戏专题详情页/QQ游戏专题详情页
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN -> {
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN, TYPE_WECHAT_GAME_CPM_COLUMN -> {
val subjectType = when(entity.type) {
TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
TYPE_WECHAT_GAME_COLUMN -> SubjectData.SubjectType.WECHAT_GAME
TYPE_WECHAT_GAME_CPM_COLUMN -> SubjectData.SubjectType.WECHAT_GAME_CPM
else -> SubjectData.SubjectType.NORMAL
}
className = SubjectFragment::class.java.name

View File

@ -34,7 +34,9 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONException
import org.json.JSONObject
import java.util.*
@ -216,7 +218,7 @@ object PackageObserver {
try {
jsonObject.put("game_id", gameId)
jsonObject.put("package", packageName)
val rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
val rBody = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
RetrofitManager.getInstance().api
.postPlayedGame(UserManager.getInstance().userId, rBody)
.subscribeOn(Schedulers.io())

View File

@ -94,8 +94,8 @@ object ExoCacheManager {
response =
OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build()
.newCall(request).execute()
if (response!!.isSuccessful && response.body() != null) {
val length = response.body()!!.contentLength()
if (response!!.isSuccessful && response.body != null) {
val length = response.body!!.contentLength()
contentLength = if (length == 0L) -1L else length
}
} catch (e: Exception) {

View File

@ -3,6 +3,7 @@ package com.gh.download.dialog
import android.app.Application
import androidx.lifecycle.*
import com.gh.common.constant.Config
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.feature.entity.ApkEntity
@ -34,7 +35,7 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
private var mAllApkList: MutableList<ApkEntity> = ArrayList()
private var mInstalledApkList: MutableList<ApkEntity> = ArrayList()
private var mOtherApkList: MutableList<ApkEntity> = ArrayList()
private var allPackageName: ArrayList<String>? = null
private var allPackageName: List<String>? = null
var otherSectionPosition = -1
init {
@ -47,7 +48,7 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
}
fun getAllPackageName() {
allPackageName = PackageUtils.getAllPackageName(HaloApp.getInstance())
allPackageName = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance(), 0)
}
fun initListData() {

View File

@ -6,7 +6,7 @@ import android.util.Base64
import com.gh.common.constant.Config
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageUtils
import com.gh.common.util.PackageHelper
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.ExposureEntity
@ -28,7 +28,6 @@ import org.json.JSONObject
import java.io.File
import java.net.URLEncoder
import java.util.*
import kotlin.collections.ArrayList
object BrowserInstallHelper {
@ -40,7 +39,7 @@ object BrowserInstallHelper {
private val mContext by lazy { HaloApp.getInstance().application }
private var mUseReservePort = false
private var mValidInstalledPackageList: ArrayList<String> = arrayListOf()
private var mValidInstalledPackageList: List<String> = listOf()
private var mValidConditionMatchedCache: Boolean? = null
private fun getServer(port: Int): DownloadServer {
@ -54,14 +53,14 @@ object BrowserInstallHelper {
return server
}
private fun getAllInstalledPackageList(): ArrayList<String> {
private fun getAllInstalledPackageList(): List<String> {
when {
mValidInstalledPackageList.isNotEmpty() -> {
return mValidInstalledPackageList
}
else -> {
val allInstalledPackageList = PackageUtils.getAllPackageName(mContext)
val allInstalledPackageList = PackageHelper.getInstalledPackageNameList(mContext, 0)
if (allInstalledPackageList.isNotEmpty()) {
mValidInstalledPackageList = allInstalledPackageList

View File

@ -238,7 +238,7 @@ open class SearchActivity : BaseActivity() {
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_DEFAULT,
TRACK_SEARCH_TYPE_RANK,
mSourceEntrance
)
}
@ -433,12 +433,14 @@ open class SearchActivity : BaseActivity() {
const val TRACK_SEARCH_TYPE_INPUT = "输入搜索"
const val TRACK_SEARCH_TYPE_DEFAULT = "默认搜索"
const val TRACK_SEARCH_TYPE_HISTORY = "历史搜索"
const val TRACK_SEARCH_TYPE_RANK = "榜单搜索"
@JvmStatic
fun toTrackSearchType(type: String) = when (type) {
SearchType.AUTO.value -> TRACK_SEARCH_TYPE_AUTO
SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
SearchType.HISTORY.value -> TRACK_SEARCH_TYPE_HISTORY
SearchType.RANK.value -> TRACK_SEARCH_TYPE_RANK
else -> TRACK_SEARCH_TYPE_DEFAULT
}

View File

@ -408,7 +408,7 @@ public class SkipActivity extends BaseActivity {
try {
JSONObject extJsonObject = new JSONObject(extJson);
String qqGameId = extJsonObject.optString("aid");
MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME);
MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME, "", "");
} catch (JSONException ignored) {
}
break;

View File

@ -32,7 +32,7 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
mViewModel.playedGames.observeNonNull(viewLifecycleOwner) {
defaultViewModel?.isExistHotSearch = it.isNotEmpty()
updateView()
mBinding.searchDiscoveryList.run {
mBinding.hotList.run {
layoutManager = LinearLayoutManager(context)
adapter = AmwaySearchAdapter(context, mViewModel, "安利墙搜索-最近玩过").apply { setData(it) }
}
@ -43,7 +43,7 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
override fun initView() {
mBinding = mAmwayBinding.searchContent
mBinding.searchDiscoveryHeadContainer.headTitle.text = "最近玩过"
mBinding.hotHeadContainer.headTitle.text = "最近玩过"
mBinding.historyFlexContainer.setLimitHeight(mFlexMaxHeight)
updateHistorySearchView(null)

View File

@ -309,7 +309,8 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
// 忽略首次初始化触发的事件
if (!busFour.fromInit && busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}

View File

@ -27,7 +27,7 @@ open class BaseCloudArchiveViewModel(application: Application, private val mConf
)
.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
mArchiveConfigStr = response.body()?.string() ?: ""
mArchiveConfigStr = response.body?.string() ?: ""
callback?.invoke(mArchiveConfigStr)
}

View File

@ -93,7 +93,7 @@ class AdGameBannerAdapter(
it.name ?: ""
)
if (it.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(it.miniGameAppId, it.miniGameType)
MiniGameItemHelper.launchMiniGame(it)
} else {
GameDetailActivity.startGameDetailActivity(
mContext,

View File

@ -161,6 +161,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
val showOnFailed = downloadManagerAd?.displayRule?.onFailedAction == "show"
if ((showThirdPartyAd && thirdPartyAd != null) || (!showThirdPartyAd && thirdPartyAd != null && ownerAd == null)) {
initThirdPartyAd(downloadManagerAd, thirdPartyAd) { isSuccess ->
if (!isAdded) return@initThirdPartyAd
mBinding.maskView.goneIf(!isSuccess)
if (!isSuccess && ownerAd != null && showOnFailed) {
mSlideInterval = ownerAd.adSource?.sliderInterval ?: -1
@ -215,7 +216,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
}
private fun initOwnerAd(adConfig: AdConfig) {
if (adConfig.id.isEmpty()) return
if (!isAdded || adConfig.id.isEmpty()) return
mAdGameViewModel = viewModelProvider(AdGameViewModel.Factory(adConfig))
initAdGameBanner(adConfig)
mBinding.closeAdIv.setOnClickListener {
@ -249,6 +250,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
adConfig.displayRule.onFailedAction == "show" && adConfig.thirdPartyAd != null) {
// 自有广告游戏为空时,显示第三方广告
initThirdPartyAd(adConfig, adConfig.thirdPartyAd) { isSuccess ->
if (!isAdded) return@initThirdPartyAd
mBinding.maskView.goneIf(!isSuccess)
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, System.currentTimeMillis())

View File

@ -220,7 +220,7 @@ class NewInstalledGameFragment : ToolbarFragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(packageEb: EBPackage) {
if (packageEb.isInstalledOrUninstalled()) {
if (!packageEb.fromInit && packageEb.isInstalledOrUninstalled()) {
mInstallGameViewModel.initData(
PackagesManager.filterSameApk(
PackagesManager.filterDownloadBlackPackage(mPackageViewModel?.getGameInstalledLiveData()?.value as MutableList<GameInstall>?)

View File

@ -9,14 +9,16 @@ import kotlinx.parcelize.Parcelize
@Parcelize
data class SearchSubjectEntity(
val name: String = "",
val games: List<GameEntity> = listOf(),
var games: List<GameEntity> = listOf(),
val location: Int = 0,
@SerializedName("column_id")
val columnId: String = "",
val adId: String = "", // 广告ID(本地字段),不为空时为广告专题
val codeId: String = "", // 广告CODE_ID(本地字段),不为空时为广告专题
@SerializedName("ad_icon_active")
val adIconActive: Boolean = false
val adIconActive: Boolean = false,
// 本地字段标记是否为微信小游戏CPM专题
var isWGameSubjectCPM: Boolean = false
) : Parcelable {
fun getFilterGame() = RegionSettingHelper.filterGame(games)
}

View File

@ -63,6 +63,11 @@ class SubjectData(
/**
* 微信小游戏专题
*/
WECHAT_GAME
WECHAT_GAME,
/**
* 微信小游戏CPM专题
*/
WECHAT_GAME_CPM,
}
}

View File

@ -104,6 +104,8 @@ data class SubjectEntity(
@SerializedName("is_wechat_column")
var isWechatColumn: Boolean = false,
var isWechatColumnCPM: Boolean = false,
var explain: String = "", // 游戏单合集说明
@SerializedName("show_star")
@ -130,6 +132,7 @@ data class SubjectEntity(
val subjectType: SubjectData.SubjectType get() = when {
isQQColumn -> SubjectData.SubjectType.QQ_GAME
isWechatColumnCPM -> SubjectData.SubjectType.WECHAT_GAME_CPM
isWechatColumn -> SubjectData.SubjectType.WECHAT_GAME
else -> SubjectData.SubjectType.NORMAL
}

View File

@ -1,6 +1,12 @@
package com.gh.gamecenter.eventbus
class EBPackage(var type: String, var packageName: String, var versionName: String?) {
/**
* @param fromInit 实体生成是否来自于初始化
*/
class EBPackage(var type: String,
var packageName: String,
var versionName: String?,
val fromInit: Boolean = false) {
var gameId: String? = null
var isVGame: Boolean = false // 是否是畅玩游戏

View File

@ -39,14 +39,14 @@ class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() {
override fun initView() {
mBinding = FragmentSearchDefaultBinding.bind(mCachedView)
mBinding.searchDiscoveryTagHeadContainer.root.visibility = View.GONE
mBinding.searchDiscoveryTagFlexContainer.visibility = View.GONE
mBinding.hotTagHeadContainer.root.visibility = View.GONE
mBinding.hotTagFlexContainer.visibility = View.GONE
if (mEntrance == "论坛首页" || mEntrance == "搜索栏") {
mBinding.searchDiscoveryHeadContainer.headTitle.text = "热门论坛"
mBinding.hotHeadContainer.headTitle.text = "热门论坛"
mViewModel.getForumSearchHotContent()
} else {
mBinding.searchDiscoveryHeadContainer.root.visibility = View.GONE
mBinding.searchDiscoveryList.visibility = View.GONE
mBinding.hotHeadContainer.root.visibility = View.GONE
mBinding.hotList.visibility = View.GONE
}
val params = mBinding.historyHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams
params.topMargin = 0.5f.dip2px()

View File

@ -611,7 +611,7 @@ class GameFragmentAdapter(
val subjectData = gameEntity.subjectData
DataCollectionUtils.uploadClick(mContext, subjectData?.name + "-列表", "游戏-专题", gameEntity.name)
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
} else {
GameDetailActivity.startGameDetailActivity(
mContext, gameEntity,
@ -1322,7 +1322,7 @@ class GameFragmentAdapter(
DataCollectionUtils.uploadClick(mContext, subjectData.name + "-列表", "游戏-专题", gameEntity.name)
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
} else if (gameEntity.isPluggable) {
GameDetailActivity.startGameDetailActivity(
mContext,

View File

@ -67,6 +67,8 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
}
private fun showSubjectTab(linkEntityList: MutableList<LinkEntity>) {
if (!isVisible) return
val subjectDataList = arrayListOf<SubjectData>()
for (link in linkEntityList) {

View File

@ -135,7 +135,7 @@ class GameGallerySlideViewHolder(val binding: GameGallerySlideItemBinding) : Bas
binding.iconIv.displayGameIcon(gameEntity)
binding.iconIv.setOnClickListener {
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
} else {
GameDetailActivity.startGameDetailActivity(
binding.root.context,

View File

@ -55,7 +55,7 @@ class GameGalleryViewHolder(val cell: GameGalleryItemCell) :
if (subjectEntity.isMiniGame) {
gameIcon.setOnClickListener {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
}
} else {
gameIcon.setOnClickListener(null)

View File

@ -140,7 +140,7 @@ class GameHorizontalAdapter(
}
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
} else {
GameDetailActivity.startGameDetailActivity(
mContext,

View File

@ -68,7 +68,7 @@ class GameHorizontalSlideAdapter(
holder.bindGameHorizontalItem(gameEntity, mSubjectEntity)
holder.itemView.setOnClickListener {
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
} else {
val exposureEvent = exposureEventList?.safelyGetInRelease(position)
if (exposureEvent != null) {

View File

@ -45,7 +45,9 @@ import com.zhihu.matisse.Matisse
import com.zhihu.matisse.internal.utils.PathUtils
import io.reactivex.disposables.Disposable
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import kotlin.collections.component1
import kotlin.collections.component2
@ -420,10 +422,8 @@ class GameUploadFragment : ToolbarFragment() {
requestMap["type"] = mGameType
}
val body = RequestBody.create(
MediaType.parse("application/json"),
GsonUtils.toJson(requestMap)
)
val body = GsonUtils.toJson(requestMap)
.toRequestBody("application/json".toMediaTypeOrNull())
mViewModel.uploadGames(body)
}

View File

@ -968,7 +968,7 @@ class GameCollectionDetailFragment :
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
if (!busFour.fromInit && busFour.isInstalledOrUninstalled()) {
if (EBPackage.TYPE_INSTALLED == busFour.type
&& UserManager.getInstance().isLoggedIn
&& (mEntity?.count?.playedGame ?: 0) < (mEntity?.count?.game ?: 0)

View File

@ -7,6 +7,9 @@ import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.gh.common.util.DirectUtils
@ -21,6 +24,17 @@ class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBi
private val mAdapter = GameCollectionAmwayAdapter(binding.root.context)
private val mLooperHandle = LooperHandle(this)
private val mSlideLooperKey = 333
private val mLifecycleObserver = object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
startAutoPlay()
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
stopAutoPlay()
}
}
fun bindAmway(amwayList: List<AmwayCommentEntity>, viewModel: GameCollectionSquareViewModel) {
mAdapter.setAmwayList(amwayList)
@ -54,6 +68,14 @@ class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBi
mLooperHandle.removeMessages(mSlideLooperKey)
}
fun onViewAttach(lifecycle: Lifecycle) {
lifecycle.addObserver(mLifecycleObserver)
}
fun onViewDetach(lifecycle: Lifecycle) {
lifecycle.removeObserver(mLifecycleObserver)
}
fun ViewPager2.setCurrentItem(
item: Int,
duration: Long,

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter.gamecollection.square
import android.content.Context
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils
@ -23,6 +24,7 @@ import com.lightgame.adapter.BaseRecyclerAdapter
class GameCollectionBannerAdapter(
context: Context,
private val mLifecycleOwner: LifecycleOwner,
private val mViewModel: GameCollectionSquareViewModel,
var mBannerList: List<CarouselEntity> = emptyList(),
private var mAmwayListItem: List<AmwayCommentEntity>? = null,
@ -78,6 +80,20 @@ class GameCollectionBannerAdapter(
return index
}
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is GameCollectionAmwayViewHolder) {
holder.onViewAttach(mLifecycleOwner.lifecycle)
}
}
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is GameCollectionAmwayViewHolder) {
holder.onViewDetach(mLifecycleOwner.lifecycle)
}
}
companion object {
const val ITEM_AMWAY = 100
const val ITEM_BANNER = 101

View File

@ -12,6 +12,9 @@ import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
@ -47,6 +50,7 @@ import java.lang.ref.WeakReference
class GameCollectionSquareAdapter(
context: Context,
private val mLifecycleOwner: LifecycleOwner,
private val mIsHome: Boolean = false,
private val mFragment: GameCollectionSquareFragment,
private val mViewModel: GameCollectionSquareViewModel,
@ -157,7 +161,7 @@ class GameCollectionSquareAdapter(
when (holder) {
is GameCollectionHeaderItemViewHolder -> {
val itemData = mEntityList[position]
holder.bindHeader(itemData, mBasicExposureSource, mViewModel)
holder.bindHeader(mLifecycleOwner, itemData, mBasicExposureSource, mViewModel)
}
is GameCollectionFilterItemViewHolder -> holder.bindFilter(mFragment, mViewModel, mRefreshCallback)
@ -211,6 +215,20 @@ class GameCollectionSquareAdapter(
override fun getItemCount() =
if (mEntityList.isNullOrEmpty()) 0 else if (mIsHome && mEntityList.size == 2) mEntityList.size else mEntityList.size + 1
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is GameCollectionHeaderItemViewHolder) {
holder.onViewAttach(mLifecycleOwner.lifecycle)
}
}
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is GameCollectionHeaderItemViewHolder) {
holder.onViewDetach(mLifecycleOwner.lifecycle)
}
}
class GameCollectionHeaderItemViewHolder(val binding: ItemGameCollectionHeaderBinding) :
RecyclerView.ViewHolder(binding.root) {
private lateinit var mBannerAdapter: GameCollectionBannerAdapter
@ -218,8 +236,20 @@ class GameCollectionSquareAdapter(
private lateinit var mBannerLayoutManager: LinearLayoutManager
private val mLooperHandle = LooperHandle(this)
private val mSlideLooperKey = 111
private val mLifecycleObserver = object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
startAutoPlay()
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
stopAutoPlay()
}
}
fun bindHeader(
lifecycleOwner: LifecycleOwner,
itemData: GameCollectionListItemData,
mBasicExposureSource: List<ExposureSource>,
viewModel: GameCollectionSquareViewModel
@ -249,6 +279,7 @@ class GameCollectionSquareAdapter(
mBannerLayoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
mBannerAdapter = GameCollectionBannerAdapter(
context,
lifecycleOwner,
viewModel,
bannerList,
amwayListItem,
@ -345,6 +376,14 @@ class GameCollectionSquareAdapter(
mLooperHandle.removeMessages(mSlideLooperKey)
}
fun onViewAttach(lifecycle: Lifecycle) {
lifecycle.addObserver(mLifecycleObserver)
}
fun onViewDetach(lifecycle: Lifecycle) {
lifecycle.removeObserver(mLifecycleObserver)
}
class LooperHandle(viewHolder: GameCollectionHeaderItemViewHolder) : Handler(Looper.getMainLooper()) {
private val mWeakReference: WeakReference<GameCollectionHeaderItemViewHolder> = WeakReference(viewHolder)

View File

@ -138,6 +138,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mGuideContainer?.visibility = View.GONE
} else {
if (mExposureEventList.isNotEmpty()) ExposureManager.log(mExposureEventList)
stopAutoPlay()
}
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
NewFlatLogUtils.logGameCollectSquareStayTime(stayTime, if (mUseAlternativeLayout) "首页tab栏" else "游戏单广场")
@ -175,6 +176,8 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
)
)
}
} else {
startAutoPlay()
}
mElapsedHelper.resetCounting()
mElapsedHelper.resumeCounting()
@ -270,6 +273,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mAdapter =
GameCollectionSquareAdapter(
requireContext(),
viewLifecycleOwner,
mUseAlternativeLayout,
this,
mViewModel,
@ -382,6 +386,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
val bannerAdapter = GameCollectionBannerAdapter(
requireContext(),
viewLifecycleOwner,
mViewModel,
mEntrance = "游戏单广场",
mBasicExposureSource = mBasicExposureSourceList
@ -515,7 +520,8 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
private fun startAutoPlay() {
if ((mDefaultBinding.headerContainer.bannerRv.adapter as GameCollectionBannerAdapter).getActualSize() <= 1) return
val bannerAdapter = mDefaultBinding.headerContainer.bannerRv.adapter as? GameCollectionBannerAdapter
if (bannerAdapter == null || bannerAdapter.getActualSize() <= 1) return
stopAutoPlay()
mLooperHandle.sendEmptyMessageDelayed(mSlideLooperKey, BANNER_LOOP_TIME)
}

View File

@ -394,7 +394,7 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
SensorsBridge.trackDownloadComponentsContentClick(
gameId = gameEntity.id,
gameName = gameEntity.name ?: "unknown",
gameSchemeType = gameEntity.gameBitChinese,
gameSchemaType = gameEntity.gameBitChinese,
downloadStatus = gameEntity.downloadStatusChinese,
gameType = gameEntity.categoryChinese,
downloadType = if (asVGame) "畅玩下载" else "本地下载",
@ -405,7 +405,7 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
SensorsBridge.trackDownloadComponentsShow(
gameId = gameEntity.id,
gameName = gameEntity.name ?: "unknown",
gameSchemeType = gameEntity.gameBitChinese,
gameSchemaType = gameEntity.gameBitChinese,
downloadStatus = gameEntity.downloadStatusChinese,
gameType = gameEntity.categoryChinese,
downloadType = if (asVGame) "畅玩下载" else "本地下载",

View File

@ -45,7 +45,9 @@ import com.gh.gamecenter.login.user.UserManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import retrofit2.HttpException
@ -541,7 +543,7 @@ class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver {
jsonObject.put("rom", MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName)
jsonObject.put("again", again)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
CheckLoginUtils.checkLogin(this, mEntrance) {
mViewModel.postGameComment(mComment?.id ?: "", body)

View File

@ -97,7 +97,7 @@ class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerVie
}
holder.itemView.setOnClickListener {
if (game.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(game.miniGameAppId, game.miniGameType)
MiniGameItemHelper.launchMiniGame(game)
} else {
GameDetailActivity.startGameDetailActivity(
binding.root.context,

View File

@ -140,7 +140,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
searchToolbarTabWrapperViewModel =
viewModelProviderFromParent(
SearchToolbarTabWrapperViewModel.Factory(multiTabNavId, noTabLinkId),
multiTabNavId
multiTabNavId + noTabLinkId
)
}
if (bottomTabId.isNotEmpty()) {
@ -292,7 +292,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
gameDetailDestination.observe(viewLifecycleOwner, EventObserver { (entrance, game) ->
if (game.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(game.miniGameAppId, game.miniGameType)
MiniGameItemHelper.launchMiniGame(game)
} else {
GameDetailActivity.startGameDetailActivity(
requireContext(),

View File

@ -78,6 +78,7 @@ class CustomPageViewModel(
addSource(repository.customDiscoverItemLiveData, ::notifyItemChanged)
addSource(repository.recentGamesItemLiveData, ::notifyItemChanged)
addSource(repository.customPluginItemLiveData, ::notifyItemChanged)
addSource(repository.wechatMiniGameCPMItemLiveData, ::notifyWechatMiniGameCPMSubjectItemChanged)
}
val dataList: LiveData<List<CustomPageItem>> = _dataList
@ -357,11 +358,11 @@ class CustomPageViewModel(
}
}
override fun onChangeABatch(subjectEntity: SubjectEntity, position: Int) {
override fun onChangeABatch(subjectEntity: SubjectEntity) {
val subjectId = subjectEntity.id ?: return
val gameList = subjectChangedMap[subjectId]
if (gameList != null) {
changeSubjectCustomPageItem(position, getRandomGameList(subjectEntity.data, ArrayList(gameList)))
changeSubjectCustomPageItem(subjectId, getRandomGameList(subjectEntity.data, ArrayList(gameList)))
} else {
repository.loadChangeSubjectGame(subjectEntity)
.subscribeOn(Schedulers.io())
@ -370,7 +371,7 @@ class CustomPageViewModel(
override fun onResponse(response: List<GameEntity>?) {
if (response != null) {
subjectChangedMap[subjectId] = response
onChangeABatch(subjectEntity, position)
onChangeABatch(subjectEntity)
}
}
@ -396,21 +397,32 @@ class CustomPageViewModel(
return resultGameList
}
private fun changeSubjectCustomPageItem(position: Int, newGameList: MutableList<GameEntity>) {
private fun changeSubjectCustomPageItem(id: String, newGameList: MutableList<GameEntity>) {
val oldData = _dataList.value as? MutableList<CustomPageItem>
if (!oldData.isNullOrEmpty() && newGameList.isNotEmpty()) {
val newData = oldData?.toMutableList()
if (!newData.isNullOrEmpty() && newGameList.isNotEmpty()) {
// 替换当前专题游戏数据
val customPageItem = oldData.getOrNull(position)
val position = newData.indexOfFirst {
when(it) {
is CustomSubjectItem -> it.data.id == id
is CustomSplitSubjectItem -> it.data.id == id
else -> false
}
}
if (position == -1) return
val customPageItem = newData[position]
if (customPageItem is CustomSubjectItem) {
val newCustomPageItem = customPageItem.copy(data = customPageItem.data.copy(mData = newGameList))
oldData[position] = newCustomPageItem
val newCustomPageItem =
customPageItem.copy(data = customPageItem.data.copy(mData = newGameList), _position = position)
newData[position] = newCustomPageItem
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newCustomPageItem, newGameList))
}
if (customPageItem is CustomSplitSubjectItem) {
// 移除所有旧数据
oldData.removeAll {
newData.removeAll {
it.componentPosition == customPageItem.componentPosition
}
@ -433,21 +445,15 @@ class CustomPageViewModel(
)
// 将新的 items 添加到列表集合
if (position >= oldData.size) {
oldData.addAll(newItems)
} else {
oldData.addAll(position, newItems)
}
newData.addAll(position, newItems)
// 修正集合中 item 的position 取值
oldData.forEachIndexed { index, item ->
newData.forEachIndexed { index, item ->
item.position = index
}
}
// 通知更新
_dataList.value = oldData
_dataList.value = newData
}
}
@ -467,6 +473,40 @@ class CustomPageViewModel(
}
}
/**
* 通过CPM接口异步请求获取的微信小游戏数据插入
*/
private fun notifyWechatMiniGameCPMSubjectItemChanged(result: Pair<String, List<GameEntity>>) {
val oldData = _dataList.value ?: return
val index = oldData.indexOfFirst {
it is CustomWeChatMiniGamesCPMSubjectItem && it.data.id == result.first
}
if (index == -1) return
val subjectItem = (oldData[index] as CustomWeChatMiniGamesCPMSubjectItem).apply {
data.data = result.second.toMutableList()
data.isWechatColumnCPM = true
}
val position = subjectItem.position
val componentPosition = subjectItem.componentPosition
val newData = oldData.toMutableList()
val customPageItemList = repository.convertColumnDetailSubjectItems(
position,
componentPosition,
subjectItem.link,
subjectItem.data
)
if (customPageItemList.isEmpty()) return
newData[index] = customPageItemList[0]
newData.addAll(index + 1, customPageItemList.subList(1, customPageItemList.size))
newData.forEachIndexed { pos, customPageItem ->
customPageItem.position = pos
}
repository.notifyPositionChanged(newData.size)
gamePositionAndPackageHelper.clear()
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData))
_dataList.value = newData
}
private fun notifyItemRemoved(removeItem: CustomPageItem) {
val oldData = _dataList.value ?: return
val newData = oldData.toMutableList()
@ -476,7 +516,7 @@ class CustomPageViewModel(
for (i in removeItem.position until newData.size) {
newData[i].position--
}
repository.notifyPositionChanged(-1)
repository.notifyPositionAdded(-1)
gamePositionAndPackageHelper.clear()
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData))
_dataList.value = newData

View File

@ -134,7 +134,7 @@ class CustomGameHorizontalAdapter(
}
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
} else {
GameDetailActivity.startGameDetailActivity(
context,

View File

@ -29,7 +29,7 @@ interface OnCustomPageEventListener {
/**
* 换一批
*/
fun onChangeABatch(subjectEntity: SubjectEntity, position: Int)
fun onChangeABatch(subjectEntity: SubjectEntity)
fun onChangeAppBarColor(color: Int)

View File

@ -39,7 +39,7 @@ class SubjectEventHelper(viewModel: CustomPageViewModel) : CustomPageItemChildEv
fun onChangeABatch(subject: SubjectEntity) {
tracker.trackColumnClick(_item, null, "右上角", "换一批")
viewModel.onChangeABatch(subject, _item.position)
viewModel.onChangeABatch(subject)
}
fun onMoreClick(link: LinkEntity) {

View File

@ -73,6 +73,8 @@ class CustomPageData(
val qqMiniGameColumn: SubjectEntity? = null,
@SerializedName("link_wechat_game_column_detail")
val wechatMiniGameColumn: SubjectEntity? = null,
@SerializedName("link_wechat_game_cpm_column_detail")
val wechatMiniGameCPMColumn: SubjectEntity? = null,
@SerializedName("link_common_collection")
val linkCommonCollection: CommonContentCollection? = null,
@SerializedName("link_qq_game_recently_played")
@ -83,6 +85,7 @@ class CustomPageData(
get() = when (link.type) {
CustomPageItem.CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL -> qqMiniGameColumn
CustomPageItem.CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL -> wechatMiniGameColumn
CustomPageItem.CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL -> wechatMiniGameCPMColumn
else -> linkColumn
}
@ -672,7 +675,7 @@ class CustomPageData(
@SerializedName("home")
private val _home: String? = null,
@SerializedName("more_link")
val moreLink: LinkEntity? = null
val moreLink: LinkEntity? = null
) {
val home: String

View File

@ -4,10 +4,7 @@ import com.gh.common.util.ViewPagerFragmentHelper
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.entity.AmwayCommentEntity
import com.gh.gamecenter.entity.DiscoveryCardEntity
import com.gh.gamecenter.entity.HomeItemTestV2Entity
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.vspace.VGameItemData
@ -84,6 +81,7 @@ abstract class CustomPageItem(
const val CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED = "wechat_game_recently_played"
const val CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL = ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN
const val CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL = ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN
const val CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL = ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN
const val CUSTOM_LINK_TYPE_HALO_RECOMMEND = "halo_recommend"
const val CUSTOM_LINK_TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集
const val CUSTOM_LINK_TYPE_GAME_LIST_COLLECTION = "game_list_collection"
@ -300,6 +298,7 @@ abstract class CustomPageItem(
CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED to "最近在玩",
CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL to "QQ小游戏专题",
CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL to "微信小游戏专题",
CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL to "微信小游戏专题",
CUSTOM_LINK_TYPE_HALO_RECOMMEND to "光环推荐",
CUSTOM_LINK_TYPE_COLUMN_COLLECTION to "专题合集",
CUSTOM_LINK_TYPE_GAME_LIST_COLLECTION to "游戏单合集",
@ -623,6 +622,25 @@ data class CustomRecentWeChatMiniGamesItem(
}
}
// 微信小游戏CPM专题组件
data class CustomWeChatMiniGamesCPMSubjectItem(
private val _link: LinkEntity,
val data: SubjectEntity,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY
override fun doAreContentsTheSames(other: CustomPageItem): Boolean {
return other is CustomWeChatMiniGamesCPMSubjectItem
&& data == other.data
&& position == other.position
&& componentPosition == other.componentPosition
}
}
// qq小游戏-最近在玩
data class CustomRecentQqMiniGamesItem(
private val _link: LinkEntity,

View File

@ -3,12 +3,12 @@ package com.gh.gamecenter.home.custom.model
import android.graphics.Paint
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.GameSubstituteRepositoryHelper
import com.gh.common.util.HomePluggableHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.utils.TextHelper
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.sp2px
@ -18,11 +18,11 @@ import com.gh.gamecenter.entity.DiscoveryCardEntity
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.PullDownPush
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.entity.TagStyleEntity
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_BANNER
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER
@ -47,7 +47,6 @@ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_S
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL_SLIDE
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_GAME_TIMELINE_HORIZONTAL_SLIDE
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_GAME_VERTICAL_SLIDE
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_SINGLE_GAME_CARD
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_COLUMN
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_GAME
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_HALO_RECOMMEND
@ -55,7 +54,11 @@ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMListRepository
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMListUseCase
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRemoteDataSource
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.wrapper.MainWrapperRepository
@ -63,12 +66,14 @@ import com.gh.vspace.VHelper
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import java.util.concurrent.atomic.AtomicInteger
import java.util.regex.Pattern
class CustomPageRepository private constructor(
private val remoteDataSource: CustomPageRemoteDataSource,
private val localDataSource: CustomPageLocalDataSource
private val localDataSource: CustomPageLocalDataSource,
private val wGameSubjectCPMRemoteDataSource: WGameSubjectCPMRemoteDataSource
) {
private val pageInfo = PageInfo()
@ -77,6 +82,10 @@ class CustomPageRepository private constructor(
private val shareRepository = CustomPageShareRepository.instance
private val wGameSubjectCPMListUseCase = WGameSubjectCPMListUseCase(
WGameSubjectCPMListRepository(wGameSubjectCPMRemoteDataSource)
)
private var recentItem: CustomRecentGamesItem? = null
private var recentQQItem: CustomRecentQqMiniGamesItem? = null
@ -91,14 +100,13 @@ class CustomPageRepository private constructor(
private var displayingGameIdSet = hashSetOf<String>() // 当前正在显示的游戏 id 列表
private val _customPluginItemLiveData = MediatorLiveData<CustomPluginItem>().apply {
val customPluginItemLiveData: LiveData<CustomPluginItem> = MediatorLiveData<CustomPluginItem>().apply {
addSource(PackageRepository.gameUpdateLiveData) {
refreshPluginIfNeed(it)?.let(this::setValue)
}
}
val customPluginItemLiveData: LiveData<CustomPluginItem> = _customPluginItemLiveData
private val _recentGamesItemLiveData = MediatorLiveData<CustomRecentGamesItem>().apply {
val recentGamesItemLiveData: LiveData<CustomRecentGamesItem> = MediatorLiveData<CustomRecentGamesItem>().apply {
addSource(DownloadManager.getInstance().downloadEntityLiveData) {
refreshRecentVGameIfNeed()?.let(this::setValue)
}
@ -106,29 +114,30 @@ class CustomPageRepository private constructor(
refreshRecentVGameIfNeed()?.let(this::setValue)
}
}
val recentGamesItemLiveData: LiveData<CustomRecentGamesItem> = _recentGamesItemLiveData
private val _recentMiniGamesItemLiveData = MediatorLiveData<CustomRecentWeChatMiniGamesItem>().apply {
addSource(MiniGameRecentlyPlayUseCase.wechatRecentGamesItemLiveData) {
refreshRecentWechatMiniGameIfNeed(it)?.let(this::setValue)
val recentMiniGamesItemLiveData: LiveData<CustomRecentWeChatMiniGamesItem> =
MediatorLiveData<CustomRecentWeChatMiniGamesItem>().apply {
addSource(MiniGameRecentlyPlayUseCase.wechatRecentGamesItemLiveData) {
refreshRecentWechatMiniGameIfNeed(it)?.let(this::setValue)
}
}
}
val recentMiniGamesItemLiveData: LiveData<CustomRecentWeChatMiniGamesItem> = _recentMiniGamesItemLiveData
private val _recentQqMiniGamesItemLiveData = MediatorLiveData<CustomRecentQqMiniGamesItem>().apply {
addSource(MiniGameRecentlyPlayUseCase.qqRecentGamesItemLiveData) {
refreshRecentQQMiniGameIfNeed(it)?.let(this::setValue)
val recentQqMiniGamesItemLiveData: LiveData<CustomRecentQqMiniGamesItem> =
MediatorLiveData<CustomRecentQqMiniGamesItem>().apply {
addSource(MiniGameRecentlyPlayUseCase.qqRecentGamesItemLiveData) {
refreshRecentQQMiniGameIfNeed(it)?.let(this::setValue)
}
}
}
val recentQqMiniGamesItemLiveData: LiveData<CustomRecentQqMiniGamesItem> = _recentQqMiniGamesItemLiveData
private val _customDiscoverItemLiveData = MediatorLiveData<CustomDiscoverCardItem>().apply {
addSource(shareRepository.discoverData) {
refreshDiscoverDataIfNeed(it)?.let(this::setValue)
val customDiscoverItemLiveData: LiveData<CustomDiscoverCardItem> =
MediatorLiveData<CustomDiscoverCardItem>().apply {
addSource(shareRepository.discoverData) {
refreshDiscoverDataIfNeed(it)?.let(this::setValue)
}
}
}
val customDiscoverItemLiveData: LiveData<CustomDiscoverCardItem> = _customDiscoverItemLiveData
val wechatMiniGameCPMItemLiveData: LiveData<Pair<String, List<GameEntity>>> =
wGameSubjectCPMListUseCase.wechatMiniGameCPMListLiveData
val hiddenNotifications: LiveData<HashMap<String, MutableSet<String>>>
get() = shareRepository.hiddenNotifications
@ -224,6 +233,7 @@ class CustomPageRepository private constructor(
private fun transformRawDataIntoItemData(data: CustomPageData, reloadDiscoverData: Boolean): List<CustomPageItem> {
val list = arrayListOf<CustomPageItem>()
data.customsComponents
.forEachIndexed { _, item ->
// 如果当前item不是展开大图并且上一个item为展开大图则说明展开大图组件已结束
@ -265,112 +275,24 @@ class CustomPageRepository private constructor(
}
}
item.link.type == CUSTOM_LINK_TYPE_COLUMN || item.link.type == CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL || item.link.type == CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL -> {
// 游戏专题
val gameSubject = item.gameSubjectEntity?.also {
if (item.link.type == CUSTOM_LINK_TYPE_COLUMN) {
it.data?.forEach { game ->
game.gameLocation = GameEntity.GameLocation.INDEX
}
}
}
var isAdded = false
if (gameSubject != null && !gameSubject.data.isNullOrEmpty()) {
// 记录已显示的游戏 id
for (game in gameSubject.data!!) {
displayingGameIdSet.add(game.id)
}
// 替换游戏
substituteGameIfNeeded(gameSubject)
if (gameSubject.tag == "update") {
// 优先显示更新标签
gameSubject.data?.forEach {
it.tagStyle.clear()
it.tagStyle.add(
TagStyleEntity(
id = "local_generated",
name = TimeUtils.getFormatTime(it.updateTime, "MM-dd") + " 更新",
color = "1383EB",
background = "E8F3FF",
column = "1383EB"
)
)
}
}
when (gameSubject.type) {
COMPONENTS_GAME_SUBJECT_TYPE_DOUBLE_CARD, COMPONENTS_SUBJECT_TYPE_DOUBLE_GAME_WELFARE_CARD -> {
// 双列卡片 双列福利卡片
val gameCount = gameSubject.data?.size ?: 0
if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) {
val subjectItems = convertSplitSubjectItems(item, 2, false)
list.addAll(subjectItems)
isAdded = true
}
}
COMPONENTS_GAME_SUBJECT_TYPE_GAME_VERTICAL -> {
// 长列表式
val subjectItems = convertSplitSubjectItems(item, 1, false)
list.addAll(subjectItems)
isAdded = true
}
COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL -> {
// 图标矩阵
val subjectItems = convertSplitSubjectItems(item, 4, true)
list.addAll(subjectItems)
isAdded = true
}
else -> {
if (gameSubject.type == COMPONENTS_GAME_SUBJECT_TYPE_GAME_VIDEO_HORIZONTAL_SLIDE ||
gameSubject.type == COMPONENTS_SUBJECT_TYPE_GAME_FOLD_SLIDE
) {
val gameCount = gameSubject.data?.size ?: 0
if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) {
list.add(
CustomSubjectItem(
item.link,
gameSubject,
pageInfo.position,
pageInfo.componentPosition
)
)
pageInfo.positionIncrement()
isAdded = true
}
} else {
val gameCount = gameSubject.data?.size ?: 0
if (gameCount > 0) {
list.add(
CustomSubjectItem(
item.link,
gameSubject,
pageInfo.position,
pageInfo.componentPosition
)
)
pageInfo.positionIncrement()
isAdded = true
}
}
}
}
if (isAdded) {
pageInfo.componentPositionIncrement()
}
item.link.type == CUSTOM_LINK_TYPE_COLUMN
|| item.link.type == CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL
|| item.link.type == CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL -> {
val subItems = convertColumnDetailSubjectItems(
pageInfo.position,
pageInfo.componentPosition,
item.link,
item.gameSubjectEntity
)
if (subItems.isNotEmpty()) {
list.addAll(subItems)
pageInfo.positionGetAndAdd(subItems.size)
pageInfo.componentPositionIncrement()
}
}
//QQ小游戏-最近在玩(需要用户登录才显示)
item.link.type == CUSTOM_LINK_TYPE_QQ_GAME_RECENTLY_PLAYED -> {
//QQ小游戏-最近在玩(需要用户登录才显示)
val linkQqGameRecentlyPlayed = item.linkQqGameRecentlyPlayed
if (linkQqGameRecentlyPlayed != null) {
recentQQItem = CustomRecentQqMiniGamesItem(
@ -386,8 +308,8 @@ class CustomPageRepository private constructor(
}
// 微信小游戏-最近在玩
item.link.type == CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED -> {
// 微信小游戏-最近在玩
recentWechatItem = CustomRecentWeChatMiniGamesItem(
item.link,
MiniGameRecentlyPlayUseCase.getRecentlyPlayedMiniGameList(Constants.WECHAT_MINI_GAME),
@ -398,6 +320,23 @@ class CustomPageRepository private constructor(
pageInfo.componentPositionIncrement()
}
// 微信小游戏CPM专题
item.link.type == CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL -> {
item.gameSubjectEntity?.let { subject ->
list.add(
CustomWeChatMiniGamesCPMSubjectItem(
item.link,
subject,
pageInfo.position,
pageInfo.componentPosition
)
)
wGameSubjectCPMListUseCase.getWechatMiniGameCPMList(subject.id)
pageInfo.positionIncrement()
pageInfo.componentPositionIncrement()
}
}
item.linkColumnCollection != null -> {
// 专题合集
val linkColumnCollection = item.linkColumnCollection
@ -475,7 +414,9 @@ class CustomPageRepository private constructor(
|| layout == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD
|| layout == COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT
) {
list.addAll(convertSplitCommonContentCollection(item))
val subItems = convertSplitCommonContentCollection(item)
list.addAll(subItems)
pageInfo.positionGetAndAdd(subItems.size)
pageInfo.componentPositionIncrement()
} else {
var show = true
@ -528,12 +469,16 @@ class CustomPageRepository private constructor(
// 最近在玩
val entities = VHelper.getSortedRecentlyPlayedList()
recentItem =
CustomRecentGamesItem(item.link, entities, pageInfo.position, pageInfo.componentPosition)
.also {
list.add(it)
pageInfo.positionIncrement()
pageInfo.componentPositionIncrement()
}
CustomRecentGamesItem(
item.link,
entities,
pageInfo.position,
pageInfo.componentPosition
).also {
list.add(it)
pageInfo.positionIncrement()
pageInfo.componentPositionIncrement()
}
}
item.link.type == "plugin_area" -> {
@ -666,45 +611,155 @@ class CustomPageRepository private constructor(
}
pageInfo.nextPage()
return list
}
fun convertColumnDetailSubjectItems(
position: Int,
componentPosition: Int,
link: LinkEntity,
subjectEntity: SubjectEntity?,
): List<CustomPageItem> {
var currentPosition = position
val list = mutableListOf<CustomPageItem>()
// 游戏专题
val gameSubject = subjectEntity?.also {
if (link.type == CUSTOM_LINK_TYPE_COLUMN) {
it.data?.forEach { game ->
game.gameLocation = GameEntity.GameLocation.INDEX
}
}
}
if (gameSubject != null && !gameSubject.data.isNullOrEmpty()) {
// 记录已显示的游戏 id
for (game in gameSubject.data!!) {
displayingGameIdSet.add(game.id)
}
// 替换游戏
substituteGameIfNeeded(gameSubject)
if (gameSubject.tag == "update") {
// 优先显示更新标签
gameSubject.data?.forEach {
it.tagStyle.clear()
it.tagStyle.add(
TagStyleEntity(
id = "local_generated",
name = TimeUtils.getFormatTime(it.updateTime, "MM-dd") + " 更新",
color = "1383EB",
background = "E8F3FF",
column = "1383EB"
)
)
}
}
when (gameSubject.type) {
COMPONENTS_GAME_SUBJECT_TYPE_DOUBLE_CARD, COMPONENTS_SUBJECT_TYPE_DOUBLE_GAME_WELFARE_CARD -> {
// 双列卡片 双列福利卡片
val gameCount = gameSubject.data?.size ?: 0
if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) {
val subjectItems =
convertSplitSubjectItems(link, subjectEntity, currentPosition, componentPosition, 2, false)
list.addAll(subjectItems)
currentPosition += subjectItems.size
}
}
COMPONENTS_GAME_SUBJECT_TYPE_GAME_VERTICAL -> {
// 长列表式
val subjectItems =
convertSplitSubjectItems(link, subjectEntity, currentPosition, componentPosition, 1, false)
list.addAll(subjectItems)
currentPosition += subjectItems.size
}
COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL -> {
// 图标矩阵
val subjectItems =
convertSplitSubjectItems(link, subjectEntity, currentPosition, componentPosition, 4, true)
list.addAll(subjectItems)
currentPosition += subjectItems.size
}
else -> {
if (gameSubject.type == COMPONENTS_GAME_SUBJECT_TYPE_GAME_VIDEO_HORIZONTAL_SLIDE ||
gameSubject.type == COMPONENTS_SUBJECT_TYPE_GAME_FOLD_SLIDE
) {
val gameCount = gameSubject.data?.size ?: 0
if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) {
list.add(
CustomSubjectItem(
link,
gameSubject,
currentPosition,
componentPosition
)
)
}
} else {
val gameCount = gameSubject.data?.size ?: 0
if (gameCount > 0) {
list.add(
CustomSubjectItem(
link,
gameSubject,
currentPosition,
componentPosition
)
)
}
}
}
}
}
return list
}
private fun convertSplitSubjectItems(
item: CustomPageData.CustomsComponent,
link: LinkEntity,
subjectEntity: SubjectEntity?,
position: Int,
componentPosition: Int,
stepNum: Int,
isMustFullyCover: Boolean
): List<CustomPageItem> {
val gameSubject = item.gameSubjectEntity ?: return emptyList()
val gameSubject = subjectEntity ?: return emptyList()
val items = arrayListOf<CustomPageItem>()
val games = gameSubject.data ?: emptyList()
var currentPosition = position
(games.indices step stepNum).forEach { start ->
if (isMustFullyCover) {
if (start + stepNum - 1 < games.size) {
items.add(
CustomSplitSubjectItem(
item.link,
link,
gameSubject,
pageInfo.position,
pageInfo.componentPosition,
currentPosition++,
componentPosition,
stepNum,
start
)
)
pageInfo.positionIncrement()
}
} else {
items.add(
CustomSplitSubjectItem(
item.link,
link,
gameSubject,
pageInfo.position,
pageInfo.componentPosition,
currentPosition++,
componentPosition,
stepNum,
start
)
)
pageInfo.positionIncrement()
}
}
items.forEach {
@ -729,7 +784,6 @@ class CustomPageRepository private constructor(
left
)
)
pageInfo.positionIncrement()
}
return items
}
@ -742,12 +796,20 @@ class CustomPageRepository private constructor(
}
}
fun notifyPositionChanged(offset: Int) {
pageInfo.position += offset
fun notifyPositionAdded(offset: Int) {
pageInfo.positionGetAndAdd(offset)
}
fun notifyPositionChanged(value: Int) {
pageInfo.position = value
}
fun loadChangeSubjectGame(subjectEntity: SubjectEntity): Observable<List<GameEntity>> =
remoteDataSource.loadChangeSubjectGame(subjectEntity)
if (subjectEntity.isWechatColumnCPM) {// 微信小游戏CPM专题的“换一批”接口
wGameSubjectCPMRemoteDataSource.getRecommendCPMList(2, 10).toObservable()
} else {
remoteDataSource.loadChangeSubjectGame(subjectEntity)
}
.map(RegionSettingHelper.filterGame)
.map(ApkActiveUtils.filterMapperList)
@ -798,16 +860,16 @@ class CustomPageRepository private constructor(
val page: Int
get() = _page
private var _position: Int = 0
private var _position: AtomicInteger = AtomicInteger(0)
var position: Int
get() = _position
get() = _position.get()
set(value) {
_position = value
_position.set(value)
}
private var _componentPosition = 0
private var _componentPosition: AtomicInteger = AtomicInteger(0)
val componentPosition: Int
get() = _componentPosition
get() = _componentPosition.get()
fun nextPage() {
@ -815,17 +877,25 @@ class CustomPageRepository private constructor(
}
fun positionIncrement() {
_position++
positionGetAndAdd(1)
}
fun componentPositionIncrement() {
_componentPosition++
componentPositionGetAndAdd(1)
}
fun positionGetAndAdd(value: Int) {
_position.getAndAdd(value)
}
fun componentPositionGetAndAdd(value: Int) {
_componentPosition.getAndAdd(value)
}
fun reset() {
_page = 1
_position = 0
_componentPosition = 0
_position.set(0)
_componentPosition.set(0)
}
}
@ -844,7 +914,8 @@ class CustomPageRepository private constructor(
RetrofitManager.getInstance().newApi,
MainWrapperRepository.getInstance()
),
CustomPageLocalDataSource()
CustomPageLocalDataSource(),
WGameSubjectCPMRemoteDataSource()
)
}
}

View File

@ -123,8 +123,12 @@ abstract class BaseCustomViewHolder(
_title.name = subject.name
tvTitle.text = subject.name ?: ""
}
if (_title.rightText != subject.home) {
_title.rightText = subject.home
val home = subject.home ?: ""
val homeText = subject.homeText ?: ""
if (_title.rightHome != home || _title.rightText != homeText) {
_title.rightHome = home
_title.rightText = homeText
fun getHomeText(defaultResId: Int): String =
if (subject.homeText.isNullOrBlank()) {
defaultResId.toResString()
@ -363,6 +367,7 @@ abstract class BaseCustomViewHolder(
data class TitleData(
var name: String? = null,
var rightHome: String? = null,
var rightText: String? = null,
var isRefresh: Boolean = false,
var icon: String? = null,

View File

@ -13,7 +13,7 @@ object HeadUpDisplayLogHelper {
source = source,
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
gameId = downloadEntity.gameId,
gameName = downloadEntity.name
@ -25,7 +25,7 @@ object HeadUpDisplayLogHelper {
source = source,
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
gameId = downloadEntity.gameId,
gameName = downloadEntity.name
@ -36,7 +36,7 @@ object HeadUpDisplayLogHelper {
SensorsBridge.trackAutomaticInstallationPromptBarShow(
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
gameId = downloadEntity.gameId,
gameName = downloadEntity.name
@ -47,7 +47,7 @@ object HeadUpDisplayLogHelper {
SensorsBridge.trackAutomaticInstallationPromptBarClick(
downloadType = if (downloadEntity.asVGame()) "畅玩下载" else "本地下载",
downloadStatus = downloadEntity.getMetaExtra(Constants.DOWNLOAD_STATUS_IN_CHINESE),
gameSchemeType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameSchemaType = if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
gameType = downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
gameId = downloadEntity.gameId,
gameName = downloadEntity.name

View File

@ -59,7 +59,7 @@ class MiniGameRecentlyPlayListAdapter(
if (onItemClick != null) {
onItemClick.invoke(entity, position)
} else {
MiniGameItemHelper.launchMiniGame(entity.miniGameAppId, entity.miniGameType)
MiniGameItemHelper.launchMiniGame(entity)
}
}
}

View File

@ -56,7 +56,7 @@ class MiniGameSearchDefaultRankAdapter(
// 转成Game实体比较好处理数据
val trackGame = GameEntity(
id = rank.id,
_id = rank.id,
mName = rank.name,
miniGameAppId = rank.link.link ?: "",
miniGameType = Constants.WECHAT_MINI_GAME,

View File

@ -2,14 +2,16 @@ package com.gh.gamecenter.minigame
import com.gh.gamecenter.entity.SearchSubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRemoteDataSource
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
import com.gh.gamecenter.search.ISearchGameResultRepository
import io.reactivex.Observable
import java.net.URLEncoder
import io.reactivex.Single
class MiniGameSearchResultRepository(
private val api: ApiService = RetrofitManager.getInstance().newApi
private val api: ApiService = RetrofitManager.getInstance().newApi,
private val mWGameSubjectCPMDataSource: WGameSubjectCPMRemoteDataSource = WGameSubjectCPMRemoteDataSource()
) : ISearchGameResultRepository {
override fun getSearchGame(
@ -22,4 +24,8 @@ class MiniGameSearchResultRepository(
override fun getSearchSubject(key: String?, page: Int): Observable<List<SearchSubjectEntity>> {
return Observable.just(emptyList())
}
override fun getWGameCPMGameList(): Single<MutableList<GameEntity>> {
return mWGameSubjectCPMDataSource.getRecommendCPMList(1)
}
}

View File

@ -6,7 +6,9 @@ import com.gh.gamecenter.retrofit.service.ApiService
import com.gh.gamecenter.subject.ISubjectRepository
import io.reactivex.Observable
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody
class QGameSubjectRepository(
private val api: ApiService = RetrofitManager.getInstance().newApi
@ -17,7 +19,7 @@ class QGameSubjectRepository(
}
override fun getSubjectName(column_id: String?): Observable<ResponseBody> {
return Observable.just(ResponseBody.create(MediaType.parse("application/json"), "{\"name\": \"专题\"}"))
return Observable.just("{\"name\": \"专题\"}".toResponseBody("application/json".toMediaTypeOrNull()))
}
}

View File

@ -0,0 +1,21 @@
package com.gh.gamecenter.minigame.wechat
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.subject.ISubjectListRepository
import io.reactivex.Observable
import io.reactivex.Single
class WGameSubjectCPMListRepository(
private val dataSource: WGameSubjectCPMRemoteDataSource = WGameSubjectCPMRemoteDataSource()
) : ISubjectListRepository {
override fun getColumn(column_id: String?, page: Int, sort: String?, order: String?): Single<MutableList<GameEntity>> {
return dataSource.getRecommendCPMList(page)
}
override fun getColumnSettings(column_id: String?): Observable<SubjectSettingEntity> {
return Observable.just(SubjectSettingEntity())
}
}

View File

@ -0,0 +1,46 @@
package com.gh.gamecenter.minigame.wechat
import android.annotation.SuppressLint
import androidx.lifecycle.LiveData
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.feature.entity.GameEntity
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/**
* 微信小游戏CPM-网域层
*/
class WGameSubjectCPMListUseCase(
private val repository: WGameSubjectCPMListRepository = WGameSubjectCPMListRepository()
) {
/**
* 微信专题CPM请求记录用于避免重复请求以专题ID作为Key
*/
private val requestKeyList = mutableListOf<String>()
/**
* 微信小游戏CPM列表这里的LiveData充当类似于EventBus的角色因此使用NonStickyMutableLiveData
*/
private val _wechatMiniGameCPMListLiveData = NonStickyMutableLiveData<Pair<String, List<GameEntity>>>()
val wechatMiniGameCPMListLiveData: LiveData<Pair<String, List<GameEntity>>> = _wechatMiniGameCPMListLiveData
@SuppressLint("CheckResult")
fun getWechatMiniGameCPMList(subjectId: String?) {
if (subjectId.isNullOrEmpty() || requestKeyList.contains(subjectId)) {
return
}
requestKeyList.add(subjectId)
repository.getColumn(null, 1, null, null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<List<GameEntity>>() {
override fun onSuccess(data: List<GameEntity>) {
requestKeyList.remove(subjectId)
_wechatMiniGameCPMListLiveData.value = subjectId to data
}
})
}
}

View File

@ -0,0 +1,59 @@
package com.gh.gamecenter.minigame.wechat
import com.gh.common.constant.Config
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.TagStyleEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.feature.retrofit.WGameCPMApiService
import io.reactivex.Single
class WGameSubjectCPMRemoteDataSource(
private val api: WGameCPMApiService = RetrofitManager.getInstance().wGameCPMApi
) {
fun getRecommendCPMList(page: Int, pageSize: Int = 10): Single<MutableList<GameEntity>> {
val meta = MetaUtil.getMeta()
val request = mapOf(
"head" to mapOf(
"busiAppid" to Config.WGAME_CPM_BUSIAPPID,
"oaid" to (meta.oaid ?: ""),
"manufacturer" to (meta.manufacturer ?: ""),
"mode" to (meta.model ?: ""),
"androidId" to (MetaUtil.getAndroidId()),
"imei" to (MetaUtil.getIMEI())
),
"body" to mapOf(
"page" to page - 1,
"pageSize" to pageSize,
)
)
return api.getUserRecommendList(request.toRequestBody())
.map {
if (it.ret == 0) {
it.appInfoList.map { info ->
GameEntity(
mName = info.appName,
mIcon = info.logo,
mBrief = info.briefIntro,
miniGameUid = info.appID,
miniGameAppId = info.userName,
miniGameType = Constants.WECHAT_MINI_GAME_CPM,
miniGameAppStatus = 2,
miniGameAppPath = info.wechatAppPath,
miniGameExtData = info.extData,
miniGameRecommendId = info.recommendID,
mTagStyle = arrayListOf(
TagStyleEntity(name = info.categoryName),
TagStyleEntity(name = info.subcategoryName)
)
)
}.toMutableList()
} else {
mutableListOf()
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.gh.gamecenter.minigame.wechat
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.subject.ISubjectRepository
import io.reactivex.Observable
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody
class WGameSubjectCPMRepository : ISubjectRepository {
override fun getColumnSettings(column_id: String?): Observable<SubjectSettingEntity> {
return Observable.just(SubjectSettingEntity())
}
override fun getSubjectName(column_id: String?): Observable<ResponseBody> {
return Observable.just("{\"name\": \"专题\"}".toResponseBody("application/json".toMediaTypeOrNull()))
}
}

View File

@ -6,7 +6,9 @@ import com.gh.gamecenter.retrofit.service.ApiService
import com.gh.gamecenter.subject.ISubjectRepository
import io.reactivex.Observable
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody
class WGameSubjectRepository(
private val api: ApiService = RetrofitManager.getInstance().newApi
@ -16,6 +18,6 @@ class WGameSubjectRepository(
}
override fun getSubjectName(column_id: String?): Observable<ResponseBody> {
return Observable.just(ResponseBody.create(MediaType.parse("application/json"), "{\"name\": \"专题\"}"))
return Observable.just("{\"name\": \"专题\"}".toResponseBody("application/json".toMediaTypeOrNull()))
}
}

View File

@ -26,13 +26,16 @@ class PackageFilterManager {
*/
@SuppressLint("CheckResult")
fun updateFilterPackages(
packageList: MutableList<String>,
packageList: List<String>,
appendOnly: Boolean = true,
callbackClosure: ((list: ArrayList<String>) -> Unit)? = null
) {
val finalPackageList = ArrayList(packageList)
if (appendOnly) {
// 添加因为异常而没能正常更新的包名列表
packageList.addAll(PackageRepository.mPendingPackageNameSet)
finalPackageList.addAll(PackageRepository.mPendingPackageNameSet)
}
RetrofitManager.getInstance()

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.GameUtils
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.exposure.meta.MetaUtil
@ -91,8 +92,7 @@ object PackageRepository {
/**
* 预留方法,如果想手动初始化可以调用
*/
@JvmStatic
fun initData() {
fun initData(onPackageNameReceivedCallback: (() -> Unit)? = null) {
if (mIsInitialisingData) return
mIsInitialisingData = true
@ -104,17 +104,25 @@ object PackageRepository {
Single.zip<Result<Any?>, Result<Any?>, Result<Any?>>(
Single.create { emitter ->
val list = PackageUtils.getAllPackageName(mApplication)
val list = PackageHelper.getInstalledPackageNameList(mApplication, 0)
uploadAppList()
// 回调包名获取结果
onPackageNameReceivedCallback?.invoke()
initFilterPackage(list) { filteredList ->
emitter.onSuccess(Result.success(null))
mInstalledPkgSet.addAll(filteredList)
notifyInstallPkgData()
loadInstalledGameDigestAndNotifyData(packageFilterManager.packageKey, filteredList)
loadInstalledGameDigestAndNotifyData(
packageKey = packageFilterManager.packageKey,
filteredList = filteredList,
isVGame = false,
updateInstallStatus = true,
fromInit = true
)
}
},
Single.create { emitter ->
// 畅玩游戏更新
@ -156,7 +164,7 @@ object PackageRepository {
* 初始化光环后台收录的安装包
*/
private fun initFilterPackage(
list: MutableList<String>,
list: List<String>,
callbackClosure: ((list: ArrayList<String>) -> Unit)? = null
) {
packageFilterManager.updateFilterPackages(list, false, callbackClosure)
@ -249,13 +257,15 @@ object PackageRepository {
* @param onWorkerThreadOnly 是否在工作线程执行
* @param isVGame 包名列表是否为畅玩游戏
* @param updateInstallStatus 更新安装状态 (通过 EventBus 来进行)
* @param fromInit 是否来自数据首次初始化
*/
@SuppressLint("CheckResult")
private fun loadInstalledGameDigestAndNotifyData(
packageKey: String,
filteredList: ArrayList<String>,
isVGame: Boolean = false,
updateInstallStatus: Boolean = false
updateInstallStatus: Boolean = false,
fromInit: Boolean = false
) {
var isNotifyUpdate = false
val maxPageCount = (filteredList.size / PAGE_SIZE) + 1
@ -284,7 +294,7 @@ object PackageRepository {
for (game in validGames) {
val shouldNotifyChanges =
validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus)
validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus, fromInit)
if (!isNotifyUpdate && shouldNotifyChanges) {
isNotifyUpdate = true
}
@ -310,7 +320,8 @@ object PackageRepository {
game: GameEntity,
pkgName: String,
isVGame: Boolean,
updateInstallStatus: Boolean
updateInstallStatus: Boolean,
fromInit: Boolean = false
): Boolean {
if (ghId == null || ghId == game.id) {
gameInstalled.add(GameInstall.transformGameInstall(game, pkgName, isVGame))
@ -321,7 +332,7 @@ object PackageRepository {
if (updateInstallStatus) {
EventBus.getDefault()
.post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
.post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version, fromInit))
}
if (isCanUpdate || isCanPluggable) {

View File

@ -374,12 +374,14 @@ class HaloPersonalFragment : BaseLazyFragment() {
}
mSuperiorChain?.registerInferiorChain(mPriorityChain)
startBannerAutoPlay()
}
override fun onFragmentPause() {
super.onFragmentPause()
mSuperiorChain?.unregisterInferiorChain(mPriorityChain)
stopBannerAutoPlay()
}
@SuppressLint("CheckResult", "SetTextI18n")
@ -1011,7 +1013,7 @@ class HaloPersonalFragment : BaseLazyFragment() {
}
private fun startBannerAutoPlay() {
if (mPersonalBannerAdapter.getActualSize() < 2) return
if (!::mPersonalBannerAdapter.isInitialized || mPersonalBannerAdapter.getActualSize() < 2) return
stopBannerAutoPlay()
mLooperHandle.sendEmptyMessageDelayed(mSlideLooperKey, BANNER_LOOP_TIME)
}

View File

@ -20,7 +20,9 @@ import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.json.JSONArray
import org.json.JSONObject
@ -75,7 +77,7 @@ class InstalledGameDialog(
jsonObject.put("package", game.packageName)
objects.put(jsonObject)
}
val requestBody = RequestBody.create(MediaType.parse("application/json"), objects.toString())
val requestBody = objects.toString().toRequestBody("application/json".toMediaTypeOrNull())
RetrofitManager.getInstance().api
.postPlayedGames(UserManager.getInstance().userId, requestBody)
.subscribeOn(Schedulers.io())

View File

@ -25,7 +25,9 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
@ -259,10 +261,8 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica
fun toggleComment(answerId: String, isCommentable: Boolean) {
val params = HashMap<String, Boolean>()
params["commentable"] = isCommentable
val body = RequestBody.create(
MediaType.parse("application/json"),
JSONObject(params as Map<*, *>).toString()
)
val body = JSONObject(params as Map<*, *>).toString()
.toRequestBody("application/json".toMediaTypeOrNull())
RetrofitManager.getInstance()
.api

View File

@ -26,7 +26,9 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONArray
@ -144,7 +146,7 @@ class ArticleEditViewModel(application: Application) : BaseRichEditorViewModel(a
if (draftEntity?.id != null) {
articleBody.put("draft_id", draftEntity?.id)
}
val body = RequestBody.create(MediaType.parse("application/json"), articleBody.toString())
val body = articleBody.toString().toRequestBody("application/json".toMediaTypeOrNull())
val observable = if (detailEntity == null) {
mApi.postCommunityArticle(mSelectCommunityData?.id, body)
} else {
@ -226,7 +228,7 @@ class ArticleEditViewModel(application: Application) : BaseRichEditorViewModel(a
if (mSelectCommunityData != null && mSelectCommunityData!!.id.isNotEmpty()) {
articleBody.put("community_id", mSelectCommunityData!!.id)
}
val body = RequestBody.create(MediaType.parse("application/json"), articleBody.toString())
val body = articleBody.toString().toRequestBody("application/json".toMediaTypeOrNull())
val observable = if (draftEntity?.id != null) {
mApi.patchCommunityArticleDrafts(UserManager.getInstance().userId, draftEntity?.id, body)
} else {

View File

@ -40,7 +40,7 @@ class GameDefaultAdapter(
val intent = Intent()
intent.putExtra(
GameEntity::class.java.simpleName,
GameEntity(id = entity.gameId, mIcon = entity.gameIcon, mName = entity.gameName, mCategory = entity.category)
GameEntity(_id = entity.gameId, mIcon = entity.gameIcon, mName = entity.gameName, mCategory = entity.category)
)
(mContext as Activity).setResult(Activity.RESULT_OK, intent)
(mContext as Activity).finish()

View File

@ -28,7 +28,9 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONArray
@ -266,7 +268,7 @@ class QuestionEditViewModel(application: Application) : BaseRichEditorViewModel(
}
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))
val body = RequestBody.create(MediaType.parse("application/json"), bodyJson)
val body = bodyJson.toRequestBody("application/json".toMediaTypeOrNull())
mApi.moderatorsPatchQuestion(body, UserManager.getInstance().userId, questionEntity?.id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -15,7 +15,9 @@ import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.json.JSONException
import org.json.JSONObject
@ -59,7 +61,7 @@ class QuestionsInviteViewModel(application: Application, var questionId: String?
e.printStackTrace()
}
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
RetrofitManager.getInstance().api
.postInvite(body, questionId)
.subscribeOn(Schedulers.io())

View File

@ -30,7 +30,9 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
@ -114,7 +116,7 @@ class VideoPublishViewModel(application: Application) : AndroidViewModel(applica
when {
isDraft -> {
val draftData = JSONObject(videoEntity.toJson()).put("local_path", videoPath).toString()
val body = RequestBody.create(MediaType.parse("application/json"), draftData)
val body = draftData.toRequestBody("application/json".toMediaTypeOrNull())
postDraft(body)
}
videoPatch != null -> {
@ -150,7 +152,7 @@ class VideoPublishViewModel(application: Application) : AndroidViewModel(applica
private fun patchVideo(jsonObject: JSONObject, videoId: String) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
mApi.patchBbsVideo(videoId, body)
.compose(observableToMain())
.subscribe(object : Response<ResponseBody>() {
@ -208,7 +210,7 @@ class VideoPublishViewModel(application: Application) : AndroidViewModel(applica
private fun postVideo(jsonObject: JSONObject) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
mApi.postBbsVideo(body)
.compose(observableToMain())
.subscribe(object : Response<JsonObject>() {

View File

@ -72,7 +72,7 @@ public class PackageChangeBroadcastReceiver extends BroadcastReceiver {
PackageHelper.refreshLocalPackageList();
String versionName = PackageUtils.getVersionNameByPackageName(packageName);
EBPackage installEb = new EBPackage(EBPackage.TYPE_INSTALLED, packageName, versionName);
EBPackage installEb = new EBPackage(EBPackage.TYPE_INSTALLED, packageName, versionName, false);
if (PackageUtils.isAppOnForeground(context)) {
PackageObserver.onPackageChanged(installEb, null);
EventBus.getDefault().post(installEb);
@ -102,7 +102,7 @@ public class PackageChangeBroadcastReceiver extends BroadcastReceiver {
InstallUtils.getInstance().removeUninstall(packageName);
PackageHelper.refreshLocalPackageList();
EBPackage uninstallEb = new EBPackage(EBPackage.TYPE_UNINSTALLED, packageName, "");
EBPackage uninstallEb = new EBPackage(EBPackage.TYPE_UNINSTALLED, packageName, "", false);
PackageObserver.onPackageChanged(uninstallEb, null);
EventBus.getDefault().post(uninstallEb);
if (webviewPackageName.equals(packageName)) {
@ -118,7 +118,7 @@ public class PackageChangeBroadcastReceiver extends BroadcastReceiver {
Utils.log(TAG, "替换了:" + packageName + "包名的程序");
String versionName = PackageUtils.getVersionNameByPackageName(packageName);
EBPackage updateEb = new EBPackage(EBPackage.TYPE_REPLACED, packageName, versionName);
EBPackage updateEb = new EBPackage(EBPackage.TYPE_REPLACED, packageName, versionName, false);
EventBus.getDefault().post(updateEb);
PackageObserver.onPackageChanged(updateEb, null);
if (webviewPackageName.equals(packageName)) {

View File

@ -4,6 +4,7 @@ import android.content.Context;
import com.gh.common.constant.Config;
import com.gh.gamecenter.common.retrofit.BaseRetrofitManager;
import com.gh.gamecenter.feature.retrofit.WGameCPMApiService;
import com.gh.gamecenter.retrofit.service.ApiService;
import com.gh.gamecenter.retrofit.service.VApiService;
import com.halo.assistant.HaloApp;
@ -20,6 +21,7 @@ public class RetrofitManager extends BaseRetrofitManager {
private final ApiService mNewApiService;
private final ApiService mUploadApiService;
private final VApiService mVApiService;
private final WGameCPMApiService mWGameCPMApiService;
private RetrofitManager() {
Context context = HaloApp.getInstance().getApplicationContext();
@ -27,7 +29,8 @@ public class RetrofitManager extends BaseRetrofitManager {
mApiService = provideService(okHttpNormalConfig, Config.API_HOST, ApiService.class);
mNewApiService = provideService(okHttpNormalConfig, Config.NEW_API_HOST, ApiService.class);
mUploadApiService = provideService(getOkHttpConfig(context, UPLOAD_CALL_TIME_OUT, 1), Config.API_HOST, ApiService.class);
mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class);;
mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class);
mWGameCPMApiService = provideService(okHttpNormalConfig, Config.WGAME_CPM_API_HOST, WGameCPMApiService.class);
}
public static RetrofitManager getInstance() {
@ -50,6 +53,10 @@ public class RetrofitManager extends BaseRetrofitManager {
return mVApiService;
}
public WGameCPMApiService getWGameCPMApi() {
return mWGameCPMApiService;
}
private static class SingletonHolder {
private static final RetrofitManager INSTANCE = new RetrofitManager();
}

View File

@ -3153,7 +3153,7 @@ public interface ApiService {
/**
* QQ小游戏-专题-换一换
*/
@GET("games/qq_mini/columns/{column_id}/games?page=1&page_size=30")
@GET("games/qq_mini/columns/{column_id}/games?page=2&page_size=30")
Observable<List<GameEntity>> getSubjectQGame(@Path("column_id") String columnId);
/**
@ -3186,7 +3186,7 @@ public interface ApiService {
/**
* 微信小游戏-专题-换一换
*/
@GET("wechat_game/columns/{column_id}/games?page=1&page_size=30")
@GET("wechat_game/columns/{column_id}/games?page=2&page_size=30")
Observable<List<GameEntity>> getSubjectWGame(@Path("column_id") String columnId);
/**

View File

@ -3,9 +3,12 @@ package com.gh.gamecenter.search
import com.gh.gamecenter.entity.SearchSubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import io.reactivex.Observable
import io.reactivex.Single
interface ISearchGameResultRepository {
fun getSearchGame(key: String?, page: Int): Observable<List<GameEntity>>
fun getSearchSubject(key: String?, page: Int): Observable<List<SearchSubjectEntity>>
fun getWGameCPMGameList(): Single<MutableList<GameEntity>>
}

View File

@ -1,6 +1,9 @@
package com.gh.gamecenter.search
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Shader
import android.graphics.Typeface
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.text.TextUtils
@ -15,6 +18,7 @@ import androidx.viewpager.widget.PagerAdapter
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
@ -31,7 +35,7 @@ import com.gh.gamecenter.databinding.TabItemSearchDefaultRankBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.feature.entity.DiscoveryTagEntity
import com.gh.gamecenter.feature.entity.HotTagEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.google.android.flexbox.FlexboxLayout
@ -43,7 +47,7 @@ import org.json.JSONObject
open class SearchDefaultFragment : BaseFragment<Any>() {
private var mSearchDiscoveryTagList: List<DiscoveryTagEntity>? = null
private var mHotTagList: List<HotTagEntity>? = null
protected var mRankList: List<SettingsEntity.Search.RankList>? = null
protected lateinit var mBinding: FragmentSearchDefaultBinding
@ -62,28 +66,28 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
private val mDao by lazy { provideDao() }
private val mSearchDiscoveryTagClickListener: (Int) -> Unit = {
val tag = mSearchDiscoveryTagList!![it]
val keyword = tag.keyword
if (keyword.isNotEmpty()) {
PageSwitchDataHelper.pushCurrentPageData(
hashMapOf(
Pair(PageSwitchDataHelper.PAGE_BUSINESS_TYPE, "游戏搜索-搜索发现"),
Pair(PageSwitchDataHelper.PAGE_BUSINESS_ID, tag.id ?: ""),
Pair(PageSwitchDataHelper.PAGE_BUSINESS_NAME, tag.text ?: " ")
)
private val mHotTagClickListener: (Int) -> Unit = {
val tag = mHotTagList!![it]
NewFlatLogUtils.logSearchHotTagClick(
tag.name ?: "",
tag.type ?: "",
tag.link ?: "",
tag.text ?: ""
)
DataLogUtils.uploadHotTagLog(context, tag.name)
PageSwitchDataHelper.pushCurrentPageData(
hashMapOf(
Pair(PageSwitchDataHelper.PAGE_BUSINESS_TYPE, "游戏搜索-热门标签"),
Pair(PageSwitchDataHelper.PAGE_BUSINESS_ID, tag.id ?: ""),
Pair(PageSwitchDataHelper.PAGE_BUSINESS_NAME, tag.name ?: " ")
)
SensorsBridge.trackEvent("SearchLabelClick", "label_name", tag.text ?: "", "label_id", tag.id ?: "")
SensorsBridge.trackSearchDiscoveryClick(
labelName = tag.text ?: "",
labelId = tag.id ?: "",
searchContent = keyword,
position = it
)
mViewModel?.add(keyword)
EventBus.getDefault().post(EBSearch("history", keyword))
Util_System_Keyboard.hideSoftKeyboardByIBinder(context, mBinding.historyFlex.windowToken)
}
)
SensorsBridge.trackEvent("SearchLabelClick", "label_name", tag.name ?: "", "label_id", tag.id ?: "")
val exposureEvent = ExposureEvent.createEvent(
null,
source = listOf(ExposureSource("首页搜索", ""), ExposureSource("热门标签", tag.name ?: ""))
)
DirectUtils.directToLinkPage(requireContext(), tag, "(搜索-${tag.name})", "", exposureEvent) // 不需要path
}
override fun getLayoutId(): Int {
@ -136,20 +140,16 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
}
mViewModel?.isExistRankList = mRankList?.isNotEmpty() == true
mSearchDiscoveryTagList = Config.getSettings()?.search?.discoveryTag
mViewModel?.isExistSearchDiscoveryTag = mSearchDiscoveryTagList?.isNotEmpty() == true
mHotTagList = Config.getSettings()?.search?.hotTag
mViewModel?.isExistHotTag = mHotTagList?.isNotEmpty() == true
updateHistorySearchView(null)
mViewModel?.historySearchLiveData?.observe(viewLifecycleOwner) {
updateHistorySearchView(it)
}
mBinding.searchDiscoveryTagFlexContainer.setLimitHeight(mFlexMaxHeight)
createFlexContent(
mBinding.searchDiscoveryTagFlex,
getTagListString(),
clickListener = mSearchDiscoveryTagClickListener
)
mBinding.hotTagFlexContainer.setLimitHeight(mFlexMaxHeight)
createFlexContent(mBinding.hotTagFlex, getTagListString(), true, clickListener = mHotTagClickListener)
initHeadView()
initRankViewPager()
}
@ -178,12 +178,12 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
})
}
}
mBinding.searchDiscoveryHeadContainer.headTitle.text = getString(R.string.search_hot)
mBinding.searchDiscoveryHeadContainer.headTitle.textSize = 16F
mBinding.searchDiscoveryHeadContainer.headActionTv.visibility = View.GONE
mBinding.searchDiscoveryTagHeadContainer.headTitle.text = getString(R.string.search_discovery_tag)
mBinding.searchDiscoveryTagHeadContainer.headTitle.textSize = 16F
mBinding.searchDiscoveryTagHeadContainer.headActionTv.visibility = View.GONE
mBinding.hotHeadContainer.headTitle.text = getString(R.string.search_hot)
mBinding.hotHeadContainer.headTitle.textSize = 16F
mBinding.hotHeadContainer.headActionTv.visibility = View.GONE
mBinding.hotTagHeadContainer.headTitle.text = getString(R.string.search_hot_tag)
mBinding.hotTagHeadContainer.headTitle.textSize = 16F
mBinding.hotTagHeadContainer.headActionTv.visibility = View.GONE
}
protected open fun initRankViewPager() {
@ -318,8 +318,8 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
mBinding.historyHeadContainer.root.visibility =
if (mViewModel?.isExistHistory == true) View.VISIBLE else View.GONE
mBinding.historyFlex.visibility = if (mViewModel?.isExistHistory == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryTagHeadContainer.root.layoutParams =
(mBinding.searchDiscoveryTagHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
mBinding.hotTagHeadContainer.root.layoutParams =
(mBinding.hotTagHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
setMargins(
0,
if (mViewModel?.isExistHistory == true) 16F.dip2px() else 0,
@ -327,22 +327,21 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
0
)
}
mBinding.searchDiscoveryHeadContainer.root.layoutParams =
(mBinding.searchDiscoveryHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
mBinding.hotHeadContainer.root.layoutParams =
(mBinding.hotHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
setMargins(
0,
if (mViewModel?.isExistHistory == false && mViewModel?.isExistSearchDiscoveryTag == false) 16F.dip2px() else 0,
if (mViewModel?.isExistHistory == false && mViewModel?.isExistHotTag == false) 16F.dip2px() else 0,
0,
0
)
}
mBinding.searchDiscoveryTagHeadContainer.root.visibility =
if (mViewModel?.isExistSearchDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryTagFlex.visibility =
if (mViewModel?.isExistSearchDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryHeadContainer.root.visibility =
mBinding.hotTagHeadContainer.root.visibility =
if (mViewModel?.isExistHotTag == true) View.VISIBLE else View.GONE
mBinding.hotTagFlex.visibility = if (mViewModel?.isExistHotTag == true) View.VISIBLE else View.GONE
mBinding.hotHeadContainer.root.visibility =
if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryList.visibility = if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
mBinding.hotList.visibility = if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
mBinding.rankTabLayout.visibility = if (mViewModel?.isExistRankList == true) View.VISIBLE else View.GONE
mBinding.rankTabIndicator.visibility = if (mViewModel?.isExistRankList == true) View.VISIBLE else View.GONE
mBinding.rankViewPager.visibility = if (mViewModel?.isExistRankList == true) View.VISIBLE else View.GONE
@ -364,9 +363,9 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
private fun getTagListString(): List<String> {
val list = ArrayList<String>()
if (mSearchDiscoveryTagList != null) {
for (entity in mSearchDiscoveryTagList!!) {
entity.text?.let { list.add(it) }
if (mHotTagList != null) {
for (entity in mHotTagList!!) {
entity.name?.let { list.add(it) }
}
}
return list
@ -375,6 +374,7 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
fun createFlexContent(
flexView: FlexboxLayout,
contentList: List<String>?,
isHotTag: Boolean = false,
clickListener: (Int) -> Unit
) {
@ -388,12 +388,16 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 24F.dip2px())
flexCell.layoutParams = params
flexCell.setSingleLine()
flexCell.ellipsize = TextUtils.TruncateAt.END
flexCell.gravity = Gravity.CENTER
flexCell.textSize = 12F
flexCell.text = StringUtils.shrinkStringWithDot(contentList[index], 6)
flexCell.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
if (isHotTag && !mHotTagList.isNullOrEmpty() && mHotTagList!![index].isGuessSearch) {
createSmartHotTagStyle(flexCell, contentList[index])
} else {
flexCell.setSingleLine()
flexCell.ellipsize = TextUtils.TruncateAt.END
flexCell.gravity = Gravity.CENTER
flexCell.textSize = 12F
flexCell.text = StringUtils.shrinkStringWithDot(contentList[index], 6)
flexCell.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
}
flexCell.setPadding(8F.dip2px(), 0, 8F.dip2px(), 0)
flexCell.background = if (mIsDarkModeOn) GradientDrawable().apply {
setStroke(0.5F.dip2px(), Color.parseColor("#21FFFFFF"))
@ -405,6 +409,30 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
}
}
private fun createSmartHotTagStyle(flexCell: TextView, name: String) {
flexCell.setDrawableStart(R.drawable.ic_smart_search)
flexCell.compoundDrawablePadding = 4F.dip2px()
flexCell.gravity = Gravity.CENTER_VERTICAL
flexCell.typeface = Typeface.DEFAULT_BOLD
flexCell.textSize = 12F
flexCell.text = StringUtils.shrinkStringWithDot(name, 6)
flexCell.setTextColor(Color.WHITE)
val colors =
intArrayOf(com.gh.gamecenter.common.R.color.text_FFB749.toColor(requireContext()), com.gh.gamecenter.common.R.color.text_FF6D3C.toColor(requireContext()))
val position = floatArrayOf(0F, 1F)
val linearGradient = LinearGradient(
0F,
0F,
flexCell.paint.textSize * flexCell.text.length,
0F,
colors,
position,
Shader.TileMode.CLAMP
)
flexCell.paint.shader = linearGradient
flexCell.invalidate()
}
private fun postExposureEvent(index: Int) {
mRankList?.safelyGetInRelease(index)?.content?.forEach {
if (it.link.type == "game") {
@ -419,15 +447,11 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
super.onDarkModeChanged()
initHeadView()
mBinding.rootContainer.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
mBinding.searchDiscoveryList.adapter?.run {
mBinding.hotList.adapter?.run {
notifyItemRangeChanged(0, itemCount)
}
mViewModel?.historySearchLiveData?.value?.let { updateHistorySearchView(it) }
createFlexContent(
mBinding.searchDiscoveryTagFlex,
getTagListString(),
clickListener = mSearchDiscoveryTagClickListener
)
createFlexContent(mBinding.hotTagFlex, getTagListString(), true, clickListener = mHotTagClickListener)
}
protected open fun provideDao(): ISearchHistoryDao =

View File

@ -11,7 +11,7 @@ class SearchDefaultViewModel(private val dao: ISearchHistoryDao) : ViewModel() {
it
}
var isExistHotSearch: Boolean = false
var isExistSearchDiscoveryTag: Boolean = false
var isExistHotTag: Boolean = false
var isExistHistory: Boolean = false
var isExistRankList: Boolean = false

View File

@ -214,7 +214,7 @@ class SearchGameIndexFragment : ListFragment<GameEntity, SearchGameResultViewMod
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
if (!busFour.fromInit && busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}

View File

@ -13,6 +13,7 @@ import com.gh.gamecenter.common.view.DrawableView
import com.gh.gamecenter.databinding.SearchGameIndexItemBinding
import com.gh.gamecenter.databinding.SearchSubjectItemBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.feature.databinding.GameItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
@ -85,7 +86,7 @@ class SearchSubjectItemViewHolder(var binding: SearchSubjectItemBinding) : Recyc
binding.run {
subjectRv.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
subjectRv.adapter = SearchSubjectAdapter(context, entity.getFilterGame(), "($type-专题)") {
subjectRv.adapter = SearchSubjectAdapter(context, entity.getFilterGame(), "($type-专题)", key) {
dao?.add(key)
if (itemData.adConfig != null) {
NewFlatLogUtils.logClickGameAd(
@ -119,7 +120,17 @@ class SearchSubjectItemViewHolder(var binding: SearchSubjectItemBinding) : Recyc
headContainer.headActionTv.setOnClickListener {
dao?.add(key)
if (entity.columnId.isNotEmpty()) {
DirectUtils.directToSubject(context, entity.columnId, entity.name, "($type-专题)")
DirectUtils.directToSubject(
context,
entity.columnId,
entity.name,
"($type-专题)",
subjectType = if (entity.isWGameSubjectCPM) {
SubjectData.SubjectType.WECHAT_GAME_CPM
} else {
SubjectData.SubjectType.NORMAL
}
)
} else if (entity.adId.isNotEmpty() && entity.codeId.isNotEmpty()) {
SubjectActivity.startAdSubjectActivity(
context,

View File

@ -58,7 +58,7 @@ class SearchGameResultAdapter(
private val dao: ISearchHistoryDao,
val listViewModel: SearchGameResultViewModel,
val entrance: String,
val type: String,
var type: String,
val sourceEntrance: String
) : ListAdapter<SearchItemData>(context), IExposable {
@ -752,7 +752,7 @@ class SearchGameResultAdapter(
gameEntity.name ?: "",
gameEntity.categoryChinese
)
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
MiniGameItemHelper.trackMiniGameClick(
gameEntity = gameEntity,
location = "小游戏搜索结果列表",

View File

@ -376,6 +376,7 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
this.mKey = key
this.mType = type
mAdapter?.key = key
mAdapter?.type = type
mAdapter?.clearAdIdSet()
mListViewModel?.updateSearchKeyWithType(key, type)
mListViewModel?.clearSearchSubjects()
@ -423,7 +424,7 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
if (!busFour.fromInit && busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}

View File

@ -4,14 +4,17 @@ import com.gh.common.constant.Config
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.SearchSubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRemoteDataSource
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
import com.halo.assistant.HaloApp
import io.reactivex.Observable
import io.reactivex.Single
import java.net.URLEncoder
class SearchGameResultRepository(
private val mApi: ApiService = RetrofitManager.getInstance().api
private val mApi: ApiService = RetrofitManager.getInstance().api,
private val mWGameSubjectCPMDataSource: WGameSubjectCPMRemoteDataSource = WGameSubjectCPMRemoteDataSource()
) : ISearchGameResultRepository {
override fun getSearchGame(
@ -31,4 +34,8 @@ class SearchGameResultRepository(
override fun getSearchSubject(key: String?, page: Int): Observable<List<SearchSubjectEntity>> {
return mApi.getSearchSubject(key, page)
}
override fun getWGameCPMGameList(): Single<MutableList<GameEntity>> {
return mWGameSubjectCPMDataSource.getRecommendCPMList(1)
}
}

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModelProvider
import com.gh.ad.AdDelegateHelper
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.PackageHelper
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadParams
@ -22,7 +23,6 @@ import com.gh.gamecenter.entity.SearchSubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.minigame.MiniGameSearchResultRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.SearchActivity
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
@ -58,10 +58,6 @@ class SearchGameResultViewModel(
mSearchSubjects.clear()
}
override fun loadData() {
super.loadData()
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
mGameEntityList = ArrayList(list)
@ -80,31 +76,40 @@ class SearchGameResultViewModel(
refreshWrongInstallStatus()
repository.getSearchSubject(mSearchKey, mPage)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ mutableList ->
mSearchSubjects.addAll(mutableList)
.map { dataList ->
mSearchSubjects.addAll(dataList)
var cpmSearchSubject: SearchSubjectEntity? = null
mSearchSubjects.forEach {
val item = SearchItemData(subject = it)
if (it.location <= 0 || it.location > itemDataList.size) {
itemDataList.add(item)
// 微信小游戏CPM专题需要等搜索广告位插入完成后再插入
if (it.location == WGAME_CPM_SUBJECT_POSITION) {
cpmSearchSubject = it.apply { isWGameSubjectCPM = true }
} else {
itemDataList.add(it.location - 1, item)
val item = SearchItemData(subject = it)
if (it.location <= 0 || it.location > itemDataList.size) {
itemDataList.add(item)
} else {
itemDataList.add(it.location - 1, item)
}
}
}
cpmSearchSubject to dataList
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ result ->
// 处理初始化列表且游戏列表size为0的情况
handleLoadStatusWhenGameListIsEmpty(list, itemDataList)
if (mIsManuallySearch) {
if (mSearchKey == AdDelegateHelper.gameSearchKeyword) {
updateAdConfigAndDecorateList(itemDataList, list)
updateAdConfigAndDecorateList(itemDataList, list, result.first)
} else {
AdDelegateHelper.requestAdConfig(false, mSearchKey ?: "") {
updateAdConfigAndDecorateList(itemDataList, list)
updateAdConfigAndDecorateList(itemDataList, list, result.first)
}
}
} else {
postResultList(itemDataList, list)
decorateWithWGameSubjectCPM(itemDataList, list, result.first)
}
}, {
it.printStackTrace()
@ -114,7 +119,11 @@ class SearchGameResultViewModel(
}
@SuppressLint("CheckResult")
private fun updateAdConfigAndDecorateList(itemDataList: ArrayList<SearchItemData>, list: MutableList<GameEntity>) {
private fun updateAdConfigAndDecorateList(
itemDataList: ArrayList<SearchItemData>,
list: MutableList<GameEntity>,
cpmSubjectEntity: SearchSubjectEntity?
) {
mGameSearchAdList =
AdDelegateHelper.getGameSearchAdList().filter { AdDelegateHelper.shouldShowGameSearchAd(it) }.toArrayList()
.apply { sortBy { it.position } }
@ -166,18 +175,18 @@ class SearchGameResultViewModel(
Single.zip(requestSingleList) {}
.compose(singleToMain())
.subscribe({
decorateListWithAd(itemDataList, decoratedItemDataList, list)
decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity)
}, {
decorateListWithAd(itemDataList, decoratedItemDataList, list)
decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity)
})
} else {
decorateListWithAd(itemDataList, decoratedItemDataList, list)
decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity)
}
} else {
decorateListWithThirdPartyAdOnly(decoratedItemDataList, thirdPartyAdList, list)
decorateListWithThirdPartyAdOnly(decoratedItemDataList, thirdPartyAdList, list, cpmSubjectEntity)
}
} else {
postResultList(itemDataList, list)
decorateWithWGameSubjectCPM(itemDataList, list, cpmSubjectEntity)
}
}
@ -190,19 +199,21 @@ class SearchGameResultViewModel(
private fun decorateListWithThirdPartyAdOnly(
decoratedItemDataList: ArrayList<SearchItemData>,
thirdPartyAdList: List<AdConfig>,
list: List<GameEntity>
list: List<GameEntity>,
cpmSubjectEntity: SearchSubjectEntity?
) {
thirdPartyAdList.forEach {
decoratedItemDataList.add(it.position - 1, SearchItemData(ad = it.thirdPartyAd, adConfig = it))
SPUtils.setLong(Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + it.position, System.currentTimeMillis())
}
postResultList(decoratedItemDataList, list)
decorateWithWGameSubjectCPM(decoratedItemDataList, list, cpmSubjectEntity)
}
private fun decorateListWithAd(
itemDataList: ArrayList<SearchItemData>,
decoratedItemDataList: ArrayList<SearchItemData>,
list: List<GameEntity>
list: List<GameEntity>,
cpmSubjectEntity: SearchSubjectEntity?
) {
val adGameOneIdSet = HashSet<String>() // 展示样式为单个游戏时记录游戏ID避免重复
for ((index, position) in mAdPositionSet!!.withIndex()) {
@ -270,7 +281,41 @@ class SearchGameResultViewModel(
break
}
}
postResultList(decoratedItemDataList, list)
decorateWithWGameSubjectCPM(decoratedItemDataList, list, cpmSubjectEntity)
}
@SuppressLint("CheckResult")
private fun decorateWithWGameSubjectCPM(
resultList: ArrayList<SearchItemData>,
list: List<GameEntity>,
cpmSubjectEntity: SearchSubjectEntity?
) {
// 微信小游戏CPM专题搜索结果存在则请求CPM接口获取微信小游戏列表数据并将列表数据插入缓存的CPM专题中
// 再根据location的值固定为4将CPM专题插入搜索结果列表中
// 相关需求https://jira.shanqu.cc/browse/GHZSCY-6710
cpmSubjectEntity?.let { subject ->
if (subject.games.isNotEmpty()) {
Single.just(subject.games.toMutableList())
} else {
repository.getWGameCPMGameList()
.onErrorReturnItem(mutableListOf())
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
val cpmSearchItemData = SearchItemData(subject = subject.apply { games = it })
if (subject.location <= 0 || subject.location > resultList.size) {
resultList.add(cpmSearchItemData)
} else {
resultList.add(subject.location - 1, cpmSearchItemData)
}
postResultList(resultList, list)
},
{
postResultList(resultList, list)
})
} ?: postResultList(resultList, list)
}
@SuppressLint("CheckResult")
@ -386,6 +431,7 @@ class SearchGameResultViewModel(
companion object {
const val AD_SUBJECT_GAME_MAX_COUNT = 8
const val WGAME_CPM_SUBJECT_POSITION = 4
}
}

View File

@ -6,6 +6,7 @@ import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.game.horizontal.GameHorizontalSimpleItemViewHolder
import com.lightgame.adapter.BaseRecyclerAdapter
@ -13,6 +14,7 @@ class SearchSubjectAdapter(
context: Context,
private val mList: List<GameEntity>,
private val mEntrance: String,
private val mKey: String,
private val clickCallback: ((GameEntity) -> Unit)
) : BaseRecyclerAdapter<GameHorizontalSimpleItemViewHolder>(context) {
@ -34,7 +36,16 @@ class SearchSubjectAdapter(
GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name)
root.setOnClickListener {
clickCallback.invoke(gameEntity)
GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, gameEntity.exposureEvent)
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity)
MiniGameItemHelper.trackMiniGameClick(
gameEntity = gameEntity,
location = "小游戏搜索结果列表",
searchContent = mKey,
)
} else {
GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, gameEntity.exposureEvent)
}
}
}
}

View File

@ -3,9 +3,9 @@ package com.gh.gamecenter.search.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.utils.SensorsBridge
import io.reactivex.disposables.CompositeDisposable
class SearchTabViewModel : ViewModel() {
@ -21,7 +21,8 @@ class SearchTabViewModel : ViewModel() {
GlobalActivityManager.getCurrentPageEntity().pageName,
location,
searchKeyAndType.value?.first ?: "",
searchKeyAndType.value?.second ?: "",
searchKeyAndType.value?.let {
SearchActivity.toTrackSearchType(it.second) } ?: "",
text ?: "",
position
)

View File

@ -16,7 +16,9 @@ import com.lightgame.utils.Utils.toast
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import retrofit2.HttpException
class AddKaiFuViewModel(application: Application) : AndroidViewModel(application) {
@ -266,7 +268,7 @@ class AddKaiFuViewModel(application: Application) : AndroidViewModel(application
private fun postData(postList: ArrayList<ServerCalendarEntity>) {
val body = RequestBody.create(MediaType.parse("application/json"), GsonUtils.toJson(postList))
val body = GsonUtils.toJson(postList).toRequestBody("application/json".toMediaTypeOrNull())
RetrofitManager.getInstance().api.addKaifu(body, mGameId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -11,7 +11,9 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
@ -35,7 +37,7 @@ class PatchKaifuViewModel(application: Application) : AndroidViewModel(applicati
val jsonObject = JSONObject()
jsonObject.put("note", patchName)
jsonObject.put("remark", patchRemark)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
apiService.patchKaifu(body, gameId, serverEntity!!.id)
} else {
apiService.deleteKaifu(gameId, serverEntity!!.id)

View File

@ -228,7 +228,7 @@ class SubjectAdapter(
DataCollectionUtils.uploadClick(mContext, "列表", subjectData.subjectName, gameEntity.name)
if (gameEntity.isMiniGame()) {
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.launchMiniGame(gameEntity)
val pageLocation = mViewModel.pageLocation
MiniGameItemHelper.trackMiniGameClick(
gameEntity = gameEntity,

View File

@ -207,7 +207,7 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
if (!busFour.fromInit && busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}

View File

@ -3,6 +3,8 @@ package com.gh.gamecenter.subject
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.minigame.qq.QGameSubjectListRepository
import com.gh.gamecenter.minigame.qq.QGameSubjectRepository
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMListRepository
import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRepository
import com.gh.gamecenter.minigame.wechat.WGameSubjectListRepository
import com.gh.gamecenter.minigame.wechat.WGameSubjectRepository
@ -10,12 +12,14 @@ object SubjectRepositoryFactory {
fun createRepo(subjectType: SubjectData.SubjectType): ISubjectRepository = when(subjectType) {
SubjectData.SubjectType.QQ_GAME -> QGameSubjectRepository()
SubjectData.SubjectType.WECHAT_GAME -> WGameSubjectRepository()
SubjectData.SubjectType.WECHAT_GAME_CPM -> WGameSubjectCPMRepository()
else -> SubjectRepository()
}
fun createListRepo(subjectType: SubjectData.SubjectType): ISubjectListRepository = when(subjectType) {
SubjectData.SubjectType.QQ_GAME -> QGameSubjectListRepository()
SubjectData.SubjectType.WECHAT_GAME -> WGameSubjectListRepository()
SubjectData.SubjectType.WECHAT_GAME_CPM -> WGameSubjectCPMListRepository()
else -> SubjectListRepository()
}
}

View File

@ -197,7 +197,7 @@ class TagsListFragment : ListFragment<GameEntity, TagsListViewModel>() {
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
if (!busFour.fromInit && busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}

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