Compare commits

...

233 Commits

Author SHA1 Message Date
d98b00f2dc 重置 2025-01-22 17:55:46 +08:00
8127ba7bd0 批量注册用户 2025-01-21 17:44:54 +08:00
158c36a6b1 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-20 17:03:20 +08:00
c4184b9cbb sdk只支持正式环境 2025-01-20 16:57:06 +08:00
585153cc0e 新增获取区服失败提示处理 2025-01-20 16:50:04 +08:00
112ce8da4c fix: 修复 build_with_simple_backup.sh 不能在 mac Bash 上编译的问题 2025-01-20 14:49:28 +08:00
88cfb99a12 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-17 18:24:45 +08:00
b9fbad85b2 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-17 18:22:36 +08:00
86f8aaf1e1 sdk改为只支持正式环境 2025-01-16 17:27:58 +08:00
59da6eb171 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-16 10:04:05 +08:00
4d5af5044f feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 17:58:10 +08:00
30105b3cc2 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 17:23:56 +08:00
f0b4085455 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 17:17:25 +08:00
4e896ceccf feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
52a3d4a9a7 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
8df60fcc1d feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
9946dd0df3 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
e3e218dd2b feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
e089347f8c feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
174ca03ce4 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
6adae085b1 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
6a3b164177 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
d08d1bf8e9 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
7ece9b0d4e feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
c45a2c34eb feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
06b4c3f8ab feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
7f71c1d740 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
c1c2078294 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
34d31647c3 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
e6badcb7c3 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:59:00 +08:00
8e1973bad1 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:58:59 +08:00
d9a08037b5 feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:58:59 +08:00
a65fb3535d feat:https://jira.shanqu.cc/browse/GHZSCY-6976 奇游加速SDK接入—客户端 2025-01-15 16:58:56 +08:00
f6d5d6f719 ci 2025-01-15 16:56:09 +08:00
10cc81e7fc Merge branch 'feat/va-relative' into 'dev'
feat: 同步va的release代码

See merge request halo/android/assistant-android!2042
2025-01-15 15:00:42 +08:00
60a50f5722 feat: 同步va的release代码 2025-01-15 14:58:32 +08:00
644881c14f Merge branch 'fix/package_check_stuck_issue' into 'dev'
fix: 修复包名检测弹窗弹出较慢的问题

See merge request halo/android/assistant-android!2041
2025-01-15 14:48:19 +08:00
a0e43930a0 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/ad/AdDelegateHelper.kt
#	dependencies.gradle
#	module_login/src/main/java/com/gh/gamecenter/login/user/UserRepository.java
#	vasdk
2025-01-15 14:27:40 +08:00
aa5f6f4f24 fix: 修复包名检测弹窗弹出较慢的问题 2025-01-15 14:22:22 +08:00
ab7668fd81 chore: 版本更新至 5.38.8 2025-01-15 09:19:40 +08:00
c6f014c984 Merge branch 'hotfix/v5.38.7-1117/pre_download_error' into 'release'
fix: 修复预下载获取资源时,服务端报错未能正确处理的问题

See merge request halo/android/assistant-android!2040
2025-01-14 16:30:31 +08:00
c215bd195e fix: 修复预下载获取资源时,服务端报错未能正确处理的问题 2025-01-14 16:27:43 +08:00
bb73598a87 Merge branch 'hotfix/va-relative' into 'release'
fix: va_core进程没有启动导致aidl的NPE问题。

See merge request halo/android/assistant-android!2039
2025-01-14 16:24:52 +08:00
c6f70d1b4c fix: va_core进程没有启动导致aidl的NPE问题。 2025-01-14 16:23:01 +08:00
ce7f75976c Merge branch 'fix/GHZSCY-7371' into 'dev'
fix: 游戏详情-多版本插件下载问题 https://jira.shanqu.cc/browse/GHZSCY-7371

See merge request halo/android/assistant-android!2038
2025-01-14 13:45:06 +08:00
c8a7999990 fix: 游戏详情-多版本插件下载问题 https://jira.shanqu.cc/browse/GHZSCY-7371 2025-01-14 10:49:52 +08:00
0cd281a53c Merge branch 'hotfix/va-relative' into 'release'
fix: 手机不支持armeabi-v7a架构时,根据游戏来选择架构

See merge request halo/android/assistant-android!2037
2025-01-10 18:01:24 +08:00
e92d89d498 fix: 手机不支持armeabi-v7a架构时,根据游戏来选择架构 2025-01-10 17:44:03 +08:00
a22858389b chore: 版本更新至 5.38.7 2025-01-10 13:55:24 +08:00
e9d091043d Merge branch 'hotfix/va-relative' into 'release'
feat: 同步商业版VA,修复权限问题。

See merge request halo/android/assistant-android!2036
2025-01-10 11:25:46 +08:00
db4ac95094 feat: 同步商业版VA,修复权限问题。
fix: 实名认证超大UI问题
fix: sentry va relative log.
2025-01-10 11:24:45 +08:00
13be47d440 Merge branch 'fix/search-page-crash' into 'release'
fix:https://sentry.shanqu.cc/organizations/lightgame/issues/423398/?project=22

See merge request halo/android/assistant-android!2035
2025-01-10 11:21:43 +08:00
beee098cfe fix:https://sentry.shanqu.cc/organizations/lightgame/issues/423398/?project=22 2025-01-10 11:17:26 +08:00
d67aaf956b Merge branch 'feat/GHZSCY-7046' into 'release'
feat: 补充启动广告图相关广告加载事件埋点—客户端 https://jira.shanqu.cc/browse/GHZSCY-7046

See merge request halo/android/assistant-android!2034
2025-01-09 17:29:21 +08:00
1ed9151b1f feat: 补充启动广告图相关广告加载事件埋点—客户端 https://jira.shanqu.cc/browse/GHZSCY-7046 2025-01-09 16:43:54 +08:00
13f20f6883 Merge branch 'hotfix/v5.38.6-1116/ad_view_background' into 'release'
fix: 还原自有开屏广告的背景颜色 https://jira.shanqu.cc/browse/GHZSCY-7360

See merge request halo/android/assistant-android!2033
2025-01-09 15:28:06 +08:00
78e320a192 fix: 还原自有开屏广告的背景颜色 https://jira.shanqu.cc/browse/GHZSCY-7360 2025-01-09 15:27:34 +08:00
e51db47fad Merge branch 'cherry-pick-f8a26ece' into 'release'
Merge branch 'fix/GHZSCY-7277' into 'dev'

See merge request halo/android/assistant-android!2032
2025-01-09 15:24:18 +08:00
ac02ea88b9 Merge branch 'fix/GHZSCY-7277' into 'dev'
修复错误的下载错误提示 https://jira.shanqu.cc/browse/GHZSCY-7277

See merge request halo/android/assistant-android!2025

(cherry picked from commit f8a26ece01)

54ee3ea3 fix: 游戏下载异常提示 https://jira.shanqu.cc/browse/GHZSCY-7277

Co-authored-by: 陈君陶 <chenjuntao@ghzhushou.com>
2025-01-09 15:23:53 +08:00
f60004fc81 Merge branch 'feat/GHZSCY-7359' into 'release'
需求合并

See merge request halo/android/assistant-android!2031
2025-01-09 15:05:29 +08:00
0cf39a82e2 Merge branch 'fix/viewstub_crashes' into 'release'
fix: 修复ViewStub偶发闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/422108/events/?project=22 https://sentry.shanqu.cc/organizations/lightgame/issues/425087/?project=22

See merge request halo/android/assistant-android!2030
2025-01-09 15:03:51 +08:00
315f244153 fix:【光环助手】包名检测及搜索页面在深色模式下的显示问题 https://jira.shanqu.cc/browse/GHZSCY-6985 2025-01-09 14:54:37 +08:00
f4bdc02d70 fix: 【光环助手】深色模式显示问题 https://jira.shanqu.cc/browse/GHZSCY-7121 2025-01-09 14:54:17 +08:00
aef39eb481 feat: 样式组件优化汇总—客户端 https://jira.shanqu.cc/browse/GHZSCY-6866 2025-01-09 14:53:37 +08:00
dc2e7147d9 fix: 修复ViewStub偶发闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/422108/events/?project=22 https://sentry.shanqu.cc/organizations/lightgame/issues/425087/?project=22 2025-01-09 14:49:58 +08:00
fdcb6342bf Merge branch 'hotfix/v5.38.6-1116/crashes' into 'release'
修复部分 5.38.6 线上闪退

See merge request halo/android/assistant-android!2029
2025-01-09 14:37:49 +08:00
b0da4f8986 Merge branch 'hotfix/v5.38.6-1116/blank_ad_view' into 'release'
fix: 优化开屏广告的显示,提高线程池的 core 线程数,限制视频开屏广告的触摸控制

See merge request halo/android/assistant-android!2028
2025-01-09 14:37:40 +08:00
f7cc906cc5 fix: 优化开屏广告的显示,提高线程池的 core 线程数,限制视频开屏广告的触摸控制 2025-01-09 14:37:40 +08:00
795fbabd90 Merge branch 'hotfix/v5.38.6-1116/login_culprit' into 'release'
修复`我的光环`页面在用户信息接口异常时的显示问题 https://jira.shanqu.cc/browse/GHZSCY-7340

See merge request halo/android/assistant-android!2027
2025-01-09 14:34:25 +08:00
e770f8a359 fix: 修复安装完成后更新安装信息时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/395511 2025-01-09 11:49:38 +08:00
dd12b103be fix: 捕抓上报游戏启动日志的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/406179 2025-01-09 09:59:32 +08:00
21f4a398d5 fix: 处理数组越界闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/408904 2025-01-09 09:45:22 +08:00
f8a26ece01 Merge branch 'fix/GHZSCY-7277' into 'dev'
修复错误的下载错误提示 https://jira.shanqu.cc/browse/GHZSCY-7277

See merge request halo/android/assistant-android!2025
2025-01-08 10:10:32 +08:00
54ee3ea376 fix: 游戏下载异常提示 https://jira.shanqu.cc/browse/GHZSCY-7277 2025-01-07 17:56:09 +08:00
8dfb1644a8 fix: 登录状态显示问题 https://jira.shanqu.cc/browse/GHZSCY-7340 2025-01-07 17:48:53 +08:00
945e034f88 Merge branch 'fix/bind_phone_toRequestBody' into 'dev'
fix: 修复 bindPhone 相关接口 toRequestBody 时没有附带正确 body 的问题; 还原原生 settings 实现

See merge request halo/android/assistant-android!2024
2025-01-06 15:52:23 +08:00
a5ca88729a fix: 修复 bindPhone 相关接口 toRequestBody 时没有附带正确 body 的问题; 还原原生 settings 实现 2025-01-06 15:51:40 +08:00
d4bb3835cf Merge branch 'revert-e30557e2' into 'dev'
Revert "fix:https://jira.shanqu.cc/browse/GHZSCY-7300 【光环助手】预约上线弹窗神策数据上报问题"

See merge request halo/android/assistant-android!2022
2024-12-31 18:13:23 +08:00
3c63b74900 Revert "fix:https://jira.shanqu.cc/browse/GHZSCY-7300 【光环助手】预约上线弹窗神策数据上报问题"
This reverts merge request !2020
2024-12-31 18:10:16 +08:00
712cd21f6e Merge branch 'feat/GHZSCY-7168' into 'dev'
feat:CPM微信小游戏“换一批”功能优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-7168

See merge request halo/android/assistant-android!2012
2024-12-31 16:58:00 +08:00
2b9098faa7 feat:CPM微信小游戏“换一批”功能优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-7168 2024-12-31 16:38:25 +08:00
c0fde44534 Merge branch 'feat/upload_route_doc' into 'dev'
feat: 光环助手跳转链接规则优化 (补充跳转文档上传的脚本)

See merge request halo/android/assistant-android!2021
2024-12-31 16:35:28 +08:00
785f99f0ef feat: 光环助手跳转链接规则优化 (补充跳转文档上传的脚本) 2024-12-31 16:34:59 +08:00
dbd733aec6 Merge branch 'fix/GHZSCY-7300' into 'dev'
fix:https://jira.shanqu.cc/browse/GHZSCY-7300 【光环助手】预约上线弹窗神策数据上报问题

See merge request halo/android/assistant-android!2020
2024-12-31 15:46:36 +08:00
e30557e261 fix:https://jira.shanqu.cc/browse/GHZSCY-7300 【光环助手】预约上线弹窗神策数据上报问题 2024-12-31 15:45:05 +08:00
9744b95126 Merge branch 'fix/viewstub_crash' into 'release'
fix: 修复ViewStub偶发闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/423818/?project=22

See merge request halo/android/assistant-android!2019
2024-12-27 15:14:25 +08:00
009608165c Merge branch 'fix-issues-421826' into 'release'
fix:https://sentry.shanqu.cc/organizations/lightgame/issues/421826/?project=22

See merge request halo/android/assistant-android!2018
2024-12-27 14:02:39 +08:00
98356a7dd7 fix: 修复ViewStub偶发闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/423818/?project=22 2024-12-27 13:56:10 +08:00
8389041379 fix:https://sentry.shanqu.cc/organizations/lightgame/issues/421826/?project=22 2024-12-27 13:49:29 +08:00
e4352590e9 Merge branch 'feat/GHZSCY-7052' into 'dev'
feat: 游戏下载关闭状态新增“跳转第三方”—客户端 https://jira.shanqu.cc/browse/GHZSCY-7052

See merge request halo/android/assistant-android!2017
2024-12-26 10:41:37 +08:00
4f68a52d54 feat: 游戏下载关闭状态新增“跳转第三方”—客户端 https://jira.shanqu.cc/browse/GHZSCY-7052 2024-12-26 10:41:37 +08:00
93f87c8022 Merge branch 'feat/GHZSCY-6866' into 'dev'
feat: 样式组件优化汇总—客户端 https://jira.shanqu.cc/browse/GHZSCY-6866

See merge request halo/android/assistant-android!2016
2024-12-24 11:42:13 +08:00
a77beed7db feat: 样式组件优化汇总—客户端 https://jira.shanqu.cc/browse/GHZSCY-6866 2024-12-24 11:42:13 +08:00
112ddfda13 Merge branch 'feat/GHZSCY-6945' into 'dev'
feat: 消息通知:极光推送本地化—客户端 https://jira.shanqu.cc/browse/GHZSCY-6945

See merge request halo/android/assistant-android!2015
2024-12-24 11:41:36 +08:00
14cf39f10b feat: 消息通知:极光推送本地化—客户端 https://jira.shanqu.cc/browse/GHZSCY-6945 2024-12-24 11:41:36 +08:00
d775e804fd Merge branch 'feat/GHZSCY-6824' into 'dev'
feat: 新游开测相关功能优化(第四期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-6824

See merge request halo/android/assistant-android!2014
2024-12-24 10:11:27 +08:00
d65062af26 feat: 新游开测相关功能优化(第四期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-6824 2024-12-24 10:11:27 +08:00
2522bf5654 Merge branch 'fix/parallel_game_auth' into 'dev'
fix: 修复双开分身游戏无法授权登录的问题

See merge request halo/android/assistant-android!2013
2024-12-19 17:03:24 +08:00
92177ae5f2 fix: 修复双开分身游戏无法授权登录的问题 2024-12-19 17:03:24 +08:00
21ab15a907 Merge branch 'feat/GHZSCY-6335' into 'dev'
feat:【光环助手】实名认证-实名状态更新——畅玩助手 https://jira.shanqu.cc/browse/GHZSCY-6335

See merge request halo/android/assistant-android!2011
2024-12-16 14:38:15 +08:00
5bea92c08e feat:【光环助手】实名认证-实名状态更新——畅玩助手 https://jira.shanqu.cc/browse/GHZSCY-6335 2024-12-16 14:04:38 +08:00
da6725e444 Merge branch 'feat/GHZSCY-6335' into 'dev'
feat:【光环助手】实名认证-实名状态更新——畅玩助手 https://jira.shanqu.cc/browse/GHZSCY-6335

See merge request halo/android/assistant-android!2010
2024-12-16 11:51:21 +08:00
2a2e887ddf feat:【光环助手】实名认证-实名状态更新——畅玩助手 https://jira.shanqu.cc/browse/GHZSCY-6335 2024-12-16 11:41:22 +08:00
cc39a754db build: 合并 vasdk 在 release 分支相关的内容 2024-12-11 17:03:15 +08:00
b14cd3d143 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
#	app/src/main/java/com/gh/vspace/VHelper.kt
#	dependencies.gradle
#	vasdk
2024-12-11 16:47:12 +08:00
dc5b354861 Merge branch 'feat/GHZSCY-7039' into 'dev'
fix: https://jira.shanqu.cc/browse/GHZSCY-7037 实名认证弹窗层级优化

See merge request halo/android/assistant-android!2009
2024-12-11 16:32:09 +08:00
64462ebdbe fix: https://jira.shanqu.cc/browse/GHZSCY-7037 实名认证弹窗层级优化 2024-12-11 16:31:23 +08:00
2e63257523 Merge branch 'fix/game_collection_square_crash' into 'release'
fix: 修复游戏单广场闪退问题...

See merge request halo/android/assistant-android!2007
2024-12-09 10:36:46 +08:00
c69d117ee7 Merge branch 'feat/remove-gitlab-test-branch' into 'dev'
feat:移除gitlab-ci测试分支

See merge request halo/android/assistant-android!2006
2024-12-09 10:30:56 +08:00
ddccb25559 feat:移除gitlab-ci测试分支 2024-12-09 10:30:27 +08:00
913ea39302 Merge branch 'feature-GHZS-5572' into 'dev'
feat: 搜索业务-新增搜索发现取代热门标签—客户端 https://jira.shanqu.cc/browse/GHZSCY-5572

See merge request halo/android/assistant-android!1922
2024-12-09 10:27:39 +08:00
1002d02f12 feat: 搜索业务-新增搜索发现取代热门标签—客户端 https://jira.shanqu.cc/browse/GHZSCY-5572 2024-12-09 10:27:39 +08:00
fa663cd2f6 fix: 修复游戏单广场闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/379887/?project=22&query=is%3Aunresolved+assigned%3Ame&referrer=issue-stream&statsPeriod=14d 2024-12-09 09:59:53 +08:00
19af061311 Merge branch 'feat/GHZSCY-7123' into 'release'
feat:【光环助手】游戏搜索-排序专题 显示问题 https://jira.shanqu.cc/browse/GHZSCY-7123

See merge request halo/android/assistant-android!2004
2024-12-06 17:22:38 +08:00
d643795fa3 feat:【光环助手】游戏搜索-排序专题 显示问题 https://jira.shanqu.cc/browse/GHZSCY-7123 2024-12-06 17:22:38 +08:00
44d93b7527 Merge branch 'fix/sentry-va' into 'dev'
fix: sentry 捕获的异常 https://sentry.shanqu.cc/organizations/lightgame/issues/398398/?project=22

See merge request halo/android/assistant-android!2005
2024-12-06 16:55:03 +08:00
c3d55d4ff9 fix: sentry crash[https://sentry.shanqu.cc/organizations/lightgame/issues/399032/?project=22] 2024-12-06 16:46:46 +08:00
d6f35c5942 Merge branch 'fix/GHZSCY-7121' into 'dev'
fix: 【光环助手】深色模式显示问题 https://jira.shanqu.cc/browse/GHZSCY-7121

See merge request halo/android/assistant-android!2003
2024-12-05 11:07:45 +08:00
c53c1b8228 fix: 【光环助手】深色模式显示问题 https://jira.shanqu.cc/browse/GHZSCY-7121 2024-12-05 11:07:45 +08:00
61b967e533 fix: sentry 捕获的异常 https://sentry.shanqu.cc/organizations/lightgame/issues/398398/?project=22
https://sentry.shanqu.cc/organizations/lightgame/issues/397892/?project=22
2024-12-03 18:01:30 +08:00
b1f2d0a303 Merge branch 'fix/sentry-621063' into 'release'
fix: Sentry-421063 畅玩游戏启动弹窗异步更新下载游戏数量UI时导致的崩溃问题...

See merge request halo/android/assistant-android!2002
2024-12-03 14:10:47 +08:00
bb906f0bb8 fix: Sentry-421063 畅玩游戏启动弹窗异步更新下载游戏数量UI时导致的崩溃问题... 2024-12-03 14:10:47 +08:00
6f242dcc95 Merge branch 'fix/view_stub_crash' into 'release'
fix: 补充ViewStub闪退Sentry埋点

See merge request halo/android/assistant-android!2001
2024-12-03 13:42:44 +08:00
b47a64c63d fix: 补充ViewStub闪退Sentry埋点 2024-12-03 13:40:45 +08:00
948df2582c Merge branch 'fix/view_stub_crash' into 'release'
fix: 捕获ViewStub偶发的空指针闪退问题...

See merge request halo/android/assistant-android!2000
2024-12-03 12:04:31 +08:00
35edcf1d68 fix: 捕获ViewStub偶发的空指针闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418647/events/1d426e3ceda5477c9afbc6712d335b22/?project=22 2024-12-03 11:40:14 +08:00
286d7650f2 Merge branch 'hotfix/v5.38.6-1116/crashes' into 'release'
修复部分线上闪退问题

See merge request halo/android/assistant-android!1999
2024-12-03 10:43:39 +08:00
e566ab838f fix: 捕抓磁盘满了时的闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/397785 2024-12-03 09:31:09 +08:00
cae720d4ec Merge branch 'fix/auth' into 'release'
fix: 修复未打开过光环时无法获取登录状态并授权的问题

See merge request halo/android/assistant-android!1998
2024-12-02 17:21:28 +08:00
925516724f fix: 修复未打开过光环时无法获取登录状态并授权的问题 2024-12-02 17:21:27 +08:00
a5f807c038 fix: 修复下载完成清理资源时因为磁盘满了引起的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/397443/ 2024-12-02 14:52:37 +08:00
f442a70bd3 Merge branch 'fix/delete_appointment_crash' into 'release'
fix:https://sentry.shanqu.cc/organizations/lightgame/issues/423693/?project=22...

See merge request halo/android/assistant-android!1997
2024-12-02 14:42:27 +08:00
9b3dab9897 fix:https://sentry.shanqu.cc/organizations/lightgame/issues/423693/?project=22... 2024-12-02 14:42:27 +08:00
d939aae901 fix: 移除为了能正常收取 BroadcastReceiver 而创建的 InstallService (后续已改为回到应用刷新列表) https://sentry.shanqu.cc/organizations/lightgame/issues/389377/ 2024-12-02 14:31:29 +08:00
028974ec0d fix: 捕抓磁盘已满时下载简单内容造成的闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/401379 2024-12-02 11:42:18 +08:00
ecd4610186 fix: 捕抓磁盘已满时下载广告插件造成的闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/418801/ 2024-12-02 11:17:02 +08:00
21e5f2c98d Merge branch 'fix/webview_crash' into 'release'
fix: 修复某些机型启用WebView深色模式出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/421910

See merge request halo/android/assistant-android!1996
2024-12-02 10:57:52 +08:00
71c0cfe350 fix: 修复某些机型启用WebView深色模式出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/421910 2024-12-02 10:55:37 +08:00
3b8b60bc6b Merge branch 'fix/GHZSCY-7019' into 'release'
fix:【光环助手】自定义页面的搜索显示问题 https://jira.shanqu.cc/browse/GHZSCY-7019

See merge request halo/android/assistant-android!1995
2024-11-27 14:07:54 +08:00
ac59158dbb fix:【光环助手】自定义页面的搜索显示问题 https://jira.shanqu.cc/browse/GHZSCY-7019 2024-11-27 14:07:54 +08:00
5becdf2095 chore: 版本更新至 5.38.6 2024-11-27 11:42:36 +08:00
a88b49344f Merge branch 'hotfix/v5.38.5-1115/remove_registeraion_id' into 'release'
fix: 移除极光 registration_id

See merge request halo/android/assistant-android!1994
2024-11-27 10:43:19 +08:00
f34646cde8 fix: 移除极光 registration_id 2024-11-27 10:42:15 +08:00
bc4bb9b7c6 feat: 关于投诉邮箱部分数据遗失的对外说明 https://jira.shanqu.cc/browse/GHZSCY-7033 2024-11-25 17:46:05 +08:00
9e8ffce772 Merge branch 'hotfix/v5.38.5-1115/vgame_config' into 'release'
fix: 修复接口请求失败时会把畅玩入口关闭的问题

See merge request halo/android/assistant-android!1993
2024-11-25 16:07:13 +08:00
008985489a fix: 修复接口请求失败时会把畅玩入口关闭的问题 2024-11-25 16:01:07 +08:00
2f3fbd3e7c Merge branch 'fix/custom_page_missing_required_view_id' into 'release'
fix:https://sentry.shanqu.cc/organizations/lightgame/issues/408589/events/edfa...

See merge request halo/android/assistant-android!1992
2024-11-25 09:26:26 +08:00
abef224830 fix:https://sentry.shanqu.cc/organizations/lightgame/issues/408589/events/edfa... 2024-11-25 09:26:26 +08:00
8feb9b788e Merge branch 'hotfix/v5.35.5-1115/auth_crash' into 'release'
fix: 修复授权登录页面的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/373402/?project=22

See merge request halo/android/assistant-android!1991
2024-11-25 09:22:52 +08:00
0a059deb44 fix: 修复授权登录页面的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/373402/?project=22 2024-11-22 10:14:27 +08:00
448160d255 Merge branch 'hotfix/v5.38.4-1114/va' into 'release'
fix: 修复混淆把这个方法移除了。

See merge request halo/android/assistant-android!1990
2024-11-21 14:45:54 +08:00
533f93a340 fix: 修复混淆把这个方法移除了。 2024-11-21 14:44:58 +08:00
d80b8a97a3 chore: 版本更新至 5.38.5 2024-11-21 11:50:17 +08:00
f2e6d98788 Merge branch 'feat/GHZSCY-6923' into 'release'
feat: CPM微信小游戏优化第二期—客户端 https://jira.shanqu.cc/browse/GHZSCY-6923

See merge request halo/android/assistant-android!1986
2024-11-21 11:27:25 +08:00
238a83c5fe feat: CPM微信小游戏优化第二期—客户端 https://jira.shanqu.cc/browse/GHZSCY-6923 2024-11-21 11:27:25 +08:00
ca71f23363 Merge branch 'hotfix/v5.38.4-1114/GHZSCY-7004' into 'release'
fix: 神策数据库部分字段超存储上线的问题 https://jira.shanqu.cc/browse/GHZSCY-7004

See merge request halo/android/assistant-android!1989
2024-11-21 09:57:59 +08:00
c96b41c621 fix: 神策数据库部分字段超存储上线的问题 https://jira.shanqu.cc/browse/GHZSCY-7004 2024-11-21 09:57:59 +08:00
9afb35bbb9 feat: 将与服务器校对时间的间隔改为 24 小时一次 2024-11-20 16:49:04 +08:00
e8ee63d52c Merge branch 'hotfix/v5.38.4-1114/GHZSCY-7004' into 'release'
fix: 神策数据库部分字段超存储上线的问题 https://jira.shanqu.cc/browse/GHZSCY-7004

See merge request halo/android/assistant-android!1987
2024-11-20 11:34:56 +08:00
90359cfffd fix: 神策数据库部分字段超存储上线的问题 https://jira.shanqu.cc/browse/GHZSCY-7004 2024-11-20 10:05:28 +08:00
a3da883033 Merge branch 'revert-8c95286f' into 'release'
Revert "Merge branch 'feat/GHZSCY-6923' into 'release'"

See merge request halo/android/assistant-android!1984
2024-11-19 18:16:53 +08:00
a9f1437a52 Revert "Merge branch 'feat/GHZSCY-6923' into 'release'" 2024-11-19 18:16:53 +08:00
8c95286fe5 Merge branch 'feat/GHZSCY-6923' into 'release'
feat: CPM微信小游戏优化第二期—客户端 https://jira.shanqu.cc/browse/GHZSCY-6923

See merge request halo/android/assistant-android!1982
2024-11-19 18:12:55 +08:00
8a835a94e3 feat: CPM微信小游戏优化第二期—客户端 https://jira.shanqu.cc/browse/GHZSCY-6923 2024-11-19 16:46:05 +08:00
14ec4aed3a Merge branch 'hotfix/v5.38.4-1114/GHZSCY-7004' into 'release'
fix: 神策数据库部分字段超存储上线的问题 https://jira.shanqu.cc/browse/GHZSCY-7004

See merge request halo/android/assistant-android!1981
2024-11-19 15:37:52 +08:00
07f956a1f0 fix: 神策数据库部分字段超存储上线的问题 https://jira.shanqu.cc/browse/GHZSCY-7004 2024-11-19 15:26:12 +08:00
6ef8d04e57 Merge branch 'fix/jg_push' into 'release'
fix: 神策上报极光推送ID改为profileSet方法

See merge request halo/android/assistant-android!1980
2024-11-18 18:21:45 +08:00
30248ef205 fix: 神策上报极光推送ID改为profileSet方法 2024-11-18 18:20:40 +08:00
87b9bb0bf3 fix: 修复下载过程中 response code 为 304 时造成下载异常的问题 2024-11-18 11:35:56 +08:00
b346882bfa Merge branch 'fix/GHZSCY-6939-merge' into 'release'
fix:【光环助手】“视频横屏滑动”专题视频播放问题 https://jira.shanqu.cc/browse/GHZSCY-6939

See merge request halo/android/assistant-android!1979
2024-11-15 17:51:24 +08:00
eeddb5ea51 fix:【光环助手】“视频横屏滑动”专题视频播放问题 https://jira.shanqu.cc/browse/GHZSCY-6939 2024-11-15 16:55:35 +08:00
2ccdd93e47 build: 处理编译问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-11-14 16:31:49 +08:00
d98466f60f build: 路由文档仅手动启用时生成 2024-11-14 16:19:42 +08:00
2afc2bc9d6 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/search/viewmodel/SearchGameListViewModel.kt
#	dependencies.gradle
#	feature/floating-window/src/demo/java/com/gh/gamecenter/feedback/view/help/QaFeedbackDialogFragment.kt
#	vasdk
2024-11-14 15:21:44 +08:00
243b0ccbd4 Merge branch 'fix/GHZSCY-6575' into 'dev'
fix: 下载按钮由双下载切换回单下载时的问题 https://jira.shanqu.cc/browse/GHZSCY-6575

See merge request halo/android/assistant-android!1878
2024-11-14 15:15:46 +08:00
78f9aa3ee4 Merge branch 'hotfix/v5.38.4-1114/GHZSCY-6927' into 'release'
fix: 深色模式下富文本指定颜色无法显示的问题 https://jira.shanqu.cc/browse/GHZSCY-6927

See merge request halo/android/assistant-android!1978
2024-11-14 10:21:48 +08:00
f355eae99b Merge branch 'feat/GHZSCY-6985' into 'dev'
fix:【光环助手】包名检测及搜索页面在深色模式下的显示问题 https://jira.shanqu.cc/browse/GHZSCY-6985

See merge request halo/android/assistant-android!1977
2024-11-13 17:39:06 +08:00
3c1af6e02d fix:【光环助手】包名检测及搜索页面在深色模式下的显示问题 https://jira.shanqu.cc/browse/GHZSCY-6985 2024-11-13 17:37:23 +08:00
57a8b96f56 Merge branch 'feat/GHZSCY-6984' into 'dev'
feat:搜索业务:神策埋点相关搜索结果点击事件新增序号属性position—客户端 https://jira.shanqu.cc/browse/GHZSCY-6984

See merge request halo/android/assistant-android!1976
2024-11-13 16:49:15 +08:00
71265e0ea7 feat:搜索业务:神策埋点相关搜索结果点击事件新增序号属性position—客户端 https://jira.shanqu.cc/browse/GHZSCY-6984 2024-11-13 16:46:09 +08:00
b007e63b5e Merge branch 'fix/GHZSCY-6971' into 'dev'
fix:【光环助手】2410后台优化-游戏专题-1112-测试-客户端 https://jira.shanqu.cc/browse/GHZSCY-6971

See merge request halo/android/assistant-android!1975
2024-11-12 17:40:35 +08:00
c281ea7ac5 fix:【光环助手】2410后台优化-游戏专题-1112-测试-客户端 https://jira.shanqu.cc/browse/GHZSCY-6971 2024-11-12 17:39:02 +08:00
f34ad0675d Merge branch 'hotfix/v5.38.4-1114/va' into 'release'
feat: 1. Android 8.0 以下不初始化VA。2.去掉VA的javahook。3. 去掉VA外部应用监听。

See merge request halo/android/assistant-android!1974
2024-11-12 17:24:03 +08:00
36abcc9f19 feat: 1. Android 8.0 以下不初始化VA。2.去掉VA的javahook。3. 去掉VA外部应用监听。 2024-11-12 11:17:02 +08:00
d6443a401a Merge branch 'feat/GHZSCY-5738' into 'dev'
fix:【光环助手】客户端UI组件规范更新同步2024/06/17 https://jira.shanqu.cc/browse/GHZSCY-5738

See merge request halo/android/assistant-android!1973
2024-11-12 09:28:36 +08:00
6c8ea6ffb2 fix:【光环助手】客户端UI组件规范更新同步2024/06/17 https://jira.shanqu.cc/browse/GHZSCY-5738 2024-11-11 18:04:22 +08:00
ae878eddf1 Merge branch 'hotfix/v5.38.4-1114/remove_useless_import' into 'release'
fix: 移除无用 import

See merge request halo/android/assistant-android!1971
2024-11-11 18:03:45 +08:00
ece519115b fix: 移除无用 import 2024-11-11 18:03:01 +08:00
b9e0a8e37a Merge branch 'hotfix/v5.38.4-1114/deadobject-crash' into 'release'
fix: 修复部分调用 PackageManager 相关的方法的闪退(提供异常时的回落)...

See merge request halo/android/assistant-android!1970
2024-11-11 17:35:26 +08:00
34ca8896ae fix: 修复部分调用 PackageManager 相关的方法的闪退(提供异常时的回落) https://sentry.shanqu.cc/organizations/lightgame/issues/418276/ https://sentry.shanqu.cc/organizations/lightgame/issues/417950/ 2024-11-11 17:24:40 +08:00
d6e19bfaff Merge branch 'fix/GHZSCY-6944' into 'release'
fix:【光环助手】神策埋点游戏单搜索结果点击事件游戏单标题的内容错误 https://jira.shanqu.cc/browse/GHZSCY-6944

See merge request halo/android/assistant-android!1969
2024-11-08 09:26:58 +08:00
943fb4d4e0 fix:【光环助手】神策埋点游戏单搜索结果点击事件游戏单标题的内容错误 https://jira.shanqu.cc/browse/GHZSCY-6944 2024-11-08 09:23:42 +08:00
2c5471d524 Merge branch 'fix/sentry-418688' into 'release'
fix: Sentry-418688 SearchActivity回调onSavedInstance后,调用FragmentManager的popBackStack引发的崩溃问题

See merge request halo/android/assistant-android!1968
2024-11-07 13:42:39 +08:00
cf527db60e fix: Sentry-418688 SearchActivity回调onSavedInstance后,调用FragmentManager的popBackStack引发的崩溃问题 2024-11-07 13:42:39 +08:00
f261991a55 fix: 深色模式下富文本指定颜色无法显示的问题 https://jira.shanqu.cc/browse/GHZSCY-6927
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-11-06 15:49:31 +08:00
0f9f0b7c9a Merge branch 'feat/GHZSCY-6645' into 'dev'
feat:媒体文件上传控件优化 (二、三)—客户端 https://jira.shanqu.cc/browse/GHZSCY-6645

See merge request halo/android/assistant-android!1967
2024-11-06 15:09:48 +08:00
c29efbefd7 feat:媒体文件上传控件优化 (二、三)—客户端 https://jira.shanqu.cc/browse/GHZSCY-6645 2024-11-06 15:09:47 +08:00
ab66621751 chore: 版本更新至 5.38.4 2024-11-04 17:59:19 +08:00
af262c624a Merge branch 'feat/GHZSCY-6904' into 'release'
feat:【光环助手】搜索bug https://jira.shanqu.cc/browse/GHZSCY-6904

See merge request halo/android/assistant-android!1966
2024-11-04 16:28:48 +08:00
d2813ecbda feat:【光环助手】搜索bug https://jira.shanqu.cc/browse/GHZSCY-6904 2024-11-04 16:28:48 +08:00
0ea932e36d Merge branch 'hotfix/v5.38.3-1113/aidl_npe_crash' into 'release'
fix: 尝试修复aidl获取对象为空导致NPE。https://sentry.shanqu.cc/organizations/lightgame/issues/399032/?project=22

See merge request halo/android/assistant-android!1965
2024-11-04 14:35:50 +08:00
68151ed6f9 fix: 尝试修复aidl获取对象为空导致NPE。https://sentry.shanqu.cc/organizations/lightgame/issues/399032/?project=22 2024-11-04 14:34:53 +08:00
e6d2361008 Merge branch 'hotfix/v5.38.3-1113/concurrent_crash' into 'release'
fix: 修复部分 5.38.3 的线上闪退问题

See merge request halo/android/assistant-android!1964
2024-11-04 13:43:00 +08:00
570b777c8e Merge branch 'hotfix/v5.38.3-1113/crashes' into 'release'
修复Sentry上的闪退问题

See merge request halo/android/assistant-android!1963
2024-11-04 11:50:45 +08:00
0e557b2246 fix: 修复启动游戏时多线程操作闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/406116/?project=22
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-11-04 11:50:41 +08:00
f155440814 fix: 修复下载 exception 异常为空时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/416995/?project=22
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-11-04 11:49:57 +08:00
62ba9fc7bf fix: 修复游戏详情评论页面重建时出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/379887/events/aa3bbc5102ed4a57b66c3c7fed5d7b34/?project=22 2024-11-04 11:26:00 +08:00
4637aa8808 fix: 修复下拉推送偶发的空指针闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418647/events/1d426e3ceda5477c9afbc6712d335b22/?project=22 2024-11-04 11:24:08 +08:00
81998e3aad Merge branch 'fix/sentry-418235' into 'release'
fix: 畅玩启动提示弹窗游戏列表数组越界问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418304/?project=22

See merge request halo/android/assistant-android!1962
2024-11-01 16:15:14 +08:00
82a8aa03ba fix: 畅玩启动提示弹窗游戏列表数组越界问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418304/?project=22 2024-11-01 16:13:05 +08:00
c876711578 chore: 版本更新至 5.38.3 2024-11-01 09:37:56 +08:00
41fcee7f4d Merge branch 'feat/GHZSCY-6876' into 'release'
Resolve GHZSCY-6876 "Feat/"

See merge request halo/android/assistant-android!1961
2024-11-01 09:37:04 +08:00
0ccbc4d581 feat:一键登录SDK更新—客户端 https://jira.shanqu.cc/browse/GHZSCY-6876 2024-11-01 09:37:04 +08:00
56151bc38d Merge branch 'fix/va-test-install' into 'dev'
fix: 1. 测试版本没有 从SD卡安装 的问题。2. 重复卸载安装不生效的bug

See merge request halo/android/assistant-android!1960
2024-10-31 16:07:30 +08:00
f05fc73e3a Merge branch 'hotfix/v5.38.2-1112/binding_crash' into 'release'
fix: 修复 SearchToolbarTabWrapperFragment 页面 binding bindView 时的闪退问题...

See merge request halo/android/assistant-android!1959
2024-10-31 10:31:26 +08:00
ca3c545f26 Merge branch 'hotfix/v5.38.1-1111/GHZSCY-6855' into 'release'
fix: 神策下载按钮点击事件相关字段上报异常排查 https://jira.shanqu.cc/browse/GHZSCY-6855

See merge request halo/android/assistant-android!1958
2024-10-31 10:28:28 +08:00
226539328e fix: 修复 SearchToolbarTabWrapperFragment 页面 binding bindView 时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418028/?project=22
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-10-31 10:13:36 +08:00
bb7db78b0c Merge branch 'hotfix/v5.38.2-1112/va_launch_crash' into 'release'
fix: 修复点击畅玩启动插屏广告出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418073/?project=22

See merge request halo/android/assistant-android!1957
2024-10-31 09:47:03 +08:00
ede62c5363 fix: 修复点击畅玩启动插屏广告出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/418073/?project=22 2024-10-31 09:44:40 +08:00
12bb6824ea Merge branch 'fix/wx_subscribe_msg_response_handle' into 'release'
fix: 修复微信开服提醒消息回调处理异常问题

See merge request halo/android/assistant-android!1955
2024-10-30 14:44:16 +08:00
15c0950754 fix: 修复微信开服提醒消息回调处理异常问题 2024-10-30 14:42:55 +08:00
f86b7fe12a Merge branch 'hotfix/v5.38.2-1112/emulator_auth' into 'release'
fix: 修复雷电模拟器网游插件登录后跳转回游戏出现的闪退问题

See merge request halo/android/assistant-android!1954
2024-10-30 14:31:22 +08:00
d12cdbd34b fix: 修复雷电模拟器网游插件登录后跳转回游戏出现的闪退问题 2024-10-30 14:31:22 +08:00
8436d4eda3 Merge branch 'hotfix/v5.38.2-1112/multi_tab_loading' into 'release'
fix: 修复多tab导航页loading动画没有显示的问题

See merge request halo/android/assistant-android!1952
2024-10-29 13:51:10 +08:00
be832037a7 fix: 修复多tab导航页loading动画没有显示的问题 2024-10-29 13:41:36 +08:00
b620257825 Merge branch 'hotfix/v5.38.2-1112/GHZSCY-6859' into 'release'
fix:【光环助手】深色模式切换显示问题 https://jira.shanqu.cc/browse/GHZSCY-6859

See merge request halo/android/assistant-android!1951
2024-10-28 17:13:30 +08:00
6c88cace99 fix:【光环助手】深色模式切换显示问题 https://jira.shanqu.cc/browse/GHZSCY-6859 2024-10-28 17:11:23 +08:00
f875fa1b14 Merge branch 'feat/GHZSCY-6828' into 'release'
feat: CPM微信小游戏一期优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-6828

See merge request halo/android/assistant-android!1948
2024-10-28 14:54:49 +08:00
8076c3a70a feat: CPM微信小游戏一期优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-6828 2024-10-28 14:54:49 +08:00
bebab317a3 fix: 神策下载按钮点击事件相关字段上报异常排查 https://jira.shanqu.cc/browse/GHZSCY-6855 2024-10-28 14:38:06 +08:00
c450ca570d Merge branch 'hotfix/v5.38.2-1112/GHZSCY-6854' into 'release'
fix:【光环助手】切换深色/普通模式tab字体颜色变化问题 https://jira.shanqu.cc/browse/GHZSCY-6854

See merge request halo/android/assistant-android!1950
2024-10-28 10:23:56 +08:00
d239b0755f fix:【光环助手】切换深色/普通模式tab字体颜色变化问题 https://jira.shanqu.cc/browse/GHZSCY-6854 2024-10-28 10:20:53 +08:00
0a187b2242 fix: 下载按钮由双下载切换回单下载时的问题 https://jira.shanqu.cc/browse/GHZSCY-6575
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-26 14:16:37 +08:00
367 changed files with 10870 additions and 1972 deletions

View File

@ -72,6 +72,8 @@ android_build:
only:
- dev
- release
- feat/GHZSCY-6976
- feat/GHZSCY-6976-log
# 代码检查
sonarqube_analysis:
@ -103,6 +105,8 @@ sonarqube_analysis:
only:
- dev
- release
- feat/GHZSCY-6976
- feat/GHZSCY-6976-log
## 发送简易检测结果报告
send_sonar_report:
@ -121,6 +125,8 @@ send_sonar_report:
only:
- dev
- release
- feat/GHZSCY-6976
- feat/GHZSCY-6976-log
oss-upload&send-email:
tags:
@ -157,3 +163,5 @@ oss-upload&send-email:
only:
- dev
- release
- feat/GHZSCY-6976
- feat/GHZSCY-6976-log

View File

@ -372,8 +372,6 @@ dependencies {
// debugImplementation "com.gu.android:toolargetool:${toolargetool}" // 需要使用调试时才启用
debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}"
ksp project(":feature:route_doc")
implementation "androidx.multidex:multidex:${multiDex}"
implementation "androidx.fragment:fragment-ktx:${fragment}"
@ -404,7 +402,7 @@ dependencies {
exclude module: "gsyvideoplayer-androidvideocache"
exclude group: "tv.danmaku.ijk.media"
})
implementation ("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo") {
implementation("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo") {
exclude group: 'com.google.android.exoplayer', module: 'extension-rtmp'
}
@ -449,14 +447,14 @@ dependencies {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_setting')) {
implementation(project(':module_setting')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_setting_compose')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':module_setting_compose')) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePkg) {
implementation(project(':feature:pkg'))
}
@ -512,6 +510,10 @@ dependencies {
implementation(project(':feature:sentry'))
}
if (gradle.ext.enableRouteDoc) {
ksp project(":feature:route_doc")
}
implementation(project(':feature:media_select'))
implementation(project(":module_va_api"))
@ -524,6 +526,18 @@ dependencies {
debugImplementation 'com.bytedance.android:shadowhook:1.0.9'
debugImplementation 'io.github.shiqos:wytrace:1.0.1'
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableAccelerator) {
implementation(project(":feature:accelerator"))
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enableAliPay) {
implementation(project(":feature:ali_pay"))
}
if(!gradle.ext.excludeOptionalModules || gradle.ext.enableWechatPay){
implementation(project(":feature:wechat_pay"))
}
}
File propFile = file('sign.properties')

View File

@ -10,9 +10,9 @@
<queries>
<package android:name="com.gh.toolmap" />
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="ghtoolmap"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="ghtoolmap" />
</intent>
</queries>
@ -68,6 +68,9 @@
<!-- 悬浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 适配 双开/分身 游戏授权登录 -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
@ -194,7 +197,9 @@
android:name="io.sentry.breadcrumbs.system-events"
android:value="false" />
<meta-data android:name="module_version" android:value="${VA_VERSION_NAME}" />
<meta-data
android:name="module_version"
android:value="${VA_VERSION_NAME}" />
<service android:name="com.gh.ndownload.NDownloadService" />
@ -517,10 +522,6 @@
android:name=".video.data.VideoDataActivity"
android:screenOrientation="portrait" />
<activity
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.detail.ForumDetailActivity"
android:screenOrientation="portrait" />
@ -640,6 +641,7 @@
<activity
android:name="com.gh.gamecenter.SkipCompatActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/Theme.AppCompat.Light.Fullscreen.Transparent">
<intent-filter>
<data android:scheme="ghzhushou" />
@ -663,7 +665,8 @@
android:name=".authorization.AuthorizationActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
android:taskAffinity=".auth">
<intent-filter>
<data android:scheme="ghzhushou_authorization" />
<category android:name="android.intent.category.DEFAULT" />
@ -809,6 +812,18 @@
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP" />
<activity
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.halo.assistant.member.MemberActivity"
android:screenOrientation="portrait" />
<activity
android:name=".BatchRegisterActivity"
android:screenOrientation="portrait" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
<!-- android:launchMode="singleTask"-->
@ -864,10 +879,6 @@
<!-- tools:node="remove" />-->
<!-- </provider>-->
<service android:name="com.gh.gamecenter.install.InstallService" />
<service android:name="com.gh.download.suspendwindow.DownloadSuspendWindowService" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.graphics.drawable.Animatable
import android.os.Message
import android.text.TextUtils
import android.view.View
@ -13,11 +14,13 @@ import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import com.therouter.TheRouter
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.LogUtils
import com.gh.common.util.NewFlatLogUtils.logOpenScreenAdSkip
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.MainActivity
@ -59,6 +62,8 @@ object AdDelegateHelper {
private val mGameSearchAdList: ArrayList<AdConfig> by lazy { arrayListOf() }
private var mVGameLaunchAd: AdConfig? = null
private var ownerSplashAdLoadTime = 0L
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
@ -76,6 +81,7 @@ object AdDelegateHelper {
}
var isShowingSplashAd = false // 是否正在显示开屏广告
var isOwnerSplashAdShown = false // 自有开屏广告是否展示
var gameSearchKeyword = ""
fun initAdSdk(context: Context) {
@ -302,6 +308,7 @@ object AdDelegateHelper {
) {
val hideCallback = {
isShowingSplashAd = false
isOwnerSplashAdShown = false
hideAction.invoke()
}
if (mSplashAd != null) {
@ -574,6 +581,8 @@ object AdDelegateHelper {
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
isOwnerSplashAdShown = false
val jumpBtn = startAdContainer.findViewById<TextView>(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
@ -592,38 +601,62 @@ object AdDelegateHelper {
)
adImage.visibleIf(true)
ImageUtils.display(adImage, ad.img)
ImageUtils.displayWithCallback(adImage, ad.img, true, object : BaseControllerListener<ImageInfo>() {
override fun onSubmit(id: String?, callerContext: Any?) {
super.onSubmit(id, callerContext)
adImage.post {
ownerSplashAdLoadTime = System.currentTimeMillis()
NewFlatLogUtils.logSplashAdLoad(ad.id)
}
}
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
isOwnerSplashAdShown = true
adImage.post {
NewFlatLogUtils.logSplashAdShow(ad.id, System.currentTimeMillis() - ownerSplashAdLoadTime)
}
}
override fun onFailure(id: String?, throwable: Throwable?) {
super.onFailure(id, throwable)
NewFlatLogUtils.logSplashAdFail(ad.id, "启动广告图加载失败")
}
})
if (ad.isImageType) {
adVideo.visibleIf(false)
} else {
adVideo.visibleIf(true)
adVideo.startPlay(ad.video.url)
}
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
jumpBtn.setOnClickListener {
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
it.debounceActionWithInterval(1000L) {
if (!isOwnerSplashAdShown) {
NewFlatLogUtils.logSplashAdFail(ad.id, "加载过程中点击跳过广告")
}
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
NewFlatLogUtils.logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
}
}
val sources: MutableList<ExposureSource> = ArrayList()
sources.add(ExposureSource("开屏广告", ad.id))

View File

@ -44,6 +44,16 @@ class SplashAdVideoView @JvmOverloads constructor(
return R.layout.layout_splash_ad_video
}
override fun touchSurfaceMoveFullLogic(absDeltaX: Float, absDeltaY: Float) {
// no nothing
}
override fun onPrepared() {
super.onPrepared()
visibility = VISIBLE
}
override fun onAutoCompletion() {
setStateAndUi(CURRENT_STATE_AUTO_COMPLETE);

View File

@ -21,26 +21,31 @@ import com.gh.common.view.RichEditor
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.LocalVideoEntity
import com.gh.gamecenter.feature.selector.LocalMediaActivity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.entity.VideoEntity
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.selector.ChooseType
import com.gh.gamecenter.feature.selector.LocalMediaActivity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.qa.entity.EditorInsertEntity
import com.gh.gamecenter.video.poster.PosterEditActivity
import com.gh.gamecenter.video.poster.video.VideoPosterFragment
import com.gh.gamecenter.video.upload.UploadManager
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Keyboard
import com.lightgame.utils.Utils
import com.lightgame.view.CheckableImageView
import com.therouter.TheRouter
import io.reactivex.disposables.Disposable
import org.json.JSONArray
import org.json.JSONObject
@ -229,6 +234,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
VideoPosterFragment.createVideoCoverFile(this)
findView()
onRichClick()
mViewModel = provideViewModel()
@ -739,9 +745,9 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mViewModel.id = id
mViewModel.videoId = videoId
val videoEntity = VideoEntity(url = url)
val intent =
PosterEditActivity.getIntentByVideo(this@BaseRichEditorActivity, videoEntity)
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
TheRouter.build(RouteConsts.activity.videoCoverEditActivity)
.withParcelable(EntranceConsts.KEY_VIDEO_ENTITY, videoEntity)
.navigation(this@BaseRichEditorActivity, REQUEST_CODE_IMAGE_CROP)
}
@JavascriptInterface

View File

@ -22,7 +22,8 @@ import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.callback.BiCallback
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.constant.Constants.SP_MEMBER_PAYMENT_BUTTON_CLICK
import com.gh.gamecenter.common.constant.Constants.SP_MEMBER_RECHARGE_BUTTON_CLICK
import com.gh.gamecenter.common.entity.NotificationUgc
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.loghub.LoghubUtils
@ -30,20 +31,23 @@ import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
import com.gh.gamecenter.common.tracker.Tracker
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge.EVENT_MEMBER_RECHARGE_BUTTON_CLICK
import com.gh.gamecenter.common.utils.SensorsBridge.EVENT_NAME
import com.gh.gamecenter.common.utils.SensorsBridge.KEY_IS_FIRST_TIME
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.SensorsEvent
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.AcctRecordEntity
import com.gh.gamecenter.feature.entity.Badge
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.OrderEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.login.user.LoginTag
import com.gh.gamecenter.login.user.UserManager
@ -55,6 +59,9 @@ import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.setting.SettingBridge
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.halo.assistant.member.MemberRepository
import com.halo.assistant.member.MemberRepository.Companion.PAYMENT_TYPE_ALIPAY
import com.halo.assistant.member.MemberRepository.Companion.PAYMENT_TYPE_WECHAT
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus.*
@ -75,6 +82,7 @@ class DefaultJsApi(
private var mBbsId: String? = "",
private var mOriginUrl: String? = "",
private val mForumName: String? = "",
private val listener: OnWebClickListener? = null
) {
companion object {
@ -699,6 +707,84 @@ class DefaultJsApi(
}
}
@JavascriptInterface
fun preOrderWithAli(json: Any) {
val order = json.toString().toObject<OrderEntity>() ?: return
trackMemberPaymentButtonClick(order, PAYMENT_TYPE_ALIPAY)
listener?.onPreOrderWithAli(order)
}
@JavascriptInterface
fun preOrderWithWechat(json: Any) {
val order = json.toString().toObject<OrderEntity>() ?: return
trackMemberPaymentButtonClick(order, PAYMENT_TYPE_WECHAT)
listener?.onPreOrderWithWechat(order)
}
private fun trackMemberPaymentButtonClick(order: OrderEntity, paymentType: String) {
val isFirstTime = SPUtils.getBoolean(SP_MEMBER_PAYMENT_BUTTON_CLICK, true)
SPUtils.setBoolean(SP_MEMBER_PAYMENT_BUTTON_CLICK, false)
SensorsBridge.trackMemberPaymentButtonClick(
isFirstTime,
paymentType,
order.setMenuName,
order.paymentAmount
)
}
@JavascriptInterface
fun startGameAccelerate(acctJson: Any) {
if (acctJson is String) {
val acctRecord = GsonUtils.fromJson(acctJson, AcctRecordEntity::class.java)
val accInfo = acctRecord.accInfo
listener?.onStartGameAccelerate(accInfo)
}
}
@JavascriptInterface
fun getCurAcctGameId(): String {
val isSpeeding = TheRouter.get(IAcceleratorProvider::class.java)?.isCurAccSuccess() ?: false
val gameId = if (isSpeeding) {
MemberRepository.instance.acctGameRecord.gameId
} else {
""
}
return gameId
}
@JavascriptInterface
fun stopGameAccelerate() {
listener?.onStopGameAccelerate()
}
@JavascriptInterface
fun refreshToken(token: Any, handler: CompletionHandler<Any>) {
val accessToken = token.toString()
UserManager.getInstance().refreshToken(accessToken, object : UserManager.refreshCallBack {
override fun onLogin() {
handler.complete(true)
}
override fun onLoginFailure(errorMessage: String?) {
handler.complete(false)
}
})
}
@JavascriptInterface
fun trackSensorsAnalytics(json: Any) {
val hashMap = json.toString().toObject<HashMap<String, Any>>() ?: return
val eventName = hashMap.remove(EVENT_NAME) ?: return
when (eventName) {
EVENT_MEMBER_RECHARGE_BUTTON_CLICK -> {
hashMap[KEY_IS_FIRST_TIME] = SPUtils.getBoolean(SP_MEMBER_RECHARGE_BUTTON_CLICK, true)
SPUtils.setBoolean(SP_MEMBER_RECHARGE_BUTTON_CLICK, false)
}
}
SensorsBridge.trackSensorsAnalyticsFromWeb(eventName.toString(), hashMap)
}
/**
* 获取 ExposureEvent可能为空
*/
@ -815,4 +901,15 @@ class DefaultJsApi(
}
}
}
interface OnWebClickListener {
fun onPreOrderWithAli(order: OrderEntity)
fun onPreOrderWithWechat(order: OrderEntity)
fun onStartGameAccelerate(accInfo: AcctRecordEntity.AccInfo)
fun onStopGameAccelerate()
}
}

View File

@ -17,7 +17,7 @@ import kotlin.concurrent.fixedRateTimer
object FixedRateJobHelper {
private const val CHECKER_PERIOD: Long = 15 * 1000L
private const val TIME_PERIOD: Long = 10 * 60 * 1000L
private const val TIME_PERIOD: Long = 24 * 60 * 60 * 1000L
private const val LOGHUB_PERIOD: Long = 2 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 1 * 60 * 1000L
private const val REGION_SETTING_PERIOD: Long = 60 * 1000L
@ -35,7 +35,7 @@ object FixedRateJobHelper {
// 时间检查每15秒检查一次
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
val elapsedTime = mExecuteCount * CHECKER_PERIOD
// 时间校对,10分钟一次
// 时间校对,24 小时一次
if (elapsedTime % TIME_PERIOD == 0L) {
RetrofitManager.getInstance().api.time
.subscribeOn(Schedulers.io())

View File

@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Context
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageChangeHelper
import com.gh.common.util.TempCertificationUtils
import com.gh.gamecenter.feature.entity.GameEntity
@ -25,6 +26,10 @@ class LandPageAddressHandler : DownloadChainHandler() {
processEndCallback?.invoke(asVGame, null)
}
} else {
val packageName = gameEntity.getApk().firstOrNull()?.packageName
if (packageName?.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(context, gameEntity.landPageAddressDialog!!.link!!)
}
}

View File

@ -8,12 +8,21 @@ import com.gh.gamecenter.feature.entity.GameEntity
class PackageCheckHandler : DownloadChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity, asVGame: Boolean) {
PackageCheckDialogFragment.show((context as AppCompatActivity), gameEntity) {
fun nextOrProcessEnd() {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity, asVGame)
} else {
processEndCallback?.invoke(asVGame, null)
}
}
if (gameEntity.canSpeed) {
nextOrProcessEnd()
} else {
PackageCheckDialogFragment.show((context as AppCompatActivity), gameEntity) {
nextOrProcessEnd()
}
}
}
}

View File

@ -114,8 +114,6 @@ public class Config {
if (!TextUtils.isEmpty(json)) {
mSettingsEntity = GsonUtils.fromJson(json, SettingsEntity.class);
}
mSettingsEntity.setGameSmooth("off");
} catch (Exception e) {
e.printStackTrace();
}
@ -263,8 +261,7 @@ public class Config {
public void onSuccess(VSetting data) {
mVSetting = data;
SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
VHelper.init(HaloApp.getInstance());
VHelper.checkVspaceUpdate(HaloApp.getInstance());
}
});
}

View File

@ -15,10 +15,10 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.DownloadChainBuilder;
import com.gh.common.chain.DownloadChainHandler;
import com.gh.common.chain.CheckDownloadHandler;
import com.gh.common.chain.CheckStoragePermissionHandler;
import com.gh.common.chain.DownloadChainBuilder;
import com.gh.common.chain.DownloadChainHandler;
import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.LandPageAddressHandler;
@ -287,19 +287,11 @@ public class BindingAdapters {
});
break;
case RESERVED:
if ("download".equals(gameEntity.getReserveStatus())) {
ReservationHelper.showDeleteReservationDialog(progressBar.getContext(), () -> {
ReservationHelper.deleteReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
ReservationHelper.showCancelReservationDialog(progressBar.getContext(),gameEntity, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
} else {
ReservationHelper.showCancelReservationDialog(progressBar.getContext(),gameEntity, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
});
}
});
break;
case H5_GAME:
LinkEntity linkEntity = gameEntity.getH5Link();
@ -345,9 +337,9 @@ public class BindingAdapters {
}
progressBar.setButtonStyle(DownloadButton.ButtonStyle.H5_GAME);
} else {
if (offStatus != null && "dialog".equals(offStatus)) {
if (("dialog".equals(offStatus) || "third_party".equals(offStatus))) {
progressBar.setText("查看");
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE);
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE_WITH_HINT);
} else if ("updating".equals(offStatus)) {
progressBar.setText("更新中");
progressBar.setButtonStyle(DownloadButton.ButtonStyle.UPDATING);

View File

@ -3,7 +3,6 @@ package com.gh.common.dialog
import android.animation.ValueAnimator
import android.content.Context
import android.content.DialogInterface
import android.content.pm.PackageInfo
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -19,7 +18,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
@ -59,7 +57,6 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
private var mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
var gameEntity: GameEntity? = null
var callBack: ConfirmListener? = null
@ -195,7 +192,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
if (binding.noRemindAgainCb.isChecked) {
saveRecord(entity)
}
val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
val isAllPackageInstalled = isAllPackageInstalled(entity)
if (isAllPackageInstalled) {
mDismissByTouchInside = true
callBack?.onConfirm()
@ -299,7 +296,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
val links = LinkedHashSet<LinkEntity>()
packageDialogEntity.detectionObjects.forEach { obj ->
if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
if (!checkDetectionsInstalled(obj.packages)) {
obj.assignDownload.forEach {
links.add(packageDialogEntity.links[it])
}
@ -325,9 +322,8 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
override fun onResume() {
super.onResume()
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
gameEntity?.packageDialog?.let {
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
if (isAllPackageInstalled(it)) {
callBack?.onConfirm()
dismissAllowingStateLoss()
}
@ -363,7 +359,6 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
mAdapter?.notifyDataSetChanged()
}
}
@ -388,7 +383,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
val entity = entities[position]
holder.binding.gameNameTv.text = entity.text
if (position <= index) {
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
val isAllInstalled = checkDetectionsInstalled(entity.packages)
if (isAllInstalled) {
holder.binding.statusTv.text = "已安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.text_theme))
@ -416,8 +411,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
return
}
val allInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
if (isAllPackageInstalled(packageDialogEntity)) {
callBack.onConfirm()
return
}
@ -453,13 +447,11 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
}
private fun checkDetectionsInstalled(
allInstalledPackages: List<String>,
packages: ArrayList<String>
): Boolean {
var isPackagesInstalled = false
packages.forEach { packageName ->
val isInstalled = allInstalledPackages.find { it == packageName } != null
if (isInstalled) {
if (PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance(), packageName)) {
isPackagesInstalled = true
return@forEach
}
@ -469,17 +461,14 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
fun isAllPackageInstalled(
allInstalledPackages: List<String>,
packageDialogEntity: PackageDialogEntity
): Boolean {
var isAllInstalled = true
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
isAllInstalled = false
return isAllInstalled
if (!checkDetectionsInstalled(obj.packages)) {
return false
}
}
return isAllInstalled
return true
}
}
}

View File

@ -17,7 +17,7 @@ import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogWechatBindingFailedBinding
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.login.user.UserManager
import com.lightgame.utils.Utils
class WechatBindingFailedDialogFragment : BaseDialogFragment() {
@ -48,10 +48,10 @@ class WechatBindingFailedDialogFragment : BaseDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
UserRepository.getInstance().loginUserInfo.observe(viewLifecycleOwner) {
currentUserId = it.data.getShortUserId()
binding.tvCurrentName.text = it.data.name
binding.ivCurrentAvatar.displayAvatar(it.data.icon)
UserManager.getInstance().userInfoEntity?.let {
currentUserId = it.getShortUserId()
binding.tvCurrentName.text = it.name ?: ""
binding.ivCurrentAvatar.displayAvatar(it.icon)
binding.tvUserId.text = getString(R.string.user_id, currentUserId)
}

View File

@ -31,6 +31,7 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
if (fragment == f) {
visibleState?.let { commitExposure(it) }
visibleState?.let { commitWXCPMExposure(it) }
throttleBus.clear()
}
}

View File

@ -0,0 +1,45 @@
package com.gh.common.fragment
import androidx.fragment.app.FragmentManager
import java.lang.reflect.Field
fun FragmentManager.popBackStackAllowStateLoss() {
popBackStackAllowStateLoss(-1, 0)
}
fun FragmentManager.popBackStackAllowStateLoss(id: Int, flags: Int) {
if (!isStateSaved) {
popBackStack(id, flags)
}
}
fun FragmentManager.popBackStackAllowStateLoss(name: String?, flags: Int) {
if (!isStateSaved) {
popBackStack(name, flags)
}
}
fun FragmentManager.popBackStackImmediateAllowStateLoss() = popBackStackAllowStateLoss(-1, 0)
fun FragmentManager.popBackStackImmediateAllowStateLoss(id: Int, flags: Int) =
if (!isStateSaved) {
popBackStackImmediate(id, flags)
} else {
false
}
@Throws(NoSuchFieldException::class)
private fun getField(clazz: Class<*>, name: String): Field {
var cls: Class<*>? = clazz
while (cls != null) {
try {
val declaredField = cls.getDeclaredField(name)
declaredField.isAccessible = true
return declaredField
} catch (e: NoSuchFieldException) {
e.printStackTrace()
}
cls = cls.superclass
}
throw NoSuchFieldException()
}

View File

@ -1,12 +1,9 @@
package com.gh.common.iinterface
interface ISmartRefreshContent {
/**
* 启用/关闭 页面滑动
* @param isScrollEnabled 是否启用
*/
fun setScrollEnabled(isScrollEnabled: Boolean)
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.constant.RefreshState
interface ISmartRefreshContent {
fun onRefresh()
/**
@ -14,4 +11,6 @@ interface ISmartRefreshContent {
* @param isSwipeRefreshEnabled 是否启用
*/
fun setSwipeRefreshEnabled(isSwipeRefreshEnabled: Boolean)
fun onStateChanged(refreshLayout: RefreshLayout, oldState: RefreshState, newState: RefreshState)
}

View File

@ -0,0 +1,58 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import android.net.Uri
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.core.provider.ICropImageProvider
import com.gh.gamecenter.personalhome.background.BackgroundClipActivity
import com.halo.assistant.fragment.user.UserPortraitCropImageActivity
import com.lightgame.utils.Utils
import com.zhihu.matisse.internal.utils.PathUtils
@com.therouter.inject.ServiceProvider
class CropImageProviderImpl : ICropImageProvider {
override fun getCropImageIntent(data: List<Uri>, imageType: Int, entrance: String, context: Context): Intent? {
if (data.isEmpty()) {
return null
}
val picturePath = PathUtils.getPath(context, data[0])
Utils.log("picturePath = $picturePath")
return when (imageType) {
IMAGE_TYPE_AVATAR -> {// 上传头像
UserPortraitCropImageActivity.getIntent(
context,
picturePath,
"我的光环(选择头像)"
)
}
IMAGE_TYPE_GAME_COLLECTION_COVER -> {// 游戏单封面
CropImageActivity.getIntent(
context,
picturePath,
142 / 328F,
false,
R.layout.layout_game_collection_crop_image_assist,
entrance
)
}
IMAGE_TYPE_PERSONAL_BACKGROUND -> { // 用户主页背景
BackgroundClipActivity.getIntent(context, picturePath, entrance)
}
else ->
null
}
}
companion object {
const val IMAGE_TYPE_AVATAR = 1
const val IMAGE_TYPE_GAME_COLLECTION_COVER = 2
const val IMAGE_TYPE_PERSONAL_BACKGROUND = 3
}
}

View File

@ -112,6 +112,12 @@ class DownloadButtonClickedProviderImpl : IDownloadButtonClickedProvider {
"本地下载"
}
// 小游戏的启动不需要上报下载点击事件
// @see https://jira.shanqu.cc/browse/GHZSCY-7013
if (boundedObject is GameEntity && boundedObject.isMiniGame()) {
return
}
// 上报神策点击事件
val customPageKV = customPageTrackData?.toKV() ?: arrayOf()
SensorsBridge.trackEventWithExposureSource(
@ -121,7 +127,7 @@ class DownloadButtonClickedProviderImpl : IDownloadButtonClickedProvider {
"game_name", gameName,
"game_type", gameTypeInChinese,
"download_status", downloadStatusInChinese,
"button_name", downloadButton.text,
"button_name", text,
"game_schema_type", gameSchemaType,
"download_type", downloadType,
"page_name", GlobalActivityManager.getCurrentPageEntity().pageName,

View File

@ -2,18 +2,16 @@ package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.therouter.router.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.IGameCollectionDetailProvider
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
@com.therouter.inject.ServiceProvider
class GameCollectionDetailProviderImpl : IGameCollectionDetailProvider {
override fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean): Intent {
return GameCollectionDetailActivity.getIntent(context, gameCollectionId, isFromSquare)
override fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean, entrance: String): Intent {
return GameCollectionDetailActivity.getIntent(context, gameCollectionId, isFromSquare, entrance)
}
override fun getSpecifiedCommentIntent(context: Context, gameCollectionId: String, topCommentId: String): Intent {
return GameCollectionDetailActivity.getSpecifiedCommentIntent(context, gameCollectionId, topCommentId)
override fun getSpecifiedCommentIntent(context: Context, gameCollectionId: String, topCommentId: String, entrance: String): Intent {
return GameCollectionDetailActivity.getSpecifiedCommentIntent(context, gameCollectionId, topCommentId, entrance)
}
}

View File

@ -0,0 +1,61 @@
package com.gh.common.provider
import android.annotation.SuppressLint
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.provider.IWechatPayResultProvider
import com.gh.gamecenter.feature.entity.OrderEntity
import com.gh.gamecenter.feature.entity.VipEntity
import com.gh.gamecenter.feature.eventbus.EBPayState
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.halo.assistant.member.MemberRepository
import com.therouter.TheRouter
import org.greenrobot.eventbus.EventBus
@com.therouter.inject.ServiceProvider
class WechatPayResultProviderImpl : IWechatPayResultProvider {
private val repository = MemberRepository.instance
@SuppressLint("CheckResult")
override fun onPayComplete(nonceStr: String, order: Any?) {
val orderEntity = order as? OrderEntity
repository.getWechatPayResult(nonceStr)
.compose(singleToMain())
.subscribe({
// 支付成功
EventBus.getDefault().post(EBPayState.PaySuccess)
// 先刷新本地状态,支付成功,肯定是付费会员
TheRouter.get(IAcceleratorProvider::class.java)?.setVipEntity(
VipEntity(
_vipStatus = true,
_isNewUser = false,
_isTryVip = false
)
)
val userId = UserManager.getInstance().userId
if (userId.isNotBlank()) {
UserRepository.getInstance().refreshVipStatus(userId, true)
}
SensorsBridge.trackMemberRechargeResult(
MemberRepository.PAYMENT_TYPE_WECHAT,
orderEntity?.setMenuName ?: "",
orderEntity?.paymentAmount ?: "",
MemberRepository.RECHARGE_RESULT_SUCCESS
)
}, {
// 支付失败
EventBus.getDefault().post(EBPayState.PayFail)
SensorsBridge.trackMemberRechargeResult(
MemberRepository.PAYMENT_TYPE_WECHAT,
orderEntity?.setMenuName ?: "",
orderEntity?.paymentAmount ?: "",
MemberRepository.RECHARGE_RESULT_FAILURE
)
})
}
}

View File

@ -4,6 +4,8 @@ import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDiskIOException
import android.database.sqlite.SQLiteException
import android.graphics.Bitmap
import android.net.Uri
import android.text.TextUtils
@ -284,7 +286,11 @@ object SimulatorGameManager {
entity.isRecentlyPlayed = it.id == gameId
simulatorGameRecordList.add(entity)
}
simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
try {
simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
} catch (e: SQLiteException) {
e.printStackTrace()
}
}
})
}

View File

@ -16,6 +16,7 @@ import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.provider.ISentryProvider;
import com.gh.gamecenter.core.utils.GsonUtils;
@ -39,6 +40,11 @@ import io.reactivex.schedulers.Schedulers;
*/
public class DataUtils {
// 神策 OAID 是否已绑定
private static boolean isSensorOAIDBounded = false;
// 原始的 OAID 是否已成功获取
private static boolean originalOAIDIsReceived = false;
private DataUtils() {
throw new IllegalStateException("Utility class");
}
@ -65,7 +71,6 @@ public class DataUtils {
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
String savedGid = SPUtils.getString(Constants.GID);
if (!TextUtils.isEmpty(savedGid)) {
HaloApp.getInstance().setGid(savedGid);
onGidReceived(savedGid);
} else {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@ -89,6 +94,8 @@ public class DataUtils {
}
private static void onGidReceived(String gid) {
bindValidOaidToSensor(false);
HaloApp.getInstance().setGid(gid);
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
@ -111,6 +118,35 @@ public class DataUtils {
});
}
/**
* 为神策绑定有效的 OAID
*/
public static void bindValidOaidToSensor(boolean fromOaidResult) {
if (isSensorOAIDBounded) return;
String oaid = HaloApp.getInstance().getOAID();
// 来自于 oaid 获取回调,或者说原始 oaid 已经获取成功
if (fromOaidResult || originalOAIDIsReceived) {
originalOAIDIsReceived = true;
// 遇到异常的 OAID
if (Constants.INVALID_OAID_1.equals(oaid)
|| Constants.INVALID_OAID_2.equals(oaid)
|| Constants.INVALID_OAID_3.equals(oaid)
|| TextUtils.isEmpty(oaid)) {
// 若 gid 不为空,那么整合 gid 作为 oaid https://jira.shanqu.cc/browse/GHZSCY-7004
if (HaloApp.getInstance().getGid() != null) {
oaid = "GID" + HaloApp.getInstance().getGid();
SensorsBridge.INSTANCE.setOAID(oaid);
isSensorOAIDBounded = true;
}
} else {
SensorsBridge.INSTANCE.setOAID(oaid);
isSensorOAIDBounded = true;
}
}
}
/**
* 获取应用 gid 绑定的实名信息
*/

View File

@ -5,6 +5,8 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.repository.ReservationRepository;
@ -41,7 +43,8 @@ public class DetailDownloadUtils {
/**
* 更新底部下载区域
* @param viewHolder 下载区域的包裹
*
* @param viewHolder 下载区域的包裹
* @param ignoreDownloadEntity 忽略下载实体(往往用于下载异常时)
*/
public static void updateViewHolder(DetailViewHolder viewHolder, boolean ignoreDownloadEntity) {
@ -52,6 +55,11 @@ public class DetailDownloadUtils {
if (viewHolder.getMultiVersionDownloadTv() != null) {
viewHolder.getMultiVersionDownloadTv().setVisibility(View.GONE);
}
if (viewHolder.getSpeedContainer() != null) {
viewHolder.getSpeedContainer().setVisibility(View.GONE);
}
viewHolder.setSpeedViewsVisible(false);
// 根据预置的配置更新 ViewHolder 的状态 (譬如青少年模式、下载内容为空等)
if (updateViewHolderWithPredefinedConfig(viewHolder, gameEntity)) {
@ -139,6 +147,7 @@ public class DetailDownloadUtils {
// 游戏包含多 APK 的情况
viewHolder.getMultiVersionDownloadTv().setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord));
viewHolder.getMultiVersionDownloadTv().setVisibility(View.VISIBLE);
viewHolder.getDownloadPb().setTag(com.gh.gamecenter.feature.R.string.download, viewHolder.getMultiVersionDownloadTv().getText());
viewHolder.getDownloadPb().setText("");
viewHolder.getDownloadPb().setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
@ -218,7 +227,7 @@ public class DetailDownloadUtils {
downloadButton.setText("");
}
} else {
decoratedBtnText = rawBtnText + (containsAddWord? "" : downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
decoratedBtnText = rawBtnText + (containsAddWord ? "" : downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
if (context.getString(com.gh.gamecenter.feature.R.string.launch).equals(rawBtnText)
@ -245,16 +254,24 @@ public class DetailDownloadUtils {
}
}
} else {
boolean isLaunchState = false;
// 非畅玩,显示为普通游戏
if (context.getString(com.gh.gamecenter.feature.R.string.pluggable).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
} else if (context.getString(com.gh.gamecenter.feature.R.string.launch).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
isLaunchState = true;
} else if (context.getString(com.gh.gamecenter.feature.R.string.install).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
} else {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
}
// 只有下载按钮状态为 “启动” 时才需要展示加速ui
if (isLaunchState) {
viewHolder.showAcceleratorGuideLayer();
} else {
viewHolder.hideSpeedUi();
}
if (showDualDownloadButton && viewHolder.getLocalDownloadSizeTv() != null) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.GONE);
@ -457,7 +474,7 @@ public class DetailDownloadUtils {
}
viewHolder.getDownloadPb().setButtonStyle(DownloadButton.ButtonStyle.H5_GAME);
} else {
if ("dialog".equals(gameEntity.getDownloadOffStatus())) {
if ("dialog".equals(gameEntity.getDownloadOffStatus()) || "third_party".equals(gameEntity.getDownloadOffStatus())) {
viewHolder.getDownloadPb().setText(TextUtils.isEmpty(gameEntity.getDownloadOffText()) ? "查看详情" : gameEntity.getDownloadOffText());
viewHolder.getDownloadPb().setButtonStyle(DownloadButton.ButtonStyle.NONE_WITH_HINT);
} else if ("updating".equals(gameEntity.getDownloadOffStatus())) {

View File

@ -11,7 +11,6 @@ import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.therouter.TheRouter
import com.gh.ad.AdPluginDownloadHelper
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager.log
@ -57,7 +56,6 @@ import com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity
import com.gh.gamecenter.gamecollection.hotlist.GameCollectionListDetailActivity
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarManagementActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersSubscribedGameListActivity
import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
@ -77,7 +75,6 @@ import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.servers.GameServerTestActivity
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.servers.gametest2.GameServerTestV2Activity
@ -98,6 +95,7 @@ import com.halo.assistant.fragment.WebFragment
import com.lightgame.utils.Utils
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.therouter.TheRouter
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
@ -178,7 +176,23 @@ object DirectUtils {
"qa",
"feedback",
"toolkit",
"float_window_game"
"float_window_game",
"my_halo",
"my_game",
"server_manager",
"receiving_information",
"game_archive",
"game_dynamics",
"game_upload",
"certification",
"wechat_reminder",
"apk_clean",
"personal_center",
"video_upload",
"account_security",
"simulator",
"teen_mode",
"message_center",
)
fun directToLinkPage(
@ -383,8 +397,8 @@ object DirectUtils {
}
}
"authentication" -> {
context.startActivity(ShellActivity.getIntent(context, ShellActivity.Type.REAL_NAME_INFO, null))
"authentication", "certification" -> {
directToRealName(context)
}
"user_background" -> {
@ -442,7 +456,7 @@ object DirectUtils {
} ?: ""
}
"halo_tab" -> directToHomeMyHaloTab(context)
"my_halo", "halo_tab" -> directToHomeMyHaloTab(context)
"common_collection" -> directToCommonCollectionDetail(
context,
@ -524,7 +538,8 @@ object DirectUtils {
ToolbarWrapperActivity.getMultiTabNavIntent(
context,
linkEntity.link ?: "",
linkEntity.text ?: ""
linkEntity.text ?: "",
entrance
)
)
@ -532,16 +547,20 @@ object DirectUtils {
ToolbarWrapperActivity.getCustomPageIntent(
context,
linkEntity.link ?: "",
linkEntity.text ?: ""
linkEntity.text ?: "",
entrance
)
)
// 选中首页底部 tab
"bottom_tab" -> {
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
if (HaloApp.getInstance().isRunningForeground) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
} else {
jumpActivity(context, Bundle())
}
context.startActivity(intent)
if (linkEntity is LaunchRedirect) {
MainWrapperRepository.getInstance().sendSelectTabEvent(linkEntity)
@ -568,6 +587,32 @@ object DirectUtils {
}
}
"my_game" -> directToMyGame(0, entrance)
"server_manager" -> directToServersCalendarManagement(entrance)
"receiving_information" -> directToDeliveryInfo(entrance)
"game_archive" -> directToGameArchive(entrance)
"game_dynamics" -> directToConcernInfo(context, entrance)
"wechat_reminder" -> CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(WebActivity.getBindWechatIntent(context))
}
"apk_clean" -> directToCleanApk(context, entrance)
"personal_center" -> directToUserInfo(entrance)
"simulator" -> directToSimulatorGame(entrance)
"account_security" -> directToAccountSecurity(entrance)
"teen_mode" -> directToTeenMode(entrance)
"message_center" -> directToMessageCenter(0, entrance)
"" -> {
// do nothing
}
@ -2083,13 +2128,17 @@ object DirectUtils {
/**
* 跳转到开服订阅页面
* @param context 上下文
*/
@JvmStatic
fun directToServersCalendarManagement(context: Context, entrance: String) {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(ServersCalendarManagementActivity.getIntent(context))
}
fun directToServersCalendarManagement(entrance: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.serversCalendarManagementActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, entrance)
.build()
TheRouter.build(uri.toString())
.navigation()
}
fun directToSearch(
@ -2149,4 +2198,100 @@ object DirectUtils {
)
}
}
@JvmStatic
fun directToMyGame(defaultTabIndex: Int, source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.myGameActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.withInt(BaseActivity_TabLayout.PAGE_INDEX, defaultTabIndex)
.navigation()
}
@JvmStatic
fun directToDeliveryInfo(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.deliveryInfoActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToGameArchive(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.gameArchiveListActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToSimulatorGame(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.simulatorGameActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToTeenMode(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.teenagerModeActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToUserInfo(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.userInfoActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToCleanApk(context: Context, source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.cleanApkActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
PermissionHelper.checkManageAllFilesOrStoragePermissionBeforeAction(context) {
TheRouter.build(uri.toString())
.navigation()
}
}
@JvmStatic
fun directToAccountSecurity(source: String, isLogoutStyle: Boolean = false) {
val uri = Uri.Builder()
.path(RouteConsts.activity.securityActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.withString(KEY_ENTRANCE, source)
.withBoolean(KEY_DISPLAY_TYPE, isLogoutStyle)
.navigation()
}
}

View File

@ -280,9 +280,9 @@ object DownloadItemUtils {
isClickable = true
buttonStyle = DownloadButton.ButtonStyle.NORMAL
} else {
if ("dialog" == offStatus) {
if ("dialog" == offStatus || "third_party" == offStatus) {
text = context.getString(com.gh.gamecenter.feature.R.string.check)
buttonStyle = DownloadButton.ButtonStyle.NORMAL
buttonStyle = DownloadButton.ButtonStyle.NONE_WITH_HINT
} else if ("updating" == offStatus) {
text = context.getString(com.gh.gamecenter.feature.R.string.updating)
buttonStyle = DownloadButton.ButtonStyle.UPDATING
@ -839,34 +839,25 @@ object DownloadItemUtils {
} else {
allStateClickCallback?.onCallback()
clickCallback?.onCallback()
if ("download" == gameEntity.reserveStatus) {
ReservationHelper.showDeleteReservationDialog(context) {
ReservationHelper.deleteReservation(gameEntity) {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
ReservationHelper.showCancelReservationDialog(context, gameEntity, {
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"确定取消",
gameEntity.id,
gameEntity.name ?: ""
)
ReservationHelper.cancelReservation(gameEntity) {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
} else {
ReservationHelper.showCancelReservationDialog(context, gameEntity,{
}, object : CancelListener {
override fun onCancel() {
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"确定取消",
"关闭弹窗",
gameEntity.id,
gameEntity.name ?: ""
)
ReservationHelper.cancelReservation(gameEntity) {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
}, object : CancelListener {
override fun onCancel() {
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"关闭弹窗",
gameEntity.id,
gameEntity.name ?: ""
)
}
})
}
}
})
}
}
return

View File

@ -53,6 +53,7 @@ object DownloadObserver {
private const val CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED = "CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED"
private val mRetryableHashMap = hashMapOf<String, Boolean>()
private val mRetryableProgressMap = hashMapOf<String, Long>()
/**
* 当下载任务是 预约上线提醒 触发的,则所有弹窗均不显示
@ -146,7 +147,8 @@ object DownloadObserver {
|| DownloadStatus.timeout == status
) {
if (mRetryableHashMap[downloadEntity.url] == true
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
&& (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
|| NDownloadBridge.isDownloadViaTrafficAllowed(downloadEntity))
) {
downloadManager.resumeDownload(downloadEntity.url)
mRetryableHashMap[downloadEntity.url] = false
@ -257,6 +259,7 @@ object DownloadObserver {
}
mRetryableHashMap.remove(downloadEntity.url)
mRetryableProgressMap.remove(downloadEntity.url)
EventBus.getDefault().post(EBDownloadStatus("done", "", "", "", downloadEntity.packageName, ""))
}
@ -264,7 +267,9 @@ object DownloadObserver {
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
// 如果已下载大小发生变化,表示成功恢复下载,则重置重试标记
if (status == DownloadStatus.downloading) {
if (status == DownloadStatus.downloading
&& downloadEntity.progress != mRetryableProgressMap[downloadEntity.url]) {
mRetryableProgressMap[downloadEntity.url] = downloadEntity.progress
mRetryableHashMap[downloadEntity.url] = true
}
}

View File

@ -135,12 +135,16 @@ object GameUtils {
// 畅玩状态优先,且畅玩实体不为空时将 downloadEntity 置为畅玩实体
if (performAsVGame && vGameDownloadEntity != null) {
downloadEntity = vGameDownloadEntity
} else if (!performAsVGame && !isFromList && downloadEntity?.isVGameDownloadInDualDownloadMode() == true) {
// 下载的任务是由畅玩触发的,游戏详情页不需判定为需要安装
downloadEntity = null
} else if (performAsVGame && !isFromList && downloadEntity?.isLocalDownloadInDualDownloadMode() == true) {
// 下载的任务是由下载安装触发的,游戏详情页不需判定为需要安装
downloadEntity = null
} else if (!isFromList) {
if (!performAsVGame
&& gameEntity.isDualBtnModeEnabled()
&& downloadEntity?.isVGameDownloadInDualDownloadMode() == true) {
// 下载的任务是由畅玩触发的,并且双下载按钮启用,游戏详情页不需判定为需要安装
downloadEntity = null
} else if (performAsVGame && downloadEntity?.isLocalDownloadInDualDownloadMode() == true) {
// 下载的任务是由下载安装触发的,游戏详情页不需判定为需要安装
downloadEntity = null
}
}
if (downloadEntity != null) {

View File

@ -2778,4 +2778,34 @@ object NewFlatLogUtils {
parseAndPutMeta()(this)
}.let(::log)
}
// 自有开屏广告加载
fun logSplashAdLoad(id: String) {
json {
KEY_EVENT to "splash_ad_load"
"ad_id" to id
parseAndPutMeta()(this)
}.let(::log)
}
// 自有开屏广告展示
fun logSplashAdShow(id: String, duration: Long) {
json {
KEY_EVENT to "splash_ad_show"
"ad_id" to id
"duration" to duration
parseAndPutMeta()(this)
}.let(::log)
}
// 自有开屏广告加载/展示失败
@JvmStatic
fun logSplashAdFail(id: String, error: String) {
json {
KEY_EVENT to "splash_ad_fail"
"ad_id" to id
"error" to error
parseAndPutMeta()(this)
}.let(::log)
}
}

View File

@ -578,7 +578,6 @@ object PackageHelper {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
@ -587,18 +586,9 @@ object PackageHelper {
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
) {
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
@ -616,12 +606,6 @@ object PackageHelper {
additionalWhiteListPackageNameSet.toString()
)
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName)
}
}
}
}
}
@ -635,7 +619,6 @@ object PackageHelper {
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (game in gameEntityList) {
for (apk in game.getApk()) {
@ -651,13 +634,6 @@ object PackageHelper {
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
&& !PackagesManager.isCanUpdate(game.id, packageName, false)
) {
cachedPkgNameAndGameEntityMap.put(packageName, game)
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
}
@ -666,10 +642,6 @@ object PackageHelper {
TAG,
"refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
@ -699,12 +671,6 @@ object PackageHelper {
additionalWhiteListPackageNameSet.toString()
)
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
}
}
}
}
}

View File

@ -18,7 +18,6 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.install.InstallService
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@ -194,12 +193,6 @@ object PackageInstaller {
private fun install(context: Context, pkgPath: String, pkgName: String?) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU && Build.MANUFACTURER.lowercase().contains("xiaomi")) {
val foregroundServiceIntent = Intent(context, InstallService::class.java)
foregroundServiceIntent.putExtra(InstallService.KEY_SERVICE_ACTION, InstallService.START_FOREGROUND)
context.startForegroundService(foregroundServiceIntent)
}
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
@ -284,7 +277,12 @@ object PackageInstaller {
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
}
updateSystemInstallerIfAvailable(context, installIntent)
// 优选系统的安装器(遇到 Exception 就回落到正常的安装器)
try {
updateSystemInstallerIfAvailable(context, installIntent)
} catch (ignored: Exception) {
// ignored
}
InstallUtils.getInstance()
.addInstall(PackageUtils.getPackageNameByPath(context, path))

View File

@ -7,7 +7,7 @@ import com.gh.gamecenter.common.utils.isVGameDownloadInDualDownloadMode
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.manager.PackagesManager
import com.gh.vspace.VHelper
object PackageLauncher {
@ -81,28 +81,11 @@ object PackageLauncher {
gameEntity: GameEntity? = null,
packageName: String?
) {
if (packageName.isNullOrEmpty()) {
ToastUtils.toast("启动失败")
return
}
// 获取 GameInstall 实体,用于记录启动日志用
val gameInstall = if (gameEntity != null) {
GameInstall.transformGameInstall(gameEntity, packageName)
} else {
PackageRepository.gameInstalled.find { it.packageName == packageName }
}
if (gameInstall != null) {
NewFlatLogUtils.logGameLaunch(
gameId = gameInstall.id ?: "unknown",
gameName = gameInstall.name ?: "unknown",
gameCategory = gameInstall.category ?: "unknown",
downloadStatus = if (gameInstall.downloadStatus == "demo") "试玩" else "下载"
)
}
try {
val intent = context.applicationContext.packageManager.getLaunchIntentForPackage(packageName)
if (intent != null) {
@ -113,6 +96,26 @@ object PackageLauncher {
} catch (e: Exception) {
ToastUtils.toast( "启动失败")
}
try {
// 获取 GameInstall 实体,用于记录启动日志用
val gameInstall = if (gameEntity != null) {
GameInstall.transformGameInstall(gameEntity, packageName)
} else {
PackagesManager.getInstalledList().find { it.packageName == packageName }
}
if (gameInstall != null) {
NewFlatLogUtils.logGameLaunch(
gameId = gameInstall.id ?: "unknown",
gameName = gameInstall.name ?: "unknown",
gameCategory = gameInstall.category ?: "unknown",
downloadStatus = if (gameInstall.downloadStatus == "demo") "试玩" else "下载"
)
}
} catch (e: RuntimeException) {
// 都 DeadSystemException 了,还想啥日志上报
}
}
}

View File

@ -14,7 +14,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.AndroidException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -29,9 +28,9 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.MD5Utils;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.vspace.VHelper;
@ -302,7 +301,7 @@ public class PackageUtils {
Signature[] signatures = packageInfo.signatures;
// 使用幸运破解器破解安卓签名认证可能会出现不用签名也能装的情况,这里有可能是空的
if (signatures[0] != null) {
if (signatures.length > 0 && signatures[0] != null) {
return parseSignature(signatures[0].toByteArray());
} else {
return new String[]{null, null};
@ -542,10 +541,8 @@ public class PackageUtils {
try {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
return intent != null;
} catch (IllegalArgumentException exception) {
// 一些设备调用获取 intent 的时候会触发 Parcel.readException !
exception.printStackTrace();
return false;
} catch (Exception exception) {
return PackageHelper.INSTANCE.getLocalPackageNameSet().contains(packageName);
}
}
@ -645,6 +642,19 @@ public class PackageUtils {
return 0;
}
/*
* 获取应用的名称
*/
public static CharSequence getNameByPackageName(Context context, String packageName) {
try {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA));
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/*
* 获取应用的 icon

View File

@ -29,53 +29,31 @@ import okhttp3.ResponseBody
object ReservationHelper {
@JvmStatic
fun deleteReservation(game: GameEntity, refreshCallback: EmptyCallback) {
deleteOrCancelReservation(game, true, refreshCallback)
}
@JvmStatic
fun cancelReservation(game: GameEntity, refreshCallback: EmptyCallback) {
deleteOrCancelReservation(game, false, refreshCallback)
}
@SuppressLint("CheckResult")
private fun deleteOrCancelReservation(
@JvmStatic
fun cancelReservation(
game: GameEntity,
deleteReservation: Boolean,
refreshCallback: EmptyCallback
) {
val retrofit = RetrofitManager.getInstance()
val single = if (deleteReservation) {
retrofit.newApi
.deleteGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
} else {
retrofit.newApi
.cancelGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
retrofit.newApi
.cancelGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
ReservationRepository.removeReservationFromMemoryAndRefresh(game.id)
refreshCallback.onCallback()
}
single.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
ReservationRepository.removeReservationFromMemoryAndRefresh(game.id)
refreshCallback.onCallback()
}
override fun onFailure(exception: Exception) {
Utils.toast(HaloApp.getInstance().application, exception.message)
exception.printStackTrace()
}
})
override fun onFailure(exception: Exception) {
Utils.toast(HaloApp.getInstance().application, exception.message)
exception.printStackTrace()
}
})
}
@JvmStatic
@ -146,21 +124,6 @@ object ReservationHelper {
})
}
@JvmStatic
fun showDeleteReservationDialog(context: Context, emptyCallback: EmptyCallback) {
DialogUtils.showCancelOrDeleteReservationDialog(
context,
"删除预约",
"游戏已上线,你可以删除此预约记录,确定删除吗?",
"确定删除",
"暂不删除", object : ConfirmListener {
override fun onConfirm() {
emptyCallback.onCallback()
}
}, null
)
}
@JvmStatic
fun showCancelReservationDialog(context: Context, game: GameEntity?, emptyCallback: EmptyCallback) {
showCancelReservationDialog(context, game, emptyCallback, null)

View File

@ -6,6 +6,7 @@ import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.ndownload.NHttpClient
import com.lightgame.utils.AppManager
import org.json.JSONObject
@ -89,4 +90,12 @@ object TempCertificationUtils {
return stringBuffer.toString()
}
/**
* 检测光环是否实名
*/
fun isUserVerified(): Boolean {
val idCard = UserManager.getInstance().userInfoEntity?.idCard
// 账号已实名
return idCard != null && idCard.status == 0
}
}

View File

@ -2,6 +2,7 @@ package com.gh.download.simple
import android.annotation.SuppressLint
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteFullException
import com.gh.gamecenter.core.utils.ToastUtils
import com.lg.download.*
import com.lg.download.listener.InnerDownloadListener
@ -174,6 +175,9 @@ object DownloadMessageHandler : InnerDownloadListener {
DownloadError.CONTENT_LENGTH_IS_ZERO -> {
ToastUtils.toast("下载链接异常,请检查")
}
DownloadError.DISK_IS_FULL -> {
ToastUtils.toast("磁盘已满,请清理空间后获得更好的体验")
}
else -> {
// 想怎么处理就怎么处理
}
@ -264,18 +268,30 @@ object DownloadMessageHandler : InnerDownloadListener {
}
fun insertDownloadToDatabase(downloadEntity: SimpleDownloadEntity) {
mDownloadDao.insertDownloadEntity(downloadEntity)
updateDownloadList()
try {
mDownloadDao.insertDownloadEntity(downloadEntity)
updateDownloadList()
} catch (e: SQLiteException) {
if (e is SQLiteFullException) {
ToastUtils.showToast("磁盘已满,请清理空间获得更好的体验")
}
e.printStackTrace()
}
}
fun updateDownloadToDatabase(
downloadEntity: SimpleDownloadEntity,
updateDownloadList: Boolean = false
) {
mDownloadDao.updateDownloadEntity(downloadEntity)
try {
mDownloadDao.updateDownloadEntity(downloadEntity)
if (updateDownloadList) {
updateDownloadList()
if (updateDownloadList) {
updateDownloadList()
}
} catch (e: SQLiteFullException) {
// 底层的下载服务遇到 SQLiteFullException 时会自动暂停下载任务,上层这里就不用纠结处理方式了
e.printStackTrace()
}
}

View File

@ -0,0 +1,81 @@
package com.gh.gamecenter
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.feature.entity.BaseEntity
import com.gh.gamecenter.login.retrofit.RetrofitManager
import com.gh.gamecenter.login.user.UserManager
import com.therouter.TheRouter
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
/**
* 奇游用户批量注册
*/
class BatchRegisterActivity : AppCompatActivity() {
private val userIds = listOf(
""
)
private var iAcceleratorProvider: IAcceleratorProvider? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_batch_register)
iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
val btnRegister = findViewById<Button>(R.id.btn_register)
btnRegister.setOnClickListener {
doRegister()
}
}
private fun doRegister() {
println("kayn -->doRegister:${userIds.size}")
Observable.fromIterable(userIds)
.flatMap({ userId ->
RetrofitManager.getInstance().newApi
.getQyToken(userId, "gjonline_vip")
.onErrorReturnItem(BaseEntity())
.flatMap { entity ->
val token = entity.data?.token ?: ""
Single.create<Pair<Boolean, String>> {
if (token.isBlank()) {
it.onSuccess(false to userId)
} else {
iAcceleratorProvider?.setQyUserToken(token) { isSuccess ->
it.onSuccess(isSuccess to userId)
}
}
}
}.toObservable()
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<Pair<Boolean, String>>() {
override fun onNext(response: Pair<Boolean, String>) {
super.onNext(response)
val (isSuccess, userId) = response
println("kayn -->isSuccess:$isSuccess --userId:$userId")
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
}
override fun onComplete() {
super.onComplete()
}
})
}
}

View File

@ -3,26 +3,25 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.utils.BitmapUtils;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.BitmapUtils;
import com.gh.gamecenter.common.view.CropImageCustom;
import com.gh.gamecenter.common.view.cropbox.CropBoxStyle;
import com.gh.gamecenter.core.utils.DisplayUtils;
import java.io.File;
import java.lang.ref.SoftReference;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
/**
* 裁剪图片
*/
@ -32,6 +31,8 @@ public class CropImageActivity extends ToolBarActivity {
public static final String RESULT_CLIP_PATH = "result_clip_path";
public static final String RESULT_ORIGINAL_PATH = "result_original_path";
private SoftReference<Bitmap> reference;
protected boolean mBlackTheme = false;
@ -51,7 +52,7 @@ public class CropImageActivity extends ToolBarActivity {
Intent intent = new Intent(context, CropImageActivity.class);
intent.putExtra(EntranceConsts.KEY_PATH, picturePath);
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance);
intent.putExtra(EntranceConsts.KEY_IMAGE_CROP_RATIO, cropRatio);
intent.putExtra(EntranceConsts.KEY_IMAGE_CROP_STYLE, new CropBoxStyle.Rectangle(cropRatio));
intent.putExtra(EntranceConsts.KEY_BLACK_THEME, isBlackTheme);
intent.putExtra(EntranceConsts.KEY_ASSIST_RES, assistRes);
return intent;
@ -68,20 +69,14 @@ public class CropImageActivity extends ToolBarActivity {
super.onCreate(savedInstanceState);
mCropImageCustom = findViewById(R.id.cropimage_custom);
View statusBarView = findViewById(R.id.status_bar);
TextView tvCancel = findViewById(R.id.tv_cancel);
TextView tvSubmit = findViewById(R.id.tv_submit);
mTitleTv.setTextColor(mBlackTheme ? Color.WHITE : Color.BLACK);
mToolbar.setBackgroundColor(getResources().getColor(mBlackTheme ? com.gh.gamecenter.common.R.color.text_28282E : com.gh.gamecenter.common.R.color.white));
statusBarView.setBackgroundColor(getResources().getColor(mBlackTheme ? com.gh.gamecenter.common.R.color.text_28282E : com.gh.gamecenter.common.R.color.white));
setNavigationTitle(getString(R.string.title_crop_image));
setToolbarMenu(R.menu.menu_positive);
MenuItem menuItem = getMenuItem(R.id.layout_menu_positive);
TextView menuButton = menuItem.getActionView().findViewById(R.id.menu_answer_post);
menuButton.setTextColor(getResources().getColor(com.gh.gamecenter.common.R.color.text_theme));
float ratio = getIntent().getFloatExtra(EntranceConsts.KEY_IMAGE_CROP_RATIO, 1F);
mCropImageCustom.setCropRatio(ratio);
CropBoxStyle boxStyle = getIntent().getParcelableExtra(EntranceConsts.KEY_IMAGE_CROP_STYLE);
if (boxStyle == null) {
boxStyle = new CropBoxStyle.Rectangle(1F);
}
mCropImageCustom.setCropBoxStyle(boxStyle);
int assistRes = getIntent().getIntExtra(EntranceConsts.KEY_ASSIST_RES, -1);
if (assistRes > 0) {
@ -89,8 +84,21 @@ public class CropImageActivity extends ToolBarActivity {
addAssistView(view);
}
DisplayUtils.setLightStatusBar(this, !mBlackTheme);
DisplayUtils.setStatusBarColor(this, com.gh.gamecenter.common.R.color.transparent, !mBlackTheme);
DisplayUtils.setLightStatusBar(this, false);
DisplayUtils.setStatusBarColor(this, com.gh.gamecenter.common.R.color.transparent, false);
tvCancel.setOnClickListener(v -> finish());
tvSubmit.setOnClickListener(v -> saveImage());
}
protected void saveImage() {
Intent data = new Intent();
String clipPath = getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg";
mCropImageCustom.savePicture(clipPath);
data.putExtra(RESULT_CLIP_PATH, clipPath);
setResult(RESULT_OK, data);
finish();
}
@Override
@ -98,20 +106,6 @@ public class CropImageActivity extends ToolBarActivity {
return mBlackTheme ? com.gh.gamecenter.common.R.drawable.ic_toolbar_back_white : com.gh.gamecenter.common.R.drawable.ic_bar_back;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.layout_menu_positive) {
Intent data = new Intent();
String clipPath = getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg";
mCropImageCustom.savePicture(clipPath);
data.putExtra(RESULT_CLIP_PATH, clipPath);
setResult(RESULT_OK, data);
finish();
}
return super.onMenuItemClick(item);
}
public void addAssistView(View view) {
mCropImageCustom.addAssistView(view);
}

View File

@ -166,8 +166,13 @@ public class MainActivity extends BaseActivity {
private final Handler handler = new Handler();
private boolean mShouldShowAd = false; // 是否显示广告
private Bundle mTempSavedInstanceState;
private boolean mFragmentIsCreated = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
mTempSavedInstanceState = savedInstanceState;
mShouldShowAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null
&& !HaloApp.getInstance().isAlreadyUpAndRunning;
HaloApp.getInstance().isAlreadyUpAndRunning = true;
@ -175,21 +180,12 @@ public class MainActivity extends BaseActivity {
mMainWrapperViewModel = new ViewModelProvider(this, new MainWrapperViewModel.Factory(HaloApp.getInstance()))
.get(MainWrapperViewModel.class);
DisplayUtils.transparentStatusBar(this);
DisplayUtils.updateGlobalScreen(this);
super.onCreate(savedInstanceState);
setStatusBarColor(Color.TRANSPARENT);
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(com.gh.gamecenter.selector.R.id.layout_activity_content);
mMainWrapperFragment = fragmentFromFM != null ? (MainWrapperFragment) fragmentFromFM : new MainWrapperFragment();
if (savedInstanceState != null) {
mMainWrapperFragment.setArguments(savedInstanceState);
} else if (getIntent() != null) {
mMainWrapperFragment.setArguments(getIntent().getExtras());
}
replaceFragment(mMainWrapperFragment);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (HaloApp.getInstance().isNewForThisVersion) {
LunchType lunchType = HaloApp.getInstance().getLaunchType();
@ -215,7 +211,6 @@ public class MainActivity extends BaseActivity {
DataUtils.getGid();
}
mPackageViewModel = ViewModelProviders.of(this, new PackageViewModel.Factory()).get(PackageViewModel.class);
final boolean containsErrorMsg = com.gh.gamecenter.common.constant.Config.isContainsErrorMsg();
@ -273,6 +268,7 @@ public class MainActivity extends BaseActivity {
if (mShouldShowAd) {
showAd();
} else {
doInitMainFragment(mTempSavedInstanceState);
hideTextAd();
hideSplashAd();
}
@ -328,6 +324,23 @@ public class MainActivity extends BaseActivity {
CertificationSwitchHelper.getCertificationSwitch();
}
private void doInitMainFragment(Bundle savedInstanceState) {
if (mFragmentIsCreated) return;
mTempSavedInstanceState = null;
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(com.gh.gamecenter.selector.R.id.layout_activity_content);
mMainWrapperFragment = fragmentFromFM != null ? (MainWrapperFragment) fragmentFromFM : new MainWrapperFragment();
if (savedInstanceState != null) {
mMainWrapperFragment.setArguments(savedInstanceState);
} else if (getIntent() != null) {
mMainWrapperFragment.setArguments(getIntent().getExtras());
}
replaceFragment(mMainWrapperFragment);
mFragmentIsCreated = true;
}
@SuppressLint("CheckResult")
private void getTeenagerMode() {
RetrofitManager.getInstance()
@ -541,19 +554,31 @@ public class MainActivity extends BaseActivity {
protected void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == COUNTDOWN_AD || msg.what == COUNTDOWN_SDK_AD) {
mCountdownCount++;
int maxCount;
if (msg.what == COUNTDOWN_AD) {
maxCount = mCountdownMaxCount;
} else {
maxCount = COUNTDOWN_SDK_MAX_COUNT;
}
// 读秒到一半的时候初始化 MainWrapperFragment
if (mCountdownCount == maxCount / 2) {
doInitMainFragment(mTempSavedInstanceState);
}
mCountdownCount++;
if (maxCount < mCountdownCount) {
AdDelegateHelper.INSTANCE.setShowingSplashAd(false);
hideSplashAd();
if (msg.what == COUNTDOWN_AD && msg.obj instanceof StartupAdEntity) {
StartupAdEntity ad = (StartupAdEntity) msg.obj;
if (!AdDelegateHelper.INSTANCE.isOwnerSplashAdShown()) {
com.gh.common.util.NewFlatLogUtils.logSplashAdFail(ad.getId(), "广告加载超时");
}
AdDelegateHelper.INSTANCE.setOwnerSplashAdShown(false);
LinkEntity linkEntity = ad.getJump();
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
@ -633,10 +658,11 @@ public class MainActivity extends BaseActivity {
ExtensionsKt.removeFromParent(startSdkAdIcpContainer, true);
}
onSplashHidden();
onAdHidden();
}
private void onSplashHidden() {
private void onAdHidden() {
doInitMainFragment(mTempSavedInstanceState);
// 通知全局弹窗可以进行显示
AppExecutor.getUiExecutor().execute(GlobalPriorityChainHelper.INSTANCE::start);
}
@ -854,7 +880,9 @@ public class MainActivity extends BaseActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 && !mMainWrapperFragment.onHandleBackPressed()) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0
&& mMainWrapperFragment != null
&& !mMainWrapperFragment.onHandleBackPressed()) {
DownloadEntity downloadEntity = null;
for (DownloadEntity entity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentTask()) {
if (entity.getStatus().equals(DownloadStatus.done)) {
@ -1045,6 +1073,7 @@ public class MainActivity extends BaseActivity {
blackList.add(R.id.historyTv);
blackList.add(R.id.myCollectionTv);
blackList.add(R.id.searchTv);
blackList.add(R.id.subject_tab);
updateStaticView(view, blackList);
View communityHomeWrapper = view.findViewById(R.id.communityHomeContainer);

View File

@ -15,6 +15,7 @@ import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.gh.common.fragment.popBackStackAllowStateLoss
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.LogUtils
import com.gh.gamecenter.DisplayType.*
@ -190,6 +191,7 @@ open class SearchActivity : BaseActivity() {
when (type) {
SearchType.AUTO -> handleAutoSearch(key)
SearchType.DEFAULT -> handleDefaultSearch(key)
SearchType.DISCOVERY -> handleDiscoverySearch(key)
SearchType.RANK -> handleRankSearch(key)
SearchType.HOT -> handleHotSearch(key)
SearchType.HISTORY -> handleHistorySearch(key)
@ -243,6 +245,22 @@ open class SearchActivity : BaseActivity() {
)
}
protected open fun handleDiscoverySearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(GAME_DETAIL)
LogUtils.uploadSearchGame("searching", "搜索页", key, "搜索发现")
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_DISCOVERY,
mSourceEntrance
)
}
protected open fun handleDefaultSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
@ -311,6 +329,19 @@ open class SearchActivity : BaseActivity() {
// MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
}
override fun onResume() {
super.onResume()
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
if (newSearchKey.isBlank()) {
try {
popBackToFragment(SearchDefaultFragment::class.java.name)
} catch (e: Exception) {
// no implement
}
}
}
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)
open fun updateDisplayType(type: DisplayType) {
@ -381,7 +412,7 @@ open class SearchActivity : BaseActivity() {
}
protected fun popBackToFragment(tag: String) {
supportFragmentManager.popBackStack(tag, 0)
supportFragmentManager.popBackStackAllowStateLoss(tag, 0)
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -390,6 +421,7 @@ open class SearchActivity : BaseActivity() {
SearchType.HISTORY.value -> search(SearchType.HISTORY, search.key)
SearchType.HOT.value -> search(SearchType.HOT, search.key)
SearchType.RANK.value -> search(SearchType.RANK, search.key)
SearchType.DISCOVERY.value -> search(SearchType.DISCOVERY, search.key)
"click" -> DataCollectionUtils.uploadSearchClick(
this, mSearchKey, mSearchType.value, "搜索页面",
@ -434,6 +466,7 @@ open class SearchActivity : BaseActivity() {
const val TRACK_SEARCH_TYPE_DEFAULT = "默认搜索"
const val TRACK_SEARCH_TYPE_HISTORY = "历史搜索"
const val TRACK_SEARCH_TYPE_RANK = "榜单搜索"
const val TRACK_SEARCH_TYPE_DISCOVERY = "搜索发现"
@JvmStatic
fun toTrackSearchType(type: String) = when (type) {
@ -441,6 +474,7 @@ open class SearchActivity : BaseActivity() {
SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
SearchType.HISTORY.value -> TRACK_SEARCH_TYPE_HISTORY
SearchType.RANK.value -> TRACK_SEARCH_TYPE_RANK
SearchType.DISCOVERY.value -> TRACK_SEARCH_TYPE_DISCOVERY
else -> TRACK_SEARCH_TYPE_DEFAULT
}
@ -490,7 +524,8 @@ enum class SearchType(var value: String) {
HISTORY("history"),
MANUAL("initiative"),
HOT("remen"),
RANK("rank");
RANK("rank"),
DISCOVERY("dicovery");
fun toChinese() = when (this) {
AUTO -> "自动搜索"
@ -499,6 +534,7 @@ enum class SearchType(var value: String) {
MANUAL -> "主动搜索"
HOT -> "热门搜索"
RANK -> "榜单搜索"
DISCOVERY -> "搜索发现"
}
companion object {

View File

@ -62,16 +62,16 @@ import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.entity.CommunityEntity;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.entity.LaunchRedirect;
import com.gh.gamecenter.common.entity.SimpleGameEntity;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.entity.SubjectData;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.VideoLinkEntity;
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.login.view.LoginActivity;
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper;
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
import com.gh.vspace.VHelper;
@ -356,8 +356,8 @@ public class SkipActivity extends BaseActivity {
if (!TextUtils.isEmpty(dataString)) {
byte[] linkData = Base64.decode(dataString, Base64.DEFAULT);
String linkDataString = new String(linkData, "UTF-8");
LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class);
DirectUtils.directToLinkPage(this, le, entrance, "", "");
LaunchRedirect launchRedirect = GsonUtils.fromJson(linkDataString, LaunchRedirect.class);
DirectUtils.directToLinkPage(this, launchRedirect, entrance, "", "");
}
} catch (Exception e) {
e.printStackTrace();

View File

@ -14,8 +14,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.text.bold
import androidx.core.text.buildSpannedString
import androidx.core.text.color
import com.therouter.router.Route
import com.therouter.TheRouter
import com.gh.common.dialog.NewPrivacyPolicyDialogFragment
import com.gh.common.util.DeviceTokenUtils
import com.gh.common.util.DialogUtils
@ -32,13 +30,14 @@ import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.iinterface.ISplashScreen
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IPackageUtilsProvider
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.feature.utils.PlatformUtils
import com.gh.gamecenter.pkg.PkgHelper
import com.halo.assistant.HaloApp
import com.therouter.TheRouter
import com.therouter.router.Route
import org.json.JSONObject
import splitties.systemservices.notificationManager
import java.text.SimpleDateFormat
@ -90,8 +89,10 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
showPrivacyDialog()
} else {
val spanBuilder = buildSpannedString {
append("这个弹窗只会在右上角有环境标签的测试包出现" +
"\n进入应用以后还可以到关于我们页面长按应用图标重新选择")
append(
"这个弹窗只会在右上角有环境标签的测试包出现" +
"\n进入应用以后还可以到关于我们页面长按应用图标重新选择"
)
bold {
color(com.gh.gamecenter.common.R.color.text_theme.toColor(this@SplashScreenActivity)) {
append("\n点击这里进行预设置渠道")
@ -103,7 +104,7 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
executeDex2OatInAdvance()
DialogHelper.showDialog(
context = this,
title ="选择环境",
title = "选择环境",
content = spanBuilder,
confirmText = "正式环境",
cancelText = "测试环境",
@ -130,6 +131,7 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
} else {
launchMainActivity()
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
SPUtils.setString(Constants.SP_XAPK_URL, "")
@ -282,11 +284,11 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
SensorsBridge.setOAID(HaloApp.getInstance().oaid)
val pushProvider = TheRouter.get(IPushProvider::class.java)
val registrationId = pushProvider?.getRegistrationId(this)
if (!registrationId.isNullOrEmpty()) {
SensorsBridge.profileAppend(KEY_REGISTRATION_ID, registrationId)
}
// val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
// val registrationId = pushProvider?.getRegistrationId(this)
// if (!registrationId.isNullOrEmpty()) {
// SensorsBridge.profileSet(KEY_REGISTRATION_ID, registrationId)
// }
}
private fun prefetchData() {

View File

@ -4,12 +4,15 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.halo.assistant.fragment.user.UserInfoFragment
import com.therouter.router.Route
/**
* 编辑资料
*/
@Route(
path = RouteConsts.activity.userInfoActivity,
description = "个人中心"
)
class UserInfoActivity : ToolBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@ -17,6 +20,14 @@ class UserInfoActivity : ToolBarActivity() {
updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
UserInfoActivity::class.java,
UserInfoFragment::class.java
)
}
companion object {
fun getIntent(context: Context?): Intent? {
return getTargetIntent(

View File

@ -6,17 +6,19 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.KeyEvent
import android.view.View
import com.therouter.router.Route
import com.gh.common.constant.Config
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.ToolBoxEntity
import com.gh.gamecenter.common.utils.EnvHelper
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.feature.entity.ConcernEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.common.entity.ToolBoxEntity
import com.halo.assistant.fragment.WebFragment
import com.halo.assistant.member.MemberActivity
import com.therouter.router.Route
@Route(path = RouteConsts.activity.webActivity)
open class WebActivity : ToolBarActivity() {
@ -29,6 +31,8 @@ open class WebActivity : ToolBarActivity() {
val mIsBackpressRequireConfirmation =
bundle.getBoolean(WebFragment.KEY_REQUIRE_BACK_CONFIRMATION, false)
mIsFullScreen = !TextUtils.isEmpty(mGameName) && mIsBackpressRequireConfirmation
mIsFullScreen = true
if (mIsFullScreen) {
setTheme(R.style.AppFullScreenTheme)
}
@ -305,5 +309,17 @@ open class WebActivity : ToolBarActivity() {
intent.putExtra(NORMAL_FRAGMENT_BUNDLE, bundle)
return intent
}
@JvmStatic
fun getMyAssetsIntent(context: Context): Intent {
val intent = Intent(context, MemberActivity::class.java)
val url = if (EnvHelper.isDevEnv) {
Constants.MY_ASSETS_DEV
} else {
Constants.MY_ASSETS
}
intent.putExtra(EntranceConsts.KEY_URL, url)
return intent
}
}
}

View File

@ -4,8 +4,11 @@ import android.content.Context
import android.content.Intent
import android.text.TextUtils
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.Group
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import com.airbnb.lottie.LottieAnimationView
@ -13,6 +16,7 @@ import com.gh.common.chain.*
import com.gh.common.constant.Config
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.dialog.GameOffServiceDialogFragment
import com.gh.common.dialog.PackageCheckDialogFragment
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.history.HistoryHelper
import com.gh.common.simulator.NewSimulatorGameManager
@ -45,6 +49,7 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.feature.view.DownloadButton.ButtonStyle
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.teenagermode.TeenagerModeActivity.Companion.getIntent
import com.gh.vspace.VHelper
@ -62,7 +67,8 @@ class DetailViewHolder(
name: String?,
title: String?,
val traceEvent: ExposureEvent?,
val isSupportDualButton: Boolean = false // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示
val isSupportDualButton: Boolean = false, // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示,
val acceleratorUiHelper: GameDetailAcceleratorUiHelper? = null // 网速加速,只有游戏详情才有
) {
var context: Context
var downloadBottom: View
@ -90,6 +96,12 @@ class DetailViewHolder(
// 多版本下载文字
var multiVersionDownloadTv: TextView?
// 加速按钮
val speedContainer: ConstraintLayout?
private val ivFreeVipTag: ImageView?
private val gMoreZone: Group?
// 注意 View 的命名
init {
downloadBottom = view.findViewById(R.id.detail_ll_bottom)
@ -104,6 +116,10 @@ class DetailViewHolder(
localDownloadTitleTv = view.findViewById(R.id.localDownloadTitleTv)
localDownloadButton = view.findViewById(R.id.localDownloadButton)
speedContainer = view.findViewById(R.id.cl_speed_container)
ivFreeVipTag = view.findViewById(R.id.iv_free_vip_tag)
gMoreZone = view.findViewById(R.id.g_more_zone)
context = view.context
var gameDownloadMode = gameEntity.getGameDownloadButtonMode()
@ -158,7 +174,9 @@ class DetailViewHolder(
localDownloadButton?.putObject(gameEntity)
localDownloadButton?.setTag(
com.gh.gamecenter.feature.R.string.download, context.getString(
com.gh.gamecenter.feature.R.string.download_local))
com.gh.gamecenter.feature.R.string.download_local
)
)
}
}
downloadPb.putWidgetBusinessName("游戏详情页")
@ -176,6 +194,19 @@ class DetailViewHolder(
gamePermissionDialogFragment?.dismissAllowingStateLoss()
}
fun hideSpeedUi() {
acceleratorUiHelper?.showSpeedUi = false
}
fun showAcceleratorGuideLayer() {
acceleratorUiHelper?.checkIfShowGuideLayer(context)
}
fun setSpeedViewsVisible(isVisible: Boolean) {
ivFreeVipTag?.goneIf(!isVisible)
speedContainer?.goneIf(!isVisible)
}
internal class OnDetailDownloadClickListener(
private val mViewHolder: DetailViewHolder,
private val mEntrance: String?,
@ -194,6 +225,10 @@ class DetailViewHolder(
if (mGameEntity.isLandPageAddressDialog() && !mGameEntity.isLandPageAddressDialogShowOnly()) {
// 第三方落地页为开启状态并且展示状态不为“仅显示弹窗”,需要在点击确认后显示弹窗
DialogUtils.showLandPageAddressDialog(mViewHolder.context, mGameEntity) {
val packageName = mGameEntity.getApk().firstOrNull()?.packageName
if (packageName?.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(mViewHolder.context, mGameEntity.landPageAddressDialog!!.link!!)
}
}
@ -271,14 +306,20 @@ class DetailViewHolder(
ButtonStyle.NONE_WITH_HINT, ButtonStyle.NONE -> {
val offStatus = mGameEntity.downloadOffStatus
if (offStatus != null && "off" != offStatus) {
if ("dialog" == offStatus) {
showOffServiceDialog(mGameEntity.downloadOffDialog) {
when (offStatus) {
"dialog" -> {
showOffServiceDialog(mGameEntity.downloadOffDialog) {
showLandPageAddressDialogIfNeeded()
}
}
"toast" -> {
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
ToastUtils.toast("该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~")
showLandPageAddressDialogIfNeeded()
}
"third_party" -> {
showLandPageAddressDialogIfNeeded()
}
} else if ("toast" == offStatus) {
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
ToastUtils.toast("该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~")
showLandPageAddressDialogIfNeeded()
}
} else {
ToastUtils.toast("该游戏已关闭下载")
@ -324,7 +365,19 @@ class DetailViewHolder(
if (mAsVGame) {
VHelper.installOrLaunch(mViewHolder.context, mGameEntity, null)
} else {
PackageLauncher.launchApp(mViewHolder.context, mGameEntity, mGameEntity.getUniquePackageName())
// 如果游戏配置了加速,则启动时需要进行包名检测
if (mGameEntity.canSpeed) {
PackageCheckDialogFragment.show(mViewHolder.context as AppCompatActivity, mGameEntity) {
PackageLauncher.launchApp(
mViewHolder.context, mGameEntity, mGameEntity.getUniquePackageName()
)
}
} else {
PackageLauncher.launchApp(
mViewHolder.context, mGameEntity, mGameEntity.getUniquePackageName()
)
}
}
} else {
GamePermissionDialogFragment.show(
@ -455,17 +508,9 @@ class DetailViewHolder(
}
ButtonStyle.RESERVED -> {
if ("download" == mGameEntity.reserveStatus) {
ReservationHelper.showDeleteReservationDialog(mViewHolder.context) {
ReservationHelper.deleteReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
}
}
} else {
ReservationHelper.showCancelReservationDialog(mViewHolder.context, mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
}
ReservationHelper.showCancelReservationDialog(mViewHolder.context, mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
}
}
}
@ -592,8 +637,9 @@ class DetailViewHolder(
val apkEntity = mGameEntity.getApk().firstOrNull()
val msg = FileUtils.isCanDownload(mViewHolder.context, apkEntity?.size ?: "")
if (TextUtils.isEmpty(msg)) {
val btnContainsUpdateText = mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update_v) == buttonText
|| buttonText.contains(mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update))
val btnContainsUpdateText =
mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update_v) == buttonText
|| buttonText.contains(mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update))
if (asVGame && btnContainsUpdateText) {
VHelper.updateOrReDownload(mGameEntity)

View File

@ -1,11 +1,14 @@
package com.gh.gamecenter.authorization
import android.app.Dialog
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.UserHandle
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.DialogUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
@ -16,6 +19,7 @@ import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ActivityAuthorizationBinding
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.vspace.VHelper
import com.lightgame.utils.Utils
@ -68,6 +72,13 @@ class AuthorizationActivity : ToolBarActivity() {
//授权token
private var mToken = ""
/**
* 游戏UID (适配双开/分身游戏)
*/
private var gameUid = -1
private var loadingDialog: Dialog? = null
override fun getLayoutId(): Int {
return R.layout.activity_authorization
}
@ -80,11 +91,16 @@ class AuthorizationActivity : ToolBarActivity() {
mBinding = ActivityAuthorizationBinding.bind(mContentView)
checkParam()
initView()
mBinding.authorizeBtn.postDelayed({
mBaseHandler.post {
if (loadingDialog == null) {
loadingDialog = DialogUtils.showWaitDialog(this, "请稍后...")
}
}
UserRepository.getInstance().loginUserInfo.observe(this) {
checkLogin {
initUserInfo()
}
}, 500)
}
NewFlatLogUtils.logLoginFromGHZSShow(
gameId = gameId,
gameName = gameName
@ -97,14 +113,21 @@ class AuthorizationActivity : ToolBarActivity() {
}
private fun initData() {
if (mToken.isNotEmpty() || isFinishing) return
val loadingDialog = DialogUtils.showWaitDialog(this, "请稍后...")
if (mToken.isNotEmpty() || isFinishing) {
loadingDialog?.dismiss()
return
}
if (loadingDialog == null) {
loadingDialog = DialogUtils.showWaitDialog(this, "请稍后...")
} else if (loadingDialog?.isShowing == false) {
loadingDialog?.show()
}
mViewModel.getAccessToken(listOf(mContent), {
mToken = it
loadingDialog.dismiss()
loadingDialog?.dismiss()
}, {
toast("获取token失败")
loadingDialog.dismiss()
loadingDialog?.dismiss()
})
}
@ -143,6 +166,7 @@ class AuthorizationActivity : ToolBarActivity() {
mContent = uri.getQueryParameter(EntranceConsts.KEY_CONTENT) ?: ""
gameId = uri.getQueryParameter(EntranceConsts.KEY_GAME_ID) ?: ""
gameName = uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME) ?: ""
gameUid = uri.getQueryParameter(EntranceConsts.KEY_UID)?.toIntOrNull() ?: -1
if (mRemotePkgName == null) {
finish()
return
@ -152,8 +176,8 @@ class AuthorizationActivity : ToolBarActivity() {
private fun initView() {
//通过包名获取app图标和名称
val pkgName = mRemotePkgName ?: return
val icon = packageManager.getApplicationIcon(pkgName)
val name = packageManager.getApplicationLabel(packageManager.getApplicationInfo(pkgName, 0))
val icon = PackageUtils.getIconByPackageName(this, pkgName)
val name = PackageUtils.getNameByPackageName(this, pkgName)
mBinding.authorizeAppIcon.setImageDrawable(icon)
mBinding.authorizeAppName.text = name
mBinding.authorizeBtn.setOnClickListener {
@ -217,7 +241,11 @@ class AuthorizationActivity : ToolBarActivity() {
intent.putExtra(EntranceConsts.KEY_USER_ID, userId)
intent.putExtra(EntranceConsts.KEY_USER_NAME, username)
intent.putExtra(EntranceConsts.KEY_USER_AVATAR, userAvatar)
sendBroadcast(intent)
if (gameUid != -1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(gameUid))
} else {
sendBroadcast(intent)
}
logAuthResult(true)
backToLaunchApp()
finish()
@ -242,10 +270,10 @@ class AuthorizationActivity : ToolBarActivity() {
VHelper.launch(this, gamePkg, ignoreGApps = true, showLoading = showLoading)
return
}
val remotePkgName = this.mRemotePkgName
if (remotePkgName != null) {// 跳转回其他授权app
startActivity(packageManager.getLaunchIntentForPackage(remotePkgName))
}
// val remotePkgName = this.mRemotePkgName
// if (remotePkgName != null) {// 跳转回其他授权app
// startActivity(packageManager.getLaunchIntentForPackage(remotePkgName))
// }
}
override fun onBackPressed() {

View File

@ -132,6 +132,13 @@ class GamesCollectionAdapter(
)
mExposureEventArray?.put(position, exposureEvent)
val path = when (mViewModel.type) {
GamesCollectionFragment.TYPE_COLLECT -> "我的收藏-游戏单"
GamesCollectionFragment.TYPE_HISTORY -> "浏览记录-游戏单"
GamesCollectionFragment.TYPE_USER -> "个人主页-游戏单"
else -> ""
}
holder.binding.run {
ImageUtils.display(poster, itemEntity.cover)
nameTv.text = itemEntity.title
@ -249,12 +256,6 @@ class GamesCollectionAdapter(
}
userIcon.setOnClickListener {
val path = when (mViewModel.type) {
GamesCollectionFragment.TYPE_COLLECT -> "我的收藏-游戏单"
GamesCollectionFragment.TYPE_HISTORY -> "浏览记录-游戏单"
GamesCollectionFragment.TYPE_USER -> "个人主页-游戏单"
else -> ""
}
DirectUtils.directToHomeActivity(mContext, itemEntity.user?.id, "", path)
}
userName.setOnClickListener { userIcon.performClick() }
@ -266,7 +267,8 @@ class GamesCollectionAdapter(
mContext,
itemEntity.id,
isScrollToCommentArea = true,
exposureSourceList = ArrayList(exposureEvent.source)
exposureSourceList = ArrayList(exposureEvent.source),
entrance = path
)
)
}
@ -329,7 +331,8 @@ class GamesCollectionAdapter(
GameCollectionDetailActivity.getIntent(
mContext,
itemEntity.id,
exposureSourceList = ArrayList(exposureEvent.source)
exposureSourceList = ArrayList(exposureEvent.source),
entrance = path
)
)
} else {

View File

@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageChangeHelper
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageLauncher
import com.gh.download.DownloadManager
@ -398,6 +399,10 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
if (update.isLandPageAddressDialogShowOnly()) {
updateOrPluggable(updateBtn, update, downloadEntity, pluginDesc)
} else {
val packageName = update.packageName
if (packageName.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(it.context, update.landPageAddressDialog!!.link!!)
}
}

View File

@ -0,0 +1,16 @@
package com.gh.gamecenter.entity
import com.gh.gamecenter.feature.entity.SimpleGame
import com.google.gson.annotations.SerializedName
class GameServerTestTopGame(
@SerializedName("_id")
var id: String = "",
var game: SimpleGame? = null,
@SerializedName("column_test_v2_icon")
var icon: String = "",
@SerializedName("event_description")
var description: String = "",
@SerializedName("event_date")
var date: String = ""
)

View File

@ -18,7 +18,13 @@ data class SearchSubjectEntity(
@SerializedName("ad_icon_active")
val adIconActive: Boolean = false,
// 本地字段标记是否为微信小游戏CPM专题
var isWGameSubjectCPM: Boolean = false
var isWGameSubjectCPM: Boolean = false,
val type: String = ""
) : Parcelable {
companion object {
const val TYPE_WECHAT_GAME_CPM_COLUMN = "wechat_game_cpm_column"
}
fun getFilterGame() = RegionSettingHelper.filterGame(games)
}

View File

@ -288,7 +288,8 @@ class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumConte
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
contentId ?: "",
title ?: ""
title ?: "",
sequence
)
NewFlatLogUtils.logSearchContentClick(

View File

@ -39,8 +39,8 @@ class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() {
override fun initView() {
mBinding = FragmentSearchDefaultBinding.bind(mCachedView)
mBinding.hotTagHeadContainer.root.visibility = View.GONE
mBinding.hotTagFlexContainer.visibility = View.GONE
mBinding.hotAndDiscoveryTagHeadContainer.root.visibility = View.GONE
mBinding.hotAndDiscoveryTagFlexContainer.visibility = View.GONE
if (mEntrance == "论坛首页" || mEntrance == "搜索栏") {
mBinding.hotHeadContainer.headTitle.text = "热门论坛"
mViewModel.getForumSearchHotContent()

View File

@ -40,7 +40,8 @@ class UserSearchListFragment : LazyListFragment<FollowersOrFansEntity, UserSearc
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
mListViewModel.sourceEntrance,
userId
userId,
position
)
NewFlatLogUtils.logSearchUserClick(
SearchType.fromString(mSearchType).toChinese(),

View File

@ -4,14 +4,18 @@ import android.os.Bundle
import android.view.View
import androidx.lifecycle.ViewModelProviders
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.EntranceConsts.KEY_SHOW_SUBJECT_TAB
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.databinding.FragmentColumnCollectionDetailBinding
import com.gh.gamecenter.entity.GameColumnCollection
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.subject.tab.SubjectTabFragment
@ -55,11 +59,37 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
mListViewModel.getGameColumnCollection()
mListViewModel.columnCollection.observeNonNull(this) {
setNavigationTitle(it.name)
mCachedView?.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
logPageShow(it)
}
}
private fun logPageShow(entity: GameColumnCollection) {
val tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
val bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
mBaseHandler.postDelayed({
SensorsBridge.trackEvent("ColumnCollectionDetailPageShow", json {
"column_collection_name" to entity.name
"column_collection_id" to entity.id
"page_name" to GlobalActivityManager.getCurrentPageEntity().pageName
"page_id" to GlobalActivityManager.getCurrentPageEntity().pageId
"page_business_id" to GlobalActivityManager.getCurrentPageEntity().pageBusinessId
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
"last_page_business_id" to GlobalActivityManager.getLastPageEntity().pageBusinessId
"bottom_tab" to bottomTabName
"several_tab_page_name" to multiTabNavName
"several_tab_page_id" to multiTabNavId
"position" to tabIndex
"tab_content" to tabName
"source_entrance" to mEntrance
})
}, 3000L)
}
override fun onChanged(list: MutableList<LinkEntity>?) {
if (list != null && list.isNotEmpty()) {
showSubjectTab(list)

View File

@ -11,18 +11,22 @@ import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.IExposable
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.FixGridLayoutManager
import com.gh.gamecenter.common.view.GridSpacingItemDecoration
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.databinding.FragmentListBaseSkeletonBinding
import com.gh.gamecenter.entity.CommonCollectionEntity
import com.gh.gamecenter.home.custom.model.CustomPageItem
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_SLIDE_BANNER
@ -120,6 +124,8 @@ class CustomCommonCollectionDetailFragment : LazyListFragment<LinkEntity, Custom
}
mListRv?.removeItemDecorationAt(0)
mListRv?.addItemDecoration(itemDecoration)
logPageShow(it)
}
mListViewModel.loadExceptionLiveData.observe(viewLifecycleOwner) {
if (it != null && it.code() == 404) {
@ -154,6 +160,32 @@ class CustomCommonCollectionDetailFragment : LazyListFragment<LinkEntity, Custom
})
}
private fun logPageShow(entity: CommonCollectionEntity) {
val tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
val bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
mBaseHandler.postDelayed({
SensorsBridge.trackEvent("LinkContentCollectionDetailPageShow", json {
"link_content_collection_name" to entity.name
"link_content_collection_id" to entity.id
"page_name" to GlobalActivityManager.getCurrentPageEntity().pageName
"page_id" to GlobalActivityManager.getCurrentPageEntity().pageId
"page_business_id" to GlobalActivityManager.getCurrentPageEntity().pageBusinessId
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
"last_page_business_id" to GlobalActivityManager.getLastPageEntity().pageBusinessId
"bottom_tab" to bottomTabName
"several_tab_page_name" to multiTabNavName
"several_tab_page_id" to multiTabNavId
"position" to tabIndex
"tab_content" to tabName
"source_entrance" to mEntrance
})
}, 3000L)
}
override fun getItemDecoration(): RecyclerView.ItemDecoration =
when (mCollectionStyle) {
"1-2" ->

View File

@ -49,21 +49,24 @@ class GameCollectionDetailActivity : ToolBarActivity() {
fun getIntent(
context: Context,
gameCollectionId: String,
isFromSquare: Boolean = false
isFromSquare: Boolean = false,
entrance: String = ""
): Intent {
return getIntent(context, gameCollectionId, "", isFromSquare, false)
return getIntent(context, gameCollectionId, "", isFromSquare, false, entrance = entrance)
}
@JvmStatic
fun getSpecifiedCommentIntent(
context: Context,
gameCollectionId: String,
topCommentId: String
topCommentId: String,
entrance: String
): Intent {
return getIntent(
context, gameCollectionId, topCommentId,
isFromSquare = false,
isScrollToCommentArea = true
isScrollToCommentArea = true,
entrance = entrance
)
}
@ -74,13 +77,15 @@ class GameCollectionDetailActivity : ToolBarActivity() {
topCommentId: String = "",
isFromSquare: Boolean = false,
isScrollToCommentArea: Boolean = false,
exposureSourceList: ArrayList<ExposureSource>? = null
exposureSourceList: ArrayList<ExposureSource>? = null,
entrance: String = ""
): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_GAME_COLLECTION_ID, gameCollectionId)
bundle.putString(EntranceConsts.KEY_TOP_COMMENT_ID, topCommentId)
bundle.putBoolean(EntranceConsts.KEY_IS_FROM_SQUARE, isFromSquare)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_COMMENT_AREA, isScrollToCommentArea)
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
if (exposureSourceList != null) {
bundle.putParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST, exposureSourceList)
}

View File

@ -851,6 +851,7 @@ class GameCollectionDetailFragment :
trackEvent.put("game_collect_title", mGameCollectionTitle)
trackEvent.put("game_collect_id", mGameCollectionId)
trackEvent.put("stay_length", mElapsedHelper?.elapsedTime)
trackEvent.put("source_entrance", mEntrance)
} catch (e: JSONException) {
e.printStackTrace()
}

View File

@ -6,6 +6,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.exposure.ExposureSource
@ -58,6 +59,7 @@ class GameCollectionHotListFragment : ListFragment<GameCollectionListItemData, G
if (requireActivity() is GameCollectionListDetailActivity) {
mBasicExposureSourceList.add(ExposureSource("游戏单合集", mGameCollectionListEntity?.id ?: ""))
mBasicExposureSourceList.add(ExposureSource("合集详情", ""))
logPageShow()
} else {
mBasicExposureSourceList.add(ExposureSource("游戏单热榜", ""))
mBasicExposureSourceList.add(ExposureSource("游戏单合集", mGameCollectionListEntity?.id ?: ""))
@ -68,6 +70,32 @@ class GameCollectionHotListFragment : ListFragment<GameCollectionListItemData, G
}
}
private fun logPageShow() {
val tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
val bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
mBaseHandler.postDelayed({
SensorsBridge.trackEvent("GameListCollectionDetailPageShow", json {
"game_list_collection_name" to mGameCollectionListEntity?.name
"game_list_collection_id" to mGameCollectionListEntity?.id
"page_name" to GlobalActivityManager.getCurrentPageEntity().pageName
"page_id" to GlobalActivityManager.getCurrentPageEntity().pageId
"page_business_id" to GlobalActivityManager.getCurrentPageEntity().pageBusinessId
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
"last_page_business_id" to GlobalActivityManager.getLastPageEntity().pageBusinessId
"bottom_tab" to bottomTabName
"several_tab_page_name" to multiTabNavName
"several_tab_page_id" to multiTabNavId
"position" to tabIndex
"tab_content" to tabName
"source_entrance" to mEntrance
})
}, 3000L)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (mListRefresh != null) {
mListRefresh!!.setColorSchemeResources(com.gh.gamecenter.common.R.color.primary_theme)

View File

@ -76,7 +76,8 @@ class MyGameCollectionViewHolder(
binding.root.context.startActivity(
GameCollectionDetailActivity.getIntent(
binding.root.context,
entity.id
entity.id,
entrance = path
)
)
} else {

View File

@ -11,6 +11,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.gh.common.provider.CropImageProviderImpl.Companion.IMAGE_TYPE_GAME_COLLECTION_COVER
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.common.util.NewLogUtils
@ -45,7 +46,8 @@ class ChooseGameCollectionCoverTypeDialog : BaseDialogFragment() {
requireContext(),
ChooseType.IMAGE,
1,
"创建游戏单"
"创建游戏单",
IMAGE_TYPE_GAME_COLLECTION_COVER
), REQUEST_CODE_IMAGE
)
}
@ -101,7 +103,8 @@ class ChooseGameCollectionCoverTypeDialog : BaseDialogFragment() {
com.gh.gamecenter.common.R.drawable.bg_choose_option_selector.toDrawable(requireContext())
defaultUploadContainer.background =
com.gh.gamecenter.common.R.drawable.bg_choose_option_selector.toDrawable(requireContext())
cancelBtn.background = com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_999.toDrawable(requireContext())
cancelBtn.background =
com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_999.toDrawable(requireContext())
recommentTv.background = R.drawable.bg_game_collection_cover_tag.toDrawable(requireContext())
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(requireContext()))
localUploadTitleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))

View File

@ -313,14 +313,14 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
val games = mChooseGamesViewModel.chooseGamesLiveData.value ?: arrayListOf()
if (mIsCreateGameCollection) {
SensorsBridge.trackEvent("GameCollectCreateSuccess", json {
"game_collect_status" to if(mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_collect_status" to if (mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_num" to games.size
"game_collect_title" to mBinding.gameCollectionTitleEt.text.toString().trim()
"game_collect_id" to it.data as String
})
} else if (mViewModel.gameCollectionPatch != null) {
SensorsBridge.trackEvent("GameCollectEditSuccess", json {
"game_collect_status" to if(mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_collect_status" to if (mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_num" to games.size
"game_collect_title" to mBinding.gameCollectionTitleEt.text.toString().trim()
"game_collect_id" to mViewModel.gameCollectionPatch?.id
@ -355,7 +355,7 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
CheckLoginUtils.checkLogin(this, mEntrance) {}
return@observe
}
ErrorHelper.handleError(this, errorMsg, false, "发布游戏单", "社区实名") {
ErrorHelper.handleError(this, errorMsg, false, "发布游戏单", "社区实名") {
if (::mMenuPost.isInitialized) {
onMenuItemClick(mMenuPost)
}
@ -433,18 +433,6 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
when (requestCode) {
REQUEST_CODE_IMAGE_CROP -> {
val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) ?: ""
mViewModel.imageUrl = ""
mViewModel.imagePath = imagePath
if (imagePath.isEmpty()) {
mBinding.uploadPictureTv.text = "点击上传图片"
} else {
mBinding.uploadPictureTv.text = "图片上传中..."
mViewModel.uploadPoster()
}
initPosterUI()
}
REQUEST_CHOOSE_TAG -> {
val tags = data.getParcelableArrayListExtra<TagInfoEntity>(GameCollectionTagSelectFragment.SELECTED_TAG)
?: arrayListOf()
@ -457,20 +445,16 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
fun onActivityDialogResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {
if (requestCode == REQUEST_CODE_IMAGE) {
val selectedPaths = Matisse.obtainResult(data)
if (!selectedPaths.isNullOrEmpty()) {
val path = PathUtils.getPath(this, selectedPaths[0])
val intent =
CropImageActivity.getIntent(
this,
path,
142 / 328F,
false,
R.layout.layout_game_collection_crop_image_assist,
mEntrance
)
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) ?: ""
mViewModel.imageUrl = ""
mViewModel.imagePath = imagePath
if (imagePath.isEmpty()) {
mBinding.uploadPictureTv.text = "点击上传图片"
} else {
mBinding.uploadPictureTv.text = "图片上传中..."
mViewModel.uploadPoster()
}
initPosterUI()
} else if (requestCode == ChooseGameCollectionDefaultCoverDialog.REQUEST_CODE_DEFAULT_IMAGE) {
val entity = data.getParcelableExtra<GameCollectionCoverEntity>(EntranceConsts.KEY_DATA)
if (entity != null) {
@ -731,9 +715,17 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
} else {
DialogHelper.showDialog(this, "温馨提示", "游戏单会在1-2个工作日内审核完成您可以在“我的光环-我的游戏单”查看进度", "继续提交", "取消", {
mViewModel.uploadContent(this, requestMap)
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
DialogHelper.showDialog(
this,
"温馨提示",
"游戏单会在1-2个工作日内审核完成您可以在“我的光环-我的游戏单”查看进度",
"继续提交",
"取消",
{
mViewModel.uploadContent(this, requestMap)
},
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
}
}
}
@ -804,7 +796,8 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
activityDivider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(this@GameCollectionEditActivity))
titleDivider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(this@GameCollectionEditActivity))
introduceDivider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(this@GameCollectionEditActivity))
placeholderView.background = com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_8.toDrawable(this@GameCollectionEditActivity)
placeholderView.background =
com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_8.toDrawable(this@GameCollectionEditActivity)
selfOnlyCb.background =
R.drawable.border_round_stroke_0dot5_eee_999.toDrawable(this@GameCollectionEditActivity)
uploadPictureTv.setTextColor(com.gh.gamecenter.common.R.color.text_instance.toColor(this@GameCollectionEditActivity))
@ -912,7 +905,6 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
companion object {
const val REQUEST_CODE_IMAGE = 100
const val REQUEST_CODE_IMAGE_CROP = 101
const val REQUEST_CHOOSE_GAMES = 102
const val REQUEST_CHOOSE_TAG = 103
const val REQUEST_CHOOSE_ACTIVITY = 105

View File

@ -596,7 +596,8 @@ class GameCollectionSquareAdapter(
context,
gamesCollectionEntity.id,
isFromSquare = true,
exposureSourceList = ArrayList(exposureSource)
exposureSourceList = ArrayList(exposureSource),
entrance = "游戏单广场"
)
)
}

View File

@ -209,7 +209,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (data == null || resultCode != Activity.RESULT_OK || !::mViewModel.isInitialized) return
if (requestCode == REQUEST_SELECT_TAG) {
val tagInfoEntity = data.getParcelableExtra<TagInfoEntity>(GameCollectionTagSelectFragment.SELECTED_TAG)
val tagCategory = data.getStringExtra(GameCollectionTagSelectFragment.SELECTED_TAG_CATEGORY)

View File

@ -0,0 +1,13 @@
package com.gh.gamecenter.gamedetail
import androidx.lifecycle.ViewModel
import com.halo.assistant.member.MemberUseCase
class AcceleratorZoneViewModel : ViewModel() {
val useCase = MemberUseCase()
override fun onCleared() {
useCase.onClear()
}
}

View File

@ -58,20 +58,20 @@ import com.gh.gamecenter.common.mvvm.Status
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.WrapContentDraweeView
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.RecommendPopupEntity
import com.gh.gamecenter.eventbus.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.entity.SimpleGame
import com.gh.gamecenter.feature.entity.TagStyleEntity
import com.gh.gamecenter.feature.entity.*
import com.gh.gamecenter.feature.eventbus.EBConcernChanged
import com.gh.gamecenter.feature.eventbus.EBPayState
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.feature.utils.SentryHelper
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper
import com.gh.gamecenter.gamedetail.cloudarchive.CloudArchiveFragment
import com.gh.gamecenter.gamedetail.desc.DescFragment
import com.gh.gamecenter.gamedetail.dialog.*
@ -86,7 +86,6 @@ import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.login.user.UserViewModel
import com.gh.gamecenter.newsdetail.NewsDetailActivity
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.simulatorgame.SimulatorGameActivity
import com.gh.gamecenter.tag.TagsActivity
import com.gh.gamecenter.video.detail.CustomManager
@ -101,6 +100,7 @@ import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import com.therouter.TheRouter
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -155,6 +155,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
private val mLooperHandle = LooperHandle(this)
private val mServerLooperKey = 123
private lateinit var acceleratorUiHelper: GameDetailAcceleratorUiHelper
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.gameId == mViewModel.gameId) {
@ -265,7 +267,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
name = "游戏详情",
title = mGameEntity!!.name ?: "",
traceEvent = mTraceEvent,
isSupportDualButton = true
isSupportDualButton = true,
acceleratorUiHelper
)
private val contentCardClick: (contentCard: ContentCardEntity, position: Int) -> Unit =
@ -412,6 +415,7 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
mVideoBinding = mBodyBinding.gameDetailVideo
mDownloadBinding = mBinding.detailLlBottom
mRecommendBinding = mBinding.gameDetailRecommendView
acceleratorUiHelper = GameDetailAcceleratorUiHelper(mDownloadBinding)
}.root
}
@ -548,7 +552,12 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
pauseVideo()
mIsPauseTopVideo = true
}
mBodyBinding.toolbar.setTitleTextColor(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.black))
mBodyBinding.toolbar.setTitleTextColor(
ContextCompat.getColor(
requireContext(),
com.gh.gamecenter.common.R.color.black
)
)
} else if (mIsPauseTopVideo && absVerticalOffset == 0 && mVideoBinding.player.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
resumeVideo()
mIsPauseTopVideo = false
@ -669,7 +678,9 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
} else {
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
background = com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle.toDrawable(requireContext())
background = com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle.toDrawable(
requireContext()
)
}
}
tagView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
@ -768,6 +779,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
if (gameResource.status == Status.SUCCESS) {
mViewModel.logHistory(gameResource.data!!)
mGameEntity = gameResource.data
acceleratorUiHelper.setGame(gameResource.data)
loadAccelerationData(mGameEntity!!)
showBrowserInstallHintIfNeeded()
controlInstallHint()
// 添加启动弹窗的相关信息
@ -787,7 +800,9 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
mViewModel.gameDetailLiveData.observeNonNull(this) { detailResource ->
if (detailResource.status == Status.SUCCESS) {
val data = detailResource.data ?: return@observeNonNull
if (detailResource.data?.acceleratorStatus == true) {
acceleratorUiHelper.initSpeedUi(requireActivity())
}
DataLogUtils.uploadGameLog(context, mGameEntity!!.id, mGameEntity!!.name, mEntrance)
postDelayedRunnable({
@ -839,7 +854,12 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
DetailDownloadUtils.updateViewHolder(viewHolder)
mDestinationTab =
getTabPositionFromTabType(arguments?.getString(EntranceConsts.KEY_TARGET, EntranceConsts.TAB_TYPE_DESC) ?: EntranceConsts.TAB_TYPE_DESC)
getTabPositionFromTabType(
arguments?.getString(
EntranceConsts.KEY_TARGET,
EntranceConsts.TAB_TYPE_DESC
) ?: EntranceConsts.TAB_TYPE_DESC
)
// destinationTab 的优先级最高,关注和关联关注在它的后面
if (mDestinationTab != -1) {
@ -866,10 +886,11 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
showConcernIconAtBottomBarIfAvailable()
val downloadEntitySnapshot = DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity)
val downloadEntitySnapshot = DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity)
if (isSpecialDownloadDialogAvailable(downloadEntitySnapshot)
&& downloadEntitySnapshot != null) {
&& downloadEntitySnapshot != null
) {
updateSpecialDownloadDialogIcon(true)
}
@ -993,6 +1014,32 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
}
/**
* 调用此方法时只是能获取game的包名还无法确认该游戏是否支持加速
* 所以这里只是提前加载加速所需的数据并不需要初始化加速相关的UI
*/
private fun loadAccelerationData(game: GameEntity) {
game.getApk().size
if (game.getApk().size == 1) {
// 单版本游戏才能支持加速(后台未对此作限制,所以需要在客户端判断)
val pkgName = game.getUniquePackageName() ?: ""
mViewModel.getLastSpeedLiveData(pkgName).observe(viewLifecycleOwner) {
acceleratorUiHelper.setCurrentAcctGameInfo(it)
}
mViewModel.getZoneListLiveData(pkgName).observe(viewLifecycleOwner) {
acceleratorUiHelper.setZoneList(it)
}
mViewModel.upsertAcctZoneListBeanAction.observe(viewLifecycleOwner) { (pkgName, zoneList) ->
mViewModel.upsertAcctZoneListBean(pkgName, zoneList)
}
mViewModel.loadAccelerationData(pkgName)
}
}
@SuppressLint("ClickableViewAccessibility")
private fun initViewPage(data: NewGameDetailEntity) {
// 各个 tab 显示的顺序为:详情>云存档>评价>专区>论坛
@ -1031,7 +1078,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
mTabTitleList.clear()
val tag = "android:switcher:${mBodyBinding.gamedetailVp.id}:"
val descFragment = childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_DESC}") ?: DescFragment()
val descFragment =
childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_DESC}") ?: DescFragment()
descFragment.arguments = bundle
mFragmentsList.add(descFragment)
mTabTitleList.add(getString(R.string.game_detail_desc))
@ -1039,7 +1087,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
if (data.showArchive) {
val cloudArchiveFragment =
childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_ARCHIVE}") ?: CloudArchiveFragment()
childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_ARCHIVE}")
?: CloudArchiveFragment()
bundle.putParcelable(EntranceConsts.KEY_GAME, mGameEntity ?: GameEntity())
bundle.putString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, data.archiveTab.configUrl)
cloudArchiveFragment.arguments = bundle
@ -1055,7 +1104,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
if (data.showComment) {
val ratingFragment = childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_RATING}") ?: RatingFragment()
val ratingFragment =
childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_RATING}") ?: RatingFragment()
bundle.putBoolean(EntranceConsts.KEY_COMMENT_AS_DEFAULT_TAB, mSkipGameComment)
bundle.putBoolean(EntranceConsts.KEY_DIRECT_COMMENT, data.directComment)
ratingFragment.arguments = bundle
@ -1072,7 +1122,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
mFragmentsList.add(Fragment())
} else if (it.style == "link") {
//显示web页面
val webFragment = childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_TRENDS}") ?: WebFragment()
val webFragment =
childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_TRENDS}") ?: WebFragment()
val webBundle = Bundle()
webBundle.putString(EntranceConsts.KEY_ENTRANCE, "游戏专区")
webBundle.putString(EntranceConsts.KEY_URL, it.link)
@ -1080,7 +1131,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
webFragment.arguments = webBundle
mFragmentsList.add(webFragment)
} else {
val fuliFragment = childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_TRENDS}") ?: FuLiFragment()
val fuliFragment =
childFragmentManager.findFragmentByTag("${tag}${EntranceConsts.TAB_TYPE_TRENDS}") ?: FuLiFragment()
fuliFragment.arguments = bundle
mFragmentsList.add(fuliFragment)
}
@ -1180,7 +1232,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
private fun doShowAlertDialog(dialog: GameEntity.Dialog) {
SensorsBridge.trackEvent("GameDetailDialogShow",
SensorsBridge.trackEvent(
"GameDetailDialogShow",
"game_id", mGameEntity?.id ?: "",
"game_name", mGameEntity?.name ?: "",
"game_type", mGameEntity?.categoryChinese ?: ""
@ -1192,7 +1245,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
dialog.confirmButton.text.toString(),
dialog.closeButtonText,
{
SensorsBridge.trackEvent("GameDetailDialogClick",
SensorsBridge.trackEvent(
"GameDetailDialogClick",
"game_id", mGameEntity?.id ?: "",
"game_name", mGameEntity?.name ?: "",
"game_type", mGameEntity?.categoryChinese ?: "",
@ -1205,7 +1259,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
DirectUtils.directToLinkPage(requireContext(), dialog.confirmButton, mEntrance, "")
},
{
SensorsBridge.trackEvent("GameDetailDialogClick",
SensorsBridge.trackEvent(
"GameDetailDialogClick",
"game_id", mGameEntity?.id ?: "",
"game_name", mGameEntity?.name ?: "",
"game_type", mGameEntity?.categoryChinese ?: "",
@ -1213,7 +1268,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
)
},
{
SensorsBridge.trackEvent("GameDetailDialogClick",
SensorsBridge.trackEvent(
"GameDetailDialogClick",
"game_id", mGameEntity?.id ?: "",
"game_name", mGameEntity?.name ?: "",
"game_type", mGameEntity?.categoryChinese ?: "",
@ -1385,7 +1441,12 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
mNewGameDetailEntity?.event?.let {
mBodyBinding.gameBigEvent.visibility = View.VISIBLE
if (it.highLight) {
mBodyBinding.gameBigEvent.setTextColor(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.text_2A85FB))
mBodyBinding.gameBigEvent.setTextColor(
ContextCompat.getColor(
requireContext(),
com.gh.gamecenter.common.R.color.text_2A85FB
)
)
mBodyBinding.gameBigEvent.background =
ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event_light)
mBodyBinding.gameBigEvent.setCompoundDrawablesWithIntrinsicBounds(
@ -1852,22 +1913,12 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
requireContext(),
mGameEntity,
callback = getCallback(),
)
)
} else {
if ("download" == mGameEntity?.reserveStatus) {
ReservationHelper.showDeleteReservationDialog(requireContext()) {
ReservationHelper.deleteReservation(mGameEntity!!) {
DetailDownloadUtils.updateViewHolder(detailViewHolder)
showReserveBtn(isShowReserveBtn())
}
}
} else {
ReservationHelper.showCancelReservationDialog(requireContext(), mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity!!) {
DetailDownloadUtils.updateViewHolder(detailViewHolder)
showReserveBtn(isShowReserveBtn())
}
ReservationHelper.showCancelReservationDialog(requireContext(), mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity!!) {
DetailDownloadUtils.updateViewHolder(detailViewHolder)
showReserveBtn(isShowReserveBtn())
}
}
}
@ -2222,7 +2273,8 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
pluginLocation = PluginLocation.only_game
)
val isLaunch = (status == getString(com.gh.gamecenter.feature.R.string.launch) || status == getString(
com.gh.gamecenter.feature.R.string.open))
com.gh.gamecenter.feature.R.string.open
))
if (SPUtils.getBoolean(
Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE,
false
@ -2382,6 +2434,9 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
override fun onBackPressed(): Boolean {
if (acceleratorUiHelper.onBack()) {
return true
}
mOrientationUtils?.backToProtVideo()
val trendsTabPosition = getTabPositionFromTabType(EntranceConsts.TAB_TYPE_TRENDS)
@ -2442,6 +2497,11 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
NewFlatLogUtils.logGameDetailExit(mGameEntity?.name ?: "", mGameEntity?.id ?: "")
}
override fun onDestroyView() {
acceleratorUiHelper.clear()
super.onDestroyView()
}
override fun onDestroy() {
super.onDestroy()
releaseVideo()
@ -2535,9 +2595,21 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
// 更新分割线样式
updateDivider()
mBodyBinding.collapsingToolbar.setContentScrimColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
mBodyBinding.gamedetailAppbar.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
mBodyBinding.toolbarGapView.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
mBodyBinding.collapsingToolbar.setContentScrimColor(
com.gh.gamecenter.common.R.color.ui_surface.toColor(
requireContext()
)
)
mBodyBinding.gamedetailAppbar.setBackgroundColor(
com.gh.gamecenter.common.R.color.ui_surface.toColor(
requireContext()
)
)
mBodyBinding.toolbarGapView.setBackgroundColor(
com.gh.gamecenter.common.R.color.ui_background.toColor(
requireContext()
)
)
mBodyBinding.gamedetailTvName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
mBodyBinding.gameBigEvent.background = R.drawable.bg_game_big_event.toDrawable(requireContext())
mBodyBinding.gameBigEvent.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(requireContext()))
@ -2549,7 +2621,11 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
}
}
if (it is ImageView) {
if (mIsDarkModeOn) it.setColorFilter(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext())) else it.colorFilter =
if (mIsDarkModeOn) it.setColorFilter(
com.gh.gamecenter.common.R.color.text_primary.toColor(
requireContext()
)
) else it.colorFilter =
null
it.background = (it.background as GradientDrawable).apply {
setStroke(0.5F.dip2px(), Color.parseColor(if (mIsDarkModeOn) "#33FFFFFF" else "#CCCCCC"))
@ -2561,7 +2637,11 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
val textView = tab.customView?.findViewById(R.id.tab_title) as? TextView ?: break
TextViewCompat.setTextAppearance(textView, com.gh.gamecenter.common.R.style.TabLayoutTextAppearance)
}
mBinding.detailLlBottom.detailLlBottom.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
mBinding.detailLlBottom.detailLlBottom.setBackgroundColor(
com.gh.gamecenter.common.R.color.ui_background.toColor(
requireContext()
)
)
updateToolbarStyle(!mViewModel.displayTopVideo || mBodyBinding.gamedetailThumbSmall.visibility == View.VISIBLE)
mViewModel.gameDetailLiveData.value?.data?.let {
if (it.isShowContentCard(mGameEntity)) {
@ -2594,6 +2674,7 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
* 3. 当前游戏 APK 不为 1 个
* 4. 当前游戏类型不为畅玩
* 5. 当前游戏不是双下载时使用本地下载进行下载
* 6. 当前游戏配置了网络加速
*/
private fun isSpecialDownloadDialogAvailable(downloadEntity: DownloadEntity? = null): Boolean {
if (Config.getNewApiSettingsEntity()?.install?.questionTip?.linkEntity == null) return false
@ -2602,6 +2683,7 @@ class GameDetailFragment : BaseLazyFragment(), IScrollable {
if (downloadEntity?.asVGame() == true) return false
if (downloadEntity?.isSimulatorGame() == true) return false
if (downloadEntity?.isLocalDownloadInDualDownloadMode() == true) return false
if (mGameEntity?.canSpeed == true) return false
return true
}

View File

@ -5,14 +5,10 @@ import android.app.Application
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.*
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.history.HistoryHelper
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.feature.utils.ConcernUtils
import com.gh.common.util.LibaoUtils
import com.gh.common.util.PackageHelper
import com.gh.gamecenter.common.constant.Constants
@ -20,28 +16,53 @@ import com.gh.gamecenter.common.mvvm.Resource
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toArrayList
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.LibaoEntity
import com.gh.gamecenter.feature.entity.LibaoStatusEntity
import com.gh.gamecenter.feature.entity.SimpleGame
import com.gh.gamecenter.entity.RecommendPopupEntity
import com.gh.gamecenter.entity.UnifiedUserTrendEntity
import com.gh.gamecenter.feature.entity.*
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.feature.utils.ConcernUtils
import com.gh.gamecenter.feature.utils.ContentBlockedHelper
import com.gh.gamecenter.gamedetail.entity.*
import com.gh.gamecenter.gamedetail.accelerator.AccelerationDataBase
import com.gh.gamecenter.gamedetail.entity.BigEvent
import com.gh.gamecenter.gamedetail.entity.CustomColumn
import com.gh.gamecenter.gamedetail.entity.DetailEntity
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.halo.assistant.member.MemberUseCase
import com.therouter.TheRouter
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
import tv.danmaku.ijk.media.exo2.ExoSourceManager
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.collections.List
import kotlin.collections.arrayListOf
import kotlin.collections.find
import kotlin.collections.firstOrNull
import kotlin.collections.forEach
import kotlin.collections.forEachIndexed
import kotlin.collections.hashMapOf
import kotlin.collections.isNotEmpty
import kotlin.collections.isNullOrEmpty
import kotlin.collections.removeAll
import kotlin.collections.set
import kotlin.collections.sortByDescending
import kotlin.collections.withIndex
class GameDetailViewModel(
application: Application,
@ -69,6 +90,10 @@ class GameDetailViewModel(
var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
var displayTopVideo: Boolean = false
private val compositeDisposable = CompositeDisposable()
val memberUseCase = MemberUseCase()
init {
loadData()
}
@ -85,9 +110,17 @@ class GameDetailViewModel(
getGameDetailNew()
getRecommendPopup(game?.id ?: "")
}
gameId != null -> getGameDigest()
else -> gameLiveData.postValue(null)
}
val userId = UserManager.getInstance().userId
if (userId.isNotBlank()) {
// 如果是登录状态获取最新的vip状态
UserRepository.getInstance().refreshVipStatus(userId, false)
}
}
// 获取游戏摘要
@ -162,6 +195,11 @@ class GameDetailViewModel(
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<NewGameDetailEntity>() {
override fun onSuccess(data: NewGameDetailEntity) {
game?.acceleratorStatus = data.acceleratorStatus
if (game?.canSpeed == true) {
// 此游戏支持加速
pkgName.value = game?.getUniquePackageName() ?: ""
}
if (data.newNotice != null) {
// 存在new_notice字段时移除detail_tab里面type=notice的项并添加new_notice到detail_tab
var noticePosition = -1
@ -659,6 +697,66 @@ class GameDetailViewModel(
})
}
fun getLastSpeedLiveData(pkgName: String) =
AccelerationDataBase.instance.accelerationDao().findByPackageName(pkgName)
fun getZoneListLiveData(pkgName: String) =
AccelerationDataBase.instance.accelerationDao().findZoneListBeanByPkgName(pkgName)
.map {
it?.acctGameList?.toArrayList()
}
private val zoneList = MutableLiveData<List<AcctGameInfo>>()
private val pkgName = MutableLiveData<String>()
val upsertAcctZoneListBeanAction = MediatorLiveData<Pair<String, List<AcctGameInfo>>>().apply {
addSource(zoneList) {
val pkgNameValue = pkgName.value
if (!pkgNameValue.isNullOrBlank()) {
value = pkgNameValue to it
}
}
addSource(pkgName) {
val zoneListValue = zoneList.value
if (zoneListValue != null) {
value = it to zoneListValue
}
}
}
fun loadAccelerationData(pkgName: String) {
Single.create<ArrayList<AcctGameInfo>> { emitter ->
val iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
iAcceleratorProvider?.loadQyGameZoneData(pkgName) {
val zoneData = (it as List<AcctGameInfo>).toArrayList()
emitter.onSuccess(zoneData)
} ?: emitter.onSuccess(arrayListOf())
}.timeout(5, TimeUnit.SECONDS)
.doOnSuccess {
zoneList.value = it
}
.subscribe({}, {}).let(compositeDisposable::add)
}
/**
* 只有能够加速的游戏需要保存区服信息
*/
@SuppressLint("CheckResult")
fun upsertAcctZoneListBean(pkgName: String, zoneList: List<AcctGameInfo>) {
AccelerationDataBase.instance.accelerationDao()
.upsertAcctZoneListBean(AcctZoneListBean(pkgName, zoneList))
.compose(singleToMain())
.subscribe({}, {})
}
override fun onCleared() {
super.onCleared()
compositeDisposable.clear()
memberUseCase.onClear()
}
class Factory(
private val mApplication: Application,
private val gameId: String?,

View File

@ -0,0 +1,76 @@
package com.gh.gamecenter.gamedetail
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.feature.entity.BaseEntity
import com.gh.gamecenter.feature.entity.TrialEntity
import com.gh.gamecenter.feature.entity.VipEntity
import com.gh.gamecenter.livedata.Event
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.halo.assistant.member.MemberUseCase
import com.therouter.TheRouter
import io.reactivex.disposables.CompositeDisposable
class StartingAcceleratorViewModel : ViewModel() {
private val compositeDisposable = CompositeDisposable()
val useCase = MemberUseCase()
private val _restartingAcceleratorAction = MutableLiveData<Event<Boolean>>()
val restartingAcceleratorAction: LiveData<Event<Boolean>> = _restartingAcceleratorAction
fun loadAcceleratorToken() {
val userId = UserManager.getInstance().userId
if (userId.isNotBlank()) {
UserRepository.getInstance().setAcceleratorToken(userId) {
_restartingAcceleratorAction.value = Event(it)
}
}
}
private val _rechargeTrailResult = MutableLiveData<Event<Boolean>>()
val rechargeTrailResult: LiveData<Event<Boolean>> = _rechargeTrailResult
fun rechargeTrial() {
val userId = UserManager.getInstance().userId
useCase.rechargeTrial(userId)
.compose(singleToMain())
.subscribe(object : BiResponse<BaseEntity<TrialEntity>>() {
override fun onSuccess(data: BaseEntity<TrialEntity>) {
if (data.data?.result == true) {
// 刷新vip状态
// 这里先刷新内存数据再去刷新api数据
TheRouter.get(IAcceleratorProvider::class.java)?.setVipEntity(
VipEntity(
_vipStatus = true,
_isNewUser = false,
_isTryVip = true
)
)
refreshVipStatus(userId)
_rechargeTrailResult.value = Event(true)
} else {
_rechargeTrailResult.value = Event(false)
}
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
_rechargeTrailResult.value = Event(false)
}
}).let(compositeDisposable::add)
}
private fun refreshVipStatus(userId: String) {
UserRepository.getInstance().refreshVipStatus(userId, true)
}
override fun onCleared() {
super.onCleared()
compositeDisposable.clear()
}
}

View File

@ -0,0 +1,35 @@
package com.gh.gamecenter.gamedetail.accelerator
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.gh.gamecenter.feature.entity.AcctGameInfo
import com.gh.gamecenter.feature.entity.AcctZoneListBean
import com.gh.gamecenter.room.converter.AcctGameInfoConverter
import com.halo.assistant.HaloApp
@Database(
entities = [AcctGameInfo::class, AcctZoneListBean::class],
version = 1,
exportSchema = false
)
@TypeConverters(
AcctGameInfoConverter::class
)
abstract class AccelerationDataBase : RoomDatabase() {
abstract fun accelerationDao(): AcceleratorDao
companion object {
private const val DATABASE_NAME: String = "acceleration_db"
val instance: AccelerationDataBase by lazy { buildDatabase(HaloApp.getInstance().application) }
private fun buildDatabase(context: Context): AccelerationDataBase {
return Room.databaseBuilder(context, AccelerationDataBase::class.java, DATABASE_NAME)
.build()
}
}
}

View File

@ -0,0 +1,25 @@
package com.gh.gamecenter.gamedetail.accelerator
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Upsert
import com.gh.gamecenter.feature.entity.AcctGameInfo
import com.gh.gamecenter.feature.entity.AcctZoneListBean
import io.reactivex.Single
@Dao
interface AcceleratorDao {
@Upsert
fun upsertAcctGameInfo(gameInfo: AcctGameInfo): Single<Long>
@Query("SELECT * FROM AcctGameInfo WHERE accGamePkgName = :pkgName")
fun findByPackageName(pkgName: String): LiveData<AcctGameInfo?>
@Upsert
fun upsertAcctZoneListBean(acctZoneListBean: AcctZoneListBean): Single<Long>
@Query("SELECT * FROM AcctZoneListBean WHERE pkgName = :pkgName")
fun findZoneListBeanByPkgName(pkgName: String): LiveData<AcctZoneListBean?>
}

View File

@ -0,0 +1,182 @@
package com.gh.gamecenter.gamedetail.accelerator
import android.app.Activity
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.databinding.LayoutAcceleratorGuidePageBinding
class AcceleratorGuideView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
def: Int = 0
) : FrameLayout(context, attrs, def) {
private val binding: LayoutAcceleratorGuidePageBinding
private val rect = Rect()
private var _isShowing = false
val isShowing: Boolean
get() = _isShowing
private var isCanDismiss = false
private val guideBackgroundColor =
com.gh.gamecenter.common.R.color.black_alpha_60.toColor(context)
private val xfermode by lazy {
val mode = PorterDuff.Mode.CLEAR
PorterDuffXfermode(mode)
}
private val paint by lazy {
Paint().apply {
color = Color.YELLOW
isAntiAlias = true
isDither = true
}
}
private var onStartSpeed: (() -> Unit)? = null
init {
val inflater = LayoutInflater.from(context)
binding = LayoutAcceleratorGuidePageBinding.inflate(inflater, this, true)
binding.root.setOnClickListener {
// 点击透明区域消失
dismiss()
}
binding.clContainer.setOnClickListener {
//覆盖外部点击事件,点击此区域 guideView 不消失
}
binding.vIKnow.setOnClickListener {
dismiss()
}
binding.vSpeed.setOnClickListener {
dismiss()
onStartSpeed?.invoke()
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, left, top, right, bottom)
val bottom = rect.bottom
val top = bottom - binding.clContainer.height
val right = rect.right + BORDER_WIDTH.dip2px()
val left = right - binding.clContainer.width
binding.clContainer.layout(left, top, right, bottom)
}
override fun dispatchDraw(canvas: Canvas) {
val saveCount = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), paint)
paint.color = guideBackgroundColor
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
onDrawDecoration(canvas)
paint.xfermode = xfermode
canvas.drawRoundRect(
RectF(rect),
HIGH_LIGHT_RADIUS.dip2px().toFloat(),
HIGH_LIGHT_RADIUS.dip2px().toFloat(),
paint
)
paint.xfermode = null
canvas.restoreToCount(saveCount)
super.dispatchDraw(canvas)
}
private fun onDrawDecoration(canvas: Canvas) {
paint.color = com.gh.gamecenter.common.R.color.ui_surface.toColor(context)
val border = BORDER_WIDTH.dip2px()
val radius = HIGH_LIGHT_RADIUS.dip2px().toFloat()
val dRectF = RectF(
rect.left.toFloat() - border,
rect.top.toFloat() - border,
rect.right.toFloat() + border,
rect.bottom.toFloat() + border
)
canvas.drawRoundRect(dRectF, radius, radius, paint)
}
private fun setHighLightRect(newRect: Rect) {
rect.set(newRect)
binding.vSpeed.updateLayoutParams {
width = rect.width()
}
}
fun show(anchor: View, activity: Activity, block: () -> Unit) {
onStartSpeed = block
val newRect = getLocationInWindow(anchor)
val content = activity.window.decorView as ViewGroup
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
setHighLightRect(newRect)
content.addView(this)
setOnClickListener {
if (isCanDismiss) {
dismiss()
}
}
setOnClickListener {
}
_isShowing = true
isCanDismiss = false
AppExecutor.uiExecutor.executeWithDelay({
isCanDismiss = true
}, SHOW_MIN_DURATION)
}
fun dismiss() {
(parent as? ViewGroup)?.removeView(this)
_isShowing = false
onDismissListener?.invoke()
}
private var onDismissListener: (() -> Unit)? = null
fun setDismissListener(listener: () -> Unit) {
onDismissListener = listener
}
private fun getLocationInWindow(anchor: View): Rect {
val result = Rect()
val pos = IntArray(2)
anchor.getLocationInWindow(pos)
result.left = pos[0]
result.top = pos[1]
result.right = result.left + anchor.width
result.bottom = result.top + anchor.height
return result
}
companion object {
private const val BORDER_WIDTH = 4F
private const val HIGH_LIGHT_RADIUS = 100F
private const val SHOW_MIN_DURATION = 500L
}
}

View File

@ -0,0 +1,401 @@
package com.gh.gamecenter.gamedetail.accelerator
import android.content.Context
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.PackageLauncher
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.callback.AccelerateState
import com.gh.gamecenter.core.callback.OnAccelerateListener
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DetailDownloadItemBinding
import com.gh.gamecenter.feature.entity.AcctGameInfo
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.accelerator.chain.*
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_STOP
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorZoneDialogFragment
import com.gh.gamecenter.gamedetail.accelerator.dialog.StartingAcceleratorDialogFragment
import com.halo.assistant.member.MemberRepository
import com.therouter.TheRouter
class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBinding) {
private var iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
private var guideView: AcceleratorGuideView? = null
val isGuideLayerShowing: Boolean
get() = guideView?.isShowing ?: false
private val zoneList = arrayListOf<AcctGameInfo>()
private var hasZoneListLoaded = false
private var _last: AcctGameInfo? = null
val last: AcctGameInfo?
get() = _last
private val hasMultiZone: Boolean
get() = zoneList.size > 1
private val hasZone: Boolean
get() = zoneList.isNotEmpty()
private val isVip: Boolean
get() = iAcceleratorProvider?.isVip() ?: false
val isNewUser: Boolean
get() = iAcceleratorProvider?.isNewUser() ?: false
private var canSpeed = false
var showSpeedUi = false
private var _game: GameEntity? = null
fun setGame(game: GameEntity?) {
_game = game
}
private val accelerationListener = object : OnAccelerateListener {
override fun onStateChanged(state: AccelerateState) {
when (state) {
is AccelerateState.Success -> {
_game?.let {
val acctGameInfo = state.acctGameInfo
if (acctGameInfo is AcctGameInfo) {
setCurrentAcctGameInfo(acctGameInfo)
}
updateSpeedUi()
}
}
is AccelerateState.Normal -> {
if (!state.isTokenExpired) {
updateSpeedUi()
}
}
else -> Unit
}
}
override fun onProgress(progress: Int, curGamePkgName: String?, curGameZoneFlag: String?) = Unit
override fun onVipStatusChanged(isNewUser: Boolean, isVip: Boolean) {
binding.ivFreeVipTag.visibleIf(
showSpeedUi &&
CheckLoginUtils.isLogin() &&
isNewUser &&
!isGuideLayerShowing
)
}
}
fun initSpeedUi(context: Context) {
canSpeed = true
_game?.let {
iAcceleratorProvider?.bindAccRelatedListener(it.getUniquePackageName() ?: "", accelerationListener)
}
binding.vSpeedContent.setOnClickListener {
_game?.let { game ->
checkDataReady {
startAccelerating(context, game, false)
}
}
}
binding.vMoreZone.setOnClickListener {
_game?.let { game ->
checkDataReady {
showZoneList(context, game)
}
}
}
binding.tvStopSpeed.setOnClickListener {
_game?.let {
SensorsBridge.trackNetworkAccelerationOtherButtonClick(
it.getUniquePackageName() ?: "",
it.id,
it.name ?: "",
iAcceleratorProvider?.getMemberType() ?: "",
BUTTON_NAME_STOP_ACCELERATOR,
SOURCE_ENTRANCE_GAME_DETAIL
)
AcceleratorDialogFragment.show(
SPEED_STOP, it.getUniquePackageName() ?: "", it.id, it.name ?: "",
SOURCE_ENTRANCE_GAME_DETAIL, context
)
}
}
binding.tvEnterGame.setOnClickListener {
_game?.let { game ->
SensorsBridge.trackNetworkAccelerationOtherButtonClick(
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
iAcceleratorProvider?.getMemberType() ?: "",
BUTTON_NAME_ENTER_GAME,
SOURCE_ENTRANCE_GAME_DETAIL
)
PackageLauncher.launchApp(context, game, game.getUniquePackageName())
}
}
updateSpeedUi()
}
fun updateSpeedUi() {
if (!showSpeedUi) {
return
}
val hasGameBeingAccelerated = iAcceleratorProvider?.isCurAccSuccess() ?: false
val isCurAccSuccess = hasGameBeingAccelerated &&
MemberRepository.instance.acctGameRecord.gameId == (_game?.id ?: "")
binding.detailProgressbar.goneIf(isCurAccSuccess)
binding.clSpeed.goneIf(isCurAccSuccess)
binding.gAccelerating.goneIf(!isCurAccSuccess)
binding.gMoreZone.goneIf(!hasMultiZone)
binding.ivFreeVipTag.visibleIf(
showSpeedUi &&
CheckLoginUtils.isLogin() &&
isNewUser &&
!isGuideLayerShowing
)
binding.tvSpeed.text = if (hasMultiZone) {
last?.zoneName
} else {
null
} ?: R.string.network_acceleration.toResString()
}
/**
* 在这个方法里确定是否需要展示 加速ui
* 当 clSpeedContainer没有显示时调用updateSpeedUi()无效,可以调用initSpeedUi()
* 请注意,只要是 gameDetail 发生变化,这里就会回调,所以当 canSpeed 确定之后,这里最少还会回调一次
*/
fun checkIfShowGuideLayer(context: Context) {
showSpeedUi = canSpeed
binding.clSpeedContainer.goneIf(!showSpeedUi) {
// canSpeed =true 说明detail接口已完成
binding.detailProgressbar.setBackgroundResource(com.gh.gamecenter.common.R.drawable.bg_common_button_light_fill_blue)
binding.detailProgressbar.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
updateSpeedUi()
if (CheckLoginUtils.isLogin()) {
if (!hasShow()) {
// 优先显示弹窗
binding.ivFreeVipTag.visibleIf(false)
showGuideLayer(context)
}
} else {
// 未登录
binding.ivFreeVipTag.visibleIf(false)
showGuideLayer(context)
}
}
}
private fun showGuideLayer(context: Context) {
if (!hasShow()) {
binding.root.post {
val uiListener = object : OnAcceleratorListener {
override fun onStartAccelerator() {
_game?.let {
startAccelerating(context, it, true)
}
}
override fun onGuideLayerDismiss() {
binding.ivFreeVipTag.visibleIf(CheckLoginUtils.isLogin() && hasZone && isNewUser)
}
}
SPUtils.setBoolean(Constants.SP_HAS_SHOW_ACCELERATION_GUIDE_LAYER, true)
if (guideView == null) {
guideView = AcceleratorGuideView(context).apply {
setDismissListener(uiListener::onGuideLayerDismiss)
}
}
(guideView?.parent as? ViewGroup)?.removeView(guideView)
if (context is AppCompatActivity) {
_game?.let {
SensorsBridge.trackNetworkAccelerationGuidanceDiagramShow(
it.getUniquePackageName() ?: "",
it.id,
it.name ?: ""
)
}
guideView?.show(binding.clSpeedContainer, context, uiListener::onStartAccelerator)
}
}
}
}
fun onBack(): Boolean {
val isShowing = guideView?.isShowing ?: false
if (isShowing) {
guideView?.dismiss()
return true
} else {
return false
}
}
private fun hasShow(): Boolean {
return SPUtils.getBoolean(Constants.SP_HAS_SHOW_ACCELERATION_GUIDE_LAYER)
}
private fun startAccelerating(context: Context, game: GameEntity, isShowing: Boolean) {
if (isInvalidClick() || !hasZone) {
return
}
val lastAcctGameInfo = last
val memberType = if (CheckLoginUtils.isLogin()) {
iAcceleratorProvider?.getMemberType() ?: ""
} else {
MEMBER_TYPE_NOT_LOGIN
}
val districtServer = when {
hasMultiZone && lastAcctGameInfo != null -> lastAcctGameInfo.zoneName
hasMultiZone -> DISTRICT_SERVER_EMPTY
else -> DISTRICT_SERVER_HAVA
}
SensorsBridge.trackNetworkAccelerationButtonClick(
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
memberType,
districtServer,
if (isShowing) SCENE_TYPE_HAVE_GUIDE_LAYER else SCENE_TYPE_NO_GUIDE_LAYER,
SOURCE_ENTRANCE_GAME_DETAIL
)
when {
lastAcctGameInfo != null ->
doStartAccelerating(context, game, lastAcctGameInfo)
hasMultiZone -> AcceleratorZoneDialogFragment.show(context, zoneList, game)
else -> {
val gameInfo = zoneList.firstOrNull() ?: AcctGameInfo("", AcctGameInfo.ZoneInfo(0))
doStartAccelerating(context, game, gameInfo)
}
}
}
private fun showZoneList(context: Context, game: GameEntity) {
if (isInvalidClick() || !hasZone) {
return
}
AcceleratorZoneDialogFragment.show(context, zoneList, game)
}
private var clickTime = 0L
private fun doStartAccelerating(context: Context, game: GameEntity, acctGameInfo: AcctGameInfo) {
val request = AcceleratorValidator.Request(isVip, isNewUser, game, SOURCE_ENTRANCE_GAME_DETAIL)
AcceleratorClient.newInstance()
.execute(context, request, object : AcceleratorValidator.ValidateListener {
override fun finished(context: Context) {
StartingAcceleratorDialogFragment.show(
context, acctGameInfo, game, true, hasMultiZone,
SOURCE_ENTRANCE_GAME_DETAIL,
)
}
})
}
fun setCurrentAcctGameInfo(acctGameInfo: AcctGameInfo?) {
_last = acctGameInfo
if (hasZoneListLoaded) {
updateSpeedUi()
}
}
/**
* 第一次调用 setZoneList 是使用缓存中的数据
* 第二次调用是使用sdk中的最新数据
* 这里优先使用缓存中的sdk中的数据更新到数据库后待下次进入详情页在显示
* 当zoneList为null时说明磁盘上没有数据这时候使用sdk中的
*
*/
fun setZoneList(newZoneList: ArrayList<AcctGameInfo>?) {
if (newZoneList != null && zoneList.isEmpty()) {
hasZoneListLoaded = true
zoneList.clear()
zoneList.addAll(newZoneList)
updateSpeedUi()
}
}
private fun isInvalidClick(): Boolean {
// 300ms内只能调用一次
val currentTime = System.currentTimeMillis()
val difTime = currentTime - clickTime
if (difTime <= CLICK_DURATION) {
return true
}
clickTime = currentTime
return false
}
private fun checkDataReady(block: () -> Unit) {
when {
!hasZoneListLoaded -> {
ToastUtils.showToast("区服信息正在加载中,请稍后再试!")
}
zoneList.isEmpty() -> {
ToastUtils.showToast("区服信息加载失败,请稍后再试!")
}
else -> {
block()
}
}
}
fun clear() {
iAcceleratorProvider?.unBindAccRelatedListener(accelerationListener)
guideView?.dismiss()
}
companion object {
private const val CLICK_DURATION = 300
const val MEMBER_TYPE_NOT_LOGIN = "未登录"
private const val DISTRICT_SERVER_EMPTY = ""
const val DISTRICT_SERVER_HAVA = ""
private const val SCENE_TYPE_HAVE_GUIDE_LAYER = "有引导图"
const val SCENE_TYPE_NO_GUIDE_LAYER = "无引导图"
const val SOURCE_ENTRANCE_GAME_DETAIL = "游戏详情页"
const val SOURCE_ENTRANCE_MY_ASSETS = "我的资产"
const val BUTTON_NAME_ENTER_GAME = "进入游戏"
const val BUTTON_NAME_STOP_ACCELERATOR = "停止加速"
}
interface OnAcceleratorListener {
fun onStartAccelerator()
fun onGuideLayerDismiss()
}
}

View File

@ -0,0 +1,54 @@
package com.gh.gamecenter.gamedetail.accelerator
import android.content.Context
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.toResString
/**
* 会员功能 实名认证相关弹窗
*/
object UserVerifyDialogUtils {
fun showUnVerifiedDialog(context: Context, title: String, content: String) {
DialogHelper.showDialog(
context,
title = title,
content = content,
confirmText = R.string.go_to_real_name_authentication.toResString(),
cancelText = "取消",
confirmClickCallback = {
context.startActivity(
ShellActivity.getIntent(
context,
ShellActivity.Type.REAL_NAME_INFO
).apply {
putExtra(EntranceConsts.KEY_SOURCE_ENTRANCE, "游戏实名")
putExtra(EntranceConsts.KEY_IS_FORCED_TO_CERTIFICATE, true)
}
)
NewLogUtils.logCertificationHintDialogOptionsClicked("前往实名认证")
SensorsBridge.trackVerificationPopupClick("前往实名认证")
},
cancelClickCallback = {
NewLogUtils.logCertificationHintDialogOptionsClicked("取消")
SensorsBridge.trackVerificationPopupClick("取消")
}
)
}
fun showMinorsOrVerifyingDialog(context: Context, title: String, content: String) {
DialogHelper.showDialog(
context,
title = title,
content = content,
confirmText = R.string.dialog_hint_confirm.toResString(),
cancelText = "",
)
}
}

View File

@ -0,0 +1,28 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_NOT_INSTALLED
class AcceleratorCheckInstallInterceptor : AcceleratorValidator.Interceptor {
override fun intercept(
context: Context,
chain: AcceleratorValidator.Chain,
listener: AcceleratorValidator.ValidateListener?
) {
val request = chain.request
if (PackageUtils.isInstalled(context, request.game.getUniquePackageName() ?: "")) {
chain.proceed(context, request, listener)
} else {
val game = request.game
AcceleratorDialogFragment.show(
SPEED_NOT_INSTALLED,
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
request.sourceEntrance, context
)
}
}
}

View File

@ -0,0 +1,29 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
class AcceleratorClient(
private vararg val interceptors: AcceleratorValidator.Interceptor,
) {
fun execute(
context: Context,
request: AcceleratorValidator.Request,
listener: AcceleratorValidator.ValidateListener
) {
val chain = RealAcceleratorInterceptorChain(interceptors.toList(), 0, request)
chain.proceed(context, request, listener)
}
companion object {
fun newInstance() = AcceleratorClient(
AcceleratorCheckInstallInterceptor(),
AcceleratorLoginInterceptor(),
AcceleratorPackageCheckInterceptor(),
AcceleratorRealNameInterceptor(),
AcceleratorVipInterceptor(),
AcceleratorStateInterceptor()
)
}
}

View File

@ -0,0 +1,18 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import com.gh.gamecenter.common.utils.ifLogin
class AcceleratorLoginInterceptor : AcceleratorValidator.Interceptor {
override fun intercept(
context: Context,
chain: AcceleratorValidator.Chain,
listener: AcceleratorValidator.ValidateListener?
) {
context.ifLogin("[网络加速]") {
val request = chain.request
chain.proceed(context, request, listener)
}
}
}

View File

@ -0,0 +1,20 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.dialog.PackageCheckDialogFragment
class AcceleratorPackageCheckInterceptor : AcceleratorValidator.Interceptor {
override fun intercept(
context: Context,
chain: AcceleratorValidator.Chain,
listener: AcceleratorValidator.ValidateListener?
) {
val request = chain.request
if (context is AppCompatActivity) {
PackageCheckDialogFragment.show(context, request.game) {
chain.proceed(context, request, listener)
}
}
}
}

View File

@ -0,0 +1,26 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import com.gh.common.util.TempCertificationUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.gamedetail.accelerator.UserVerifyDialogUtils
class AcceleratorRealNameInterceptor : AcceleratorValidator.Interceptor {
override fun intercept(
context: Context,
chain: AcceleratorValidator.Chain,
listener: AcceleratorValidator.ValidateListener?
) {
val request = chain.request
if (TempCertificationUtils.isUserVerified()) {
chain.proceed(context, request, listener)
} else {
UserVerifyDialogUtils.showUnVerifiedDialog(
context,
R.string.real_name_tips.toResString(),
R.string.acceleration_service_without_real_name_description.toResString()
)
}
}
}

View File

@ -0,0 +1,37 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorReplaceDialogFragment
import com.therouter.TheRouter
class AcceleratorStateInterceptor : AcceleratorValidator.Interceptor {
override fun intercept(
context: Context,
chain: AcceleratorValidator.Chain,
listener: AcceleratorValidator.ValidateListener?
) {
val request = chain.request
val iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
val isAccelerating = iAcceleratorProvider?.isCurAccSuccess() ?: false
if (isAccelerating) {
val game = request.game
AcceleratorReplaceDialogFragment.show(
context,
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
request.sourceEntrance
) {
if (chain.isValidContext(context)) {
listener?.finished(context)
}
}
} else {
chain.proceed(context, request, listener)
}
}
}

View File

@ -0,0 +1,71 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import android.os.Parcelable
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorValidator.Request
import kotlinx.parcelize.Parcelize
class AcceleratorValidator {
interface ValidateListener {
fun finished(context: Context)
}
interface Interceptor {
fun intercept(context: Context, chain: Chain, listener: ValidateListener?)
}
interface Chain {
val request: Request
fun proceed(context: Context, request: Request, listener: ValidateListener?)
fun isValidContext(context: Context) =
context is AppCompatActivity && !context.isFinishing && !context.isDestroyed
}
@Parcelize
data class Request(
val isVip: Boolean,
val isNewUser: Boolean,
val game: GameEntity,
val sourceEntrance: String
):Parcelable
}
class RealAcceleratorInterceptorChain(
private val interceptors: List<AcceleratorValidator.Interceptor>,
private val index: Int,
private val _request: Request
) : AcceleratorValidator.Chain {
override val request: Request
get() = _request
override
fun proceed(context: Context, request: Request, listener: AcceleratorValidator.ValidateListener?) {
if (!isValidContext(context)) {
// 如果 context失效说明当前页面已销毁直接中断流程
return
}
if (index >= interceptors.size) {
// 验证完成
listener?.finished(context)
return
}
val next = RealAcceleratorInterceptorChain(
interceptors,
index + 1,
_request
)
interceptors[index].intercept(context, next, listener)
}
}

View File

@ -0,0 +1,31 @@
package com.gh.gamecenter.gamedetail.accelerator.chain
import android.content.Context
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_ENABLE_VIP
class AcceleratorVipInterceptor : AcceleratorValidator.Interceptor {
override fun intercept(
context: Context,
chain: AcceleratorValidator.Chain,
listener: AcceleratorValidator.ValidateListener?
) {
val request = chain.request
val isVip = request.isVip
val isNewUser = request.isNewUser
if (isVip || isNewUser) {
chain.proceed(context, request, listener)
} else {
val game = request.game
AcceleratorDialogFragment.show(
SPEED_ENABLE_VIP,
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
request.sourceEntrance,
context
)
}
}
}

View File

@ -0,0 +1,241 @@
package com.gh.gamecenter.gamedetail.accelerator.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.IntDef
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.databinding.DialogFragmentSpeedReplaceGameBinding
import com.therouter.TheRouter
/**
* 加速器相关的dialog
*/
class AcceleratorDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogFragmentSpeedReplaceGameBinding
private lateinit var uiHelper: SpeedDialogUiHelper
private var pkgName = ""
private var gameId = ""
private var gameName = ""
private var sourceEntrance = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val type = arguments?.getInt(EntranceConsts.KEY_SPEED_TYPE) ?: 0
pkgName = arguments?.getString(EntranceConsts.KEY_PACKAGENAME) ?: ""
gameId = arguments?.getString(EntranceConsts.KEY_GAMEID) ?: ""
gameName = arguments?.getString(EntranceConsts.KEY_GAMENAME) ?: ""
sourceEntrance = arguments?.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
uiHelper = when (type) {
SPEED_ENABLE_VIP -> {
SensorsBridge.trackMembershipActivationDialogShow(pkgName, gameId, gameName, sourceEntrance)
EnableVipUi()
}
SPEED_START_FAILURE -> {
SensorsBridge.trackNetworkAccelerationFailureDialogShow(pkgName, gameId, gameName, sourceEntrance)
SpeedFailureUi()
}
SPEED_STOP -> StopSpeedUi()
SPEED_NOT_INSTALLED -> NotInstalledUi()
else -> throw IllegalArgumentException("请传递正确的参数 SpeedType !")
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(true)
createDialog.setCancelable(true)
return createDialog
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogFragmentSpeedReplaceGameBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.tvContent.setText(uiHelper.contentResId)
binding.tvCancel.goneIf(!uiHelper.isShowCancelButton) {
if (uiHelper.cancelResId != -1) {
binding.tvCancel.setText(uiHelper.cancelResId)
}
binding.tvCancel.setOnClickListener {
dismiss()
}
}
binding.tvSubmit.setText(uiHelper.submitResId)
binding.tvSubmit.setTextColor(uiHelper.submitTextColorResId.toColor(view.context))
binding.tvSubmit.setBackgroundResource(uiHelper.submitBackgroundResId)
binding.tvSubmit.setOnClickListener {
dismiss()
when (uiHelper) {
is EnableVipUi -> {
SensorsBridge.trackMembershipActivationDialogClick(
pkgName,
gameId,
gameName,
sourceEntrance
)
SensorsBridge.trackMyAssetsPageShow(pkgName, gameId, gameName, sourceEntrance)
val intent = WebActivity.getMyAssetsIntent(requireContext())
startActivity(intent)
}
is SpeedFailureUi -> {
SensorsBridge.trackNetworkAccelerationFailureDialogClick(pkgName, gameId, gameName, sourceEntrance)
context?.let {
DirectUtils.directToWebView(it, Constants.QQ_QIDIAN_ADDRESS, "")
}
}
is StopSpeedUi -> {
TheRouter.get(IAcceleratorProvider::class.java)?.stopQyGameAccelerate()
}
}
}
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
companion object {
const val SPEED_ENABLE_VIP = 1
const val SPEED_START_FAILURE = 2
const val SPEED_STOP = 3
const val SPEED_NOT_INSTALLED = 4
fun show(
@SpeedType type: Int,
pkgName: String,
gameId: String,
gameName: String,
sourceEntrance: String,
context: Context
) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = AcceleratorDialogFragment().apply {
arguments = Bundle().apply {
putInt(EntranceConsts.KEY_SPEED_TYPE, type)
putString(EntranceConsts.KEY_PACKAGENAME, pkgName)
putString(EntranceConsts.KEY_GAMEID, gameId)
putString(EntranceConsts.KEY_GAMENAME, gameName)
putString(EntranceConsts.KEY_SOURCE_ENTRANCE, sourceEntrance)
}
}
fragment.show(it, AcceleratorDialogFragment::class.java.simpleName)
}
}
}
@IntDef(SPEED_ENABLE_VIP, SPEED_START_FAILURE, SPEED_STOP, SPEED_NOT_INSTALLED)
@Retention(AnnotationRetention.SOURCE)
annotation class SpeedType
abstract class SpeedDialogUiHelper {
abstract val contentResId: Int
abstract val isShowCancelButton: Boolean
open val cancelResId: Int = -1
abstract val submitResId: Int
open val submitTextColorResId = com.gh.gamecenter.common.R.color.text_aw_primary
open val submitBackgroundResId = com.gh.gamecenter.common.R.drawable.bg_common_button_fill_blue
}
class EnableVipUi : SpeedDialogUiHelper() {
override val contentResId: Int
get() = R.string.enable_vip_tips
override val isShowCancelButton: Boolean
get() = false
override val submitResId: Int
get() = R.string.go_to_activate
}
class SpeedFailureUi : SpeedDialogUiHelper() {
override val contentResId: Int
get() = R.string.speed_failure_tips
override val isShowCancelButton: Boolean
get() = false
override val submitResId: Int
get() = R.string.contact_service
override val submitTextColorResId: Int
get() = com.gh.gamecenter.common.R.color.primary_theme
override val submitBackgroundResId: Int
get() = com.gh.gamecenter.common.R.drawable.bg_common_button_light_fill_blue
}
class StopSpeedUi : SpeedDialogUiHelper() {
override val contentResId: Int
get() = R.string.stop_speed_tips
override val isShowCancelButton: Boolean
get() = true
override val submitResId: Int
get() = R.string.stop_speed
override val cancelResId: Int
get() = R.string.cancel
}
class NotInstalledUi : SpeedDialogUiHelper() {
override val contentResId: Int
get() = R.string.speed_not_installed_tips
override val isShowCancelButton: Boolean
get() = false
override val submitResId: Int
get() = R.string.dialog_hint_confirm
}
}

View File

@ -0,0 +1,116 @@
package com.gh.gamecenter.gamedetail.accelerator.dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.databinding.DialogFragmentSpeedReplaceGameBinding
import com.lightgame.dialog.BaseDialogFragment
class AcceleratorReplaceDialogFragment : BaseDialogFragment() {
private lateinit var binding: DialogFragmentSpeedReplaceGameBinding
private var pkgName = ""
private var gameId = ""
private var gameName = ""
private var sourceEntrance = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pkgName = arguments?.getString(EntranceConsts.KEY_PACKAGENAME) ?: ""
gameId = arguments?.getString(EntranceConsts.KEY_GAMEID) ?: ""
gameName = arguments?.getString(EntranceConsts.KEY_GAMENAME) ?: ""
sourceEntrance = arguments?.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogFragmentSpeedReplaceGameBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
SensorsBridge.trackNetworkAccelerationConflictDialogShow(pkgName, gameId, gameName, sourceEntrance)
binding.tvContent.text = getString(R.string.speed_replace_game_tips, gameName)
binding.tvCancel.setOnClickListener {
SensorsBridge.trackNetworkAccelerationConflictDialogClick(
pkgName,
gameId,
gameName,
BUTTON_NAME_CANCEL,
sourceEntrance
)
dismiss()
}
binding.tvSubmit.setOnClickListener {
SensorsBridge.trackNetworkAccelerationConflictDialogClick(
pkgName,
gameId,
gameName,
BUTTON_NAME_CONTINUE,
sourceEntrance
)
// 加速
dismiss()
callback?.invoke()
}
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().resources.displayMetrics.widthPixels - 60F.dip2px()
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
private var callback: (() -> Unit)? = null
fun setOnSubmitListener(callback: () -> Unit) {
this.callback = callback
}
companion object {
private const val BUTTON_NAME_CANCEL = "暂不启动"
private const val BUTTON_NAME_CONTINUE = "继续启动"
fun show(
context: Context,
pkgName: String,
gameId: String,
gameName: String,
sourceEntrance: String,
callback: () -> Unit
) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = AcceleratorReplaceDialogFragment().apply {
setOnSubmitListener(callback)
arguments = Bundle().apply {
putString(EntranceConsts.KEY_PACKAGENAME, pkgName)
putString(EntranceConsts.KEY_GAMEID, gameId)
putString(EntranceConsts.KEY_GAMENAME, gameName)
putString(EntranceConsts.KEY_SOURCE_ENTRANCE, sourceEntrance)
}
}
fragment.show(it, AcceleratorDialogFragment::class.java.simpleName)
}
}
}
}

View File

@ -0,0 +1,197 @@
package com.gh.gamecenter.gamedetail.accelerator.dialog
import android.content.Context
import android.graphics.Rect
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.databinding.DialogFragmentAcceleratorZoneBinding
import com.gh.gamecenter.databinding.RecyclerAcceleratorZoneBinding
import com.gh.gamecenter.feature.entity.AcctGameInfo
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.MEMBER_TYPE_NOT_LOGIN
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SCENE_TYPE_NO_GUIDE_LAYER
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SOURCE_ENTRANCE_GAME_DETAIL
import com.gh.gamecenter.gamedetail.AcceleratorZoneViewModel
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorClient
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorValidator
import com.therouter.TheRouter
import kotlin.math.roundToInt
class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcceleratorZoneBinding>() {
private val viewModel by viewModels<AcceleratorZoneViewModel>()
private lateinit var adapter: ZoneAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val data =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arguments?.getParcelableArrayList(KEY_DATA, AcctGameInfo::class.java)
} else {
arguments?.getParcelableArrayList(KEY_DATA)
} ?: listOf<AcctGameInfo>()
val game = arguments?.getParcelable<GameEntity>(KEY_GAME)!!
mBinding.titleView.setOnRightClickListener {
dismiss()
}
adapter = ZoneAdapter {
startAccelerating(game, it)
dismiss()
}
mBinding.recyclerZone.layoutManager = GridLayoutManager(requireContext(), 3)
mBinding.recyclerZone.addItemDecoration(MyDecorationItem())
mBinding.recyclerZone.adapter = adapter
adapter.submitList(data)
}
private fun startAccelerating(game: GameEntity, acctGameInfo: AcctGameInfo) {
context?.let {
viewModel.useCase.insertAcctGameInfo(acctGameInfo)
val iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
val memberType = if (CheckLoginUtils.isLogin()) {
iAcceleratorProvider?.getMemberType() ?: ""
} else {
MEMBER_TYPE_NOT_LOGIN
}
SensorsBridge.trackNetworkAccelerationButtonClick(
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
memberType,
acctGameInfo.zoneInfo.cnName ?: "",
SCENE_TYPE_NO_GUIDE_LAYER,
SOURCE_ENTRANCE_GAME_DETAIL
)
val isVip = iAcceleratorProvider?.isVip() ?: false
val isNewUser = iAcceleratorProvider?.isNewUser() ?: false
val request = AcceleratorValidator.Request(isVip, isNewUser, game, SOURCE_ENTRANCE_GAME_DETAIL)
AcceleratorClient.newInstance()
.execute(it, request, object : AcceleratorValidator.ValidateListener {
override fun finished(context: Context) {
StartingAcceleratorDialogFragment.show(
context, acctGameInfo, game, isNeedRecord = true, hasMultiZone = true,
sourceEntrance = SOURCE_ENTRANCE_GAME_DETAIL
)
}
})
}
}
companion object {
private const val KEY_DATA = "key_data"
private const val KEY_GAME = "key_game"
fun show(context: Context, data: ArrayList<AcctGameInfo>, game: GameEntity) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = AcceleratorZoneDialogFragment().apply {
arguments = Bundle().apply {
putParcelableArrayList(KEY_DATA, data)
putParcelable(KEY_GAME, game)
}
}
fragment.show(it, fragment::class.java.simpleName)
}
}
}
private class MyDecorationItem : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val space = (16F.dip2px() / 3F).roundToInt()
val (left, right) = when (position % 3) {
0 -> 0 to space
1 -> space to space
else -> space to 0
}
outRect.top = 8F.dip2px()
outRect.left = left
outRect.right = right
}
}
class ZoneAdapter(private val click: (AcctGameInfo) -> Unit) :
ListAdapter<AcctGameInfo, ZoneAdapter.ZoneViewHolder>(diffCallback) {
private var selectedPosition = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
return ZoneViewHolder(parent.toBinding())
}
override fun onBindViewHolder(holder: ZoneViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNotEmpty()) {
updateSelectedState(holder, position)
} else {
super.onBindViewHolder(holder, position, payloads)
}
}
override fun onBindViewHolder(holder: ZoneViewHolder, position: Int) {
val item = getItem(position) ?: return
updateSelectedState(holder, position)
holder.binding.tvName.text = item.zoneName
holder.itemView.setOnClickListener {
click(item)
}
}
private fun updateSelectedState(holder: ZoneViewHolder, position: Int) {
val (textColorResId, backgroundResId) = if (position == selectedPosition) {
com.gh.gamecenter.common.R.color.text_theme to R.drawable.bg_shape_2496ff_alpha_10_radius_8
} else {
com.gh.gamecenter.common.R.color.text_secondary to R.drawable.bg_shape_f8_radius_8
}
holder.binding.tvName.setTextColor(textColorResId.toColor(holder.itemView.context))
holder.binding.tvName.setBackgroundResource(backgroundResId)
}
companion object {
private const val SELECTED_CHANGED_PAYLOAD = "selected_changed_payload"
private val diffCallback = object : DiffUtil.ItemCallback<AcctGameInfo>() {
override fun areItemsTheSame(oldItem: AcctGameInfo, newItem: AcctGameInfo): Boolean {
return oldItem.zoneInfo.id == newItem.zoneInfo.id
}
override fun areContentsTheSame(oldItem: AcctGameInfo, newItem: AcctGameInfo): Boolean {
return oldItem == newItem
}
}
}
class ZoneViewHolder(val binding: RecyclerAcceleratorZoneBinding) : ViewHolder(binding.root)
}
}

View File

@ -0,0 +1,258 @@
package com.gh.gamecenter.gamedetail.accelerator.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.viewModels
import com.gh.common.util.PackageLauncher
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.core.callback.AccelerateState
import com.gh.gamecenter.core.callback.OnAccelerateListener
import com.gh.gamecenter.core.provider.IAcceleratorProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogFragmentStartingAcceleratorBinding
import com.gh.gamecenter.feature.entity.AcctGameInfo
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.StartingAcceleratorViewModel
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.DISTRICT_SERVER_HAVA
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SOURCE_ENTRANCE_GAME_DETAIL
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_START_FAILURE
import com.gh.gamecenter.livedata.EventObserver
import com.therouter.TheRouter
import io.reactivex.disposables.CompositeDisposable
import kotlin.math.max
class StartingAcceleratorDialogFragment : BaseDialogFragment() {
private val viewModel by viewModels<StartingAcceleratorViewModel>()
private lateinit var binding: DialogFragmentStartingAcceleratorBinding
private lateinit var acctGameInfo: AcctGameInfo
private lateinit var game: GameEntity
private var isNeedRecord: Boolean = false
private var iAcceleratorProvider: IAcceleratorProvider? = null
private var hasMultiZone = false
private var sourceEntrance = SOURCE_ENTRANCE_GAME_DETAIL
private val compositeDisposable = CompositeDisposable()
private var _progress = 0
private val handler = Handler(Looper.getMainLooper())
private var refreshTokenCount = 0
private val accelerationListener = object : OnAccelerateListener {
override fun onStateChanged(state: AccelerateState) {
// 如果状态能成功回,则移除计时
handler.removeCallbacksAndMessages(null)
when (state) {
is AccelerateState.Success -> {
ToastUtils.showToast("加速成功")
// 加速成功,启动游戏
PackageLauncher.launchApp(requireContext(), game, game.getUniquePackageName())
// 记录加速记录
if (isNeedRecord) {
viewModel.useCase.recordAcctGameInfo(game.id, acctGameInfo, hasMultiZone)
}
trackNetworkAccelerationStartupResult("成功")
dismissAllowingStateLoss()
}
is AccelerateState.Failure -> {
// 有些错误需要额外处理,这里直接跳过错误提示(如token失效登录时token设置失败)
if ((state.isTokenExpired || state.isTokenEmpty) && refreshTokenCount < REFRESH_TOKEN_MAX_COUNT) {
// do nothing
} else {
if (!state.isSkipError) {
context?.let {
AcceleratorDialogFragment.show(
SPEED_START_FAILURE,
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
sourceEntrance,
it
)
}
}
dismissAllowingStateLoss()
trackNetworkAccelerationStartupResult("失败(${state.code})")
}
}
is AccelerateState.Normal -> {
if (state.isTokenExpired || state.isTokenEmpty) {
// token过期/登录时token设置失败,在此获取token并重新启动加速(最多重试三次)
if (refreshTokenCount < REFRESH_TOKEN_MAX_COUNT) {
viewModel.loadAcceleratorToken()
refreshTokenCount++
}
}
}
else -> Unit
}
}
override fun onProgress(progress: Int, curGamePkgName: String?, curGameZoneFlag: String?) {
_progress = max(_progress, progress)
binding.tvProgress.text = getString(R.string.accelerating_with_progress, "$progress")
}
override fun onVipStatusChanged(isNewUser: Boolean, isVip: Boolean) = Unit
}
private fun trackNetworkAccelerationStartupResult(result: String) {
SensorsBridge.trackNetworkAccelerationStartupResult(
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
iAcceleratorProvider?.getMemberType() ?: "",
if (hasMultiZone) acctGameInfo.zoneInfo.cnName ?: "" else DISTRICT_SERVER_HAVA,
result,
sourceEntrance
)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setCancelable(false)
setCanceledOnTouchOutside(false)
this@StartingAcceleratorDialogFragment.isCancelable = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
acctGameInfo = arguments?.getParcelable(EntranceConsts.KEY_ACCT_GAME_INFO)!!
game = arguments?.getParcelable(EntranceConsts.KEY_GAME)!!
isNeedRecord = arguments?.getBoolean(EntranceConsts.KEY_IS_NEED_RECORD) ?: false
hasMultiZone = arguments?.getBoolean(EntranceConsts.KEY_HAS_MULTI_ZONE) ?: false
sourceEntrance = arguments?.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: SOURCE_ENTRANCE_GAME_DETAIL
}
override fun onBack(): Boolean {
return true
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogFragmentStartingAcceleratorBinding.inflate(inflater, container, false)
.also {
binding = it
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.tvProgress.text = getString(R.string.accelerating_with_progress, "0")
iAcceleratorProvider?.bindAccRelatedListener("", accelerationListener)
val isVip = iAcceleratorProvider?.isVip() ?: false
val isNewUser = iAcceleratorProvider?.isNewUser() ?: false
if (isNewUser && !isVip) {
// 新用户并且还不是vip
viewModel.rechargeTrial()
} else {
startGameAccelerate()
}
viewModel.restartingAcceleratorAction.observe(viewLifecycleOwner, EventObserver {
startGameAccelerate()
})
viewModel.rechargeTrailResult.observe(viewLifecycleOwner, EventObserver {
if (it) {
startGameAccelerate()
} else {
// 充值失败
AcceleratorDialogFragment.show(
SPEED_START_FAILURE,
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
sourceEntrance,
requireContext()
)
dismissAllowingStateLoss()
}
})
}
private fun startGameAccelerate() {
handler.removeCallbacksAndMessages(null)
handler.postDelayed({
// 15s以后不管成功还是失败都要关闭当前页面
dismissAllowingStateLoss()
}, TIME_OUT)
viewModel.useCase.setLastAcctGameRecord(game)
iAcceleratorProvider?.startQyGameAccelerate(acctGameInfo)
if (isNeedRecord) {
viewModel.useCase.insertAcctGameInfo(acctGameInfo)
}
if (refreshTokenCount == 0) {
SensorsBridge.trackNetworkAccelerationStartup(
game.getUniquePackageName() ?: "",
game.id,
game.name ?: "",
iAcceleratorProvider?.getMemberType() ?: "",
if (hasMultiZone) acctGameInfo.zoneInfo.cnName ?: "" else DISTRICT_SERVER_HAVA,
sourceEntrance
)
}
}
override fun onDestroyView() {
handler.removeCallbacksAndMessages(null)
iAcceleratorProvider?.unBindAccRelatedListener(accelerationListener)
super.onDestroyView()
compositeDisposable.clear()
}
companion object {
private const val TIME_OUT = 1000 * 15L
private const val REFRESH_TOKEN_MAX_COUNT = 3
fun show(
context: Context,
acctGameInfo: AcctGameInfo,
game: GameEntity,
isNeedRecord: Boolean,
hasMultiZone: Boolean,
sourceEntrance: String
) {
if (context is AppCompatActivity) {
context.supportFragmentManager
} else {
(CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity)?.supportFragmentManager
}?.let {
val fragment = StartingAcceleratorDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(EntranceConsts.KEY_ACCT_GAME_INFO, acctGameInfo)
putParcelable(EntranceConsts.KEY_GAME, game)
putBoolean(EntranceConsts.KEY_IS_NEED_RECORD, isNeedRecord)
putBoolean(EntranceConsts.KEY_HAS_MULTI_ZONE, hasMultiZone)
putString(EntranceConsts.KEY_SOURCE_ENTRANCE, sourceEntrance)
}
}
fragment.show(it, fragment::class.java.simpleName)
}
}
}
}

View File

@ -983,14 +983,17 @@ class DescAdapter(
setExpandMaxLines(maxDesLines)
setIsExpanded(Int.MAX_VALUE == maxDesLines)
if (customColumn.isHtmlDes == true) {
val decoratedDesBrief = (customColumn.desBrief ?: "").dropFontColorInDarkMode(contentTv.context)
val decoratedDes = (customColumn.des ?: "").dropFontColorInDarkMode(contentTv.context)
shrankSpanned = HtmlCompat.fromHtml(
customColumn.desBrief ?: "",
decoratedDesBrief,
HtmlCompat.FROM_HTML_MODE_COMPACT,
PicassoImageGetter(contentTv),
ExtraTagHandler()
)
expandedSpanned = HtmlCompat.fromHtml(
customColumn.des ?: "",
decoratedDes,
HtmlCompat.FROM_HTML_MODE_COMPACT,
PicassoImageGetter(contentTv),
ExtraTagHandler()

View File

@ -61,7 +61,14 @@ class NewGameDetailEntity(
@SerializedName("new_notice")
var newNotice: ArrayList<LinkEntity>? = null,
@SerializedName("accelerator_status")
private var _acceleratorStatus: Boolean? = null
) {
val acceleratorStatus: Boolean
get() = _acceleratorStatus ?: false
fun isShowContentCard(gameEntity: GameEntity?): Boolean {
return contentCard.size > 1 && (gameEntity?.shouldUseMirrorInfo() == false || (gameEntity?.shouldUseMirrorInfo() == true && mirrorData?.contentCardStatus == "on"))
}

View File

@ -6,11 +6,14 @@ import android.os.Bundle
import androidx.fragment.app.Fragment
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.therouter.router.Route
/**
* 开服订阅
*/
@Route(
path = RouteConsts.activity.serversCalendarManagementActivity,
description = "开服订阅"
)
class ServersCalendarManagementActivity : BaseActivity_TabLayout() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -25,10 +25,10 @@ import com.gh.gamecenter.common.utils.toPx
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.eventbus.EBStar
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.halo.assistant.HaloApp
import org.greenrobot.eventbus.EventBus
@ -60,7 +60,7 @@ class RatingFragment : LazyListFragment<RatingComment, RatingViewModel>(), IScro
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RATING_EDIT_REQUEST && resultCode == Activity.RESULT_OK) {
mListViewModel.initData()
mListViewModel?.initData()
} else if (
(requestCode == RATING_REPLAY_REQUEST || requestCode == RATING_PATCH_REQUEST)
&& resultCode == Activity.RESULT_OK

View File

@ -3,7 +3,11 @@ package com.gh.gamecenter.home.custom
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
@ -54,6 +58,7 @@ import com.gh.gamecenter.feature.entity.PageLocation
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.feature.utils.SentryHelper
import com.gh.gamecenter.game.commoncollection.detail.CustomCommonCollectionDetailActivity
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.home.PageConfigure
@ -69,6 +74,9 @@ import com.gh.gamecenter.wrapper.SearchToolbarTabWrapperViewModel
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.constant.RefreshState
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -179,6 +187,22 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
viewModel.init(pageConfigure, searchToolbarTabWrapperViewModel, pageLocation)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = try {
FragmentCustomBinding.inflate(layoutInflater)
} catch (e: Exception) {
SentryHelper.onEvent(
"VIEW_BINDING_BIND_ERROR",
"digest", e.localizedMessage,
"gid", HaloApp.getInstance().gid
)
// 玄学,重试一次,该闪退闪退
FragmentCustomBinding.inflate(layoutInflater)
}
mCachedView = binding.root
return mCachedView
}
override fun getRealLayoutId() = R.layout.fragment_custom
override fun onFragmentFirstVisible() {
@ -215,7 +239,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
viewModel.loadFirst(false)
}
}
binding.reuseNoConnectionStub.inflate()
binding.reuseNoConnectionStub.inflateOrShow()
} else {
noConnectionBinding?.root?.visibility = View.VISIBLE
}
@ -225,7 +249,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
noDataBinding = ReuseNoneDataBinding.bind(inflated)
noDataBinding?.root?.visibility = View.VISIBLE
}
binding.reuseNoDataStub.inflate()
binding.reuseNoDataStub.inflateOrShow()
} else {
noDataBinding?.root?.visibility = View.VISIBLE
}
@ -275,9 +299,12 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
if (searchBarBinding == null) {
binding.reuseSearchBarStub.setOnInflateListener { _, inflated ->
searchBarBinding = LayoutSearchBarBinding.bind(inflated)
binding.gameRefresh.updateLayoutParams<RelativeLayout.LayoutParams> {
addRule(RelativeLayout.BELOW, R.id.reuseSearchBar)
}
initSearchBar(it)
}
binding.reuseSearchBarStub.inflate()
binding.reuseSearchBarStub.inflateOrShow()
} else {
initSearchBar(it)
}
@ -469,7 +496,8 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
pageLocation.tabPosition,
pageLocation.tabContent,
pageLocation.pageId,
pageLocation.pageName
pageLocation.pageName,
mEntrance
)
viewModel.loadData()
@ -488,8 +516,6 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
override fun initRealView() {
super.initRealView()
binding = FragmentCustomBinding.bind(mCachedView)
scrollCalculatorHelper = ScrollCalculatorHelper(binding.gameList, R.id.autoVideoView, 0, false)
buildPriorityChain()
@ -743,7 +769,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
}
}
override fun setScrollEnabled(isScrollEnabled: Boolean) {
private fun setScrollEnabled(isScrollEnabled: Boolean) {
if (::layoutManager.isInitialized) {
layoutManager.isScrollVerticallyEnabled = isScrollEnabled
}
@ -759,6 +785,32 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
}
}
override fun onStateChanged(refreshLayout: RefreshLayout, oldState: RefreshState, newState: RefreshState) {
if (oldState == RefreshState.None && newState == RefreshState.PullDownToRefresh) {
pauseVideo()
} else if ((oldState == RefreshState.TwoLevelFinish || oldState == RefreshState.RefreshFinish) && newState == RefreshState.None) {
val currentPlayer = scrollCalculatorHelper.currentPlayer
if (currentPlayer == null) {
scrollCalculatorHelper.playIfValid()
} else if (currentPlayer.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
resumeVideo()
}
}
when (newState) {
RefreshState.TwoLevel -> {
setScrollEnabled(false)
}
RefreshState.None -> {
setScrollEnabled(true)
}
else -> {
// do nothing
}
}
}
override fun scrollToTop() {
if (::binding.isInitialized) {
binding.gameList.stopScroll()

View File

@ -93,7 +93,12 @@ class CustomPageViewModel(
private var searchToolbarTabWrapperViewModel: SearchToolbarTabWrapperViewModel? = null
private val subjectChangedMap: ArrayMap<String, List<GameEntity>> = ArrayMap()
private val subjectChangedMap: ArrayMap<SubjectChanged, List<GameEntity>> = ArrayMap()
/**
* 微信CPM专题当前的页码记录
*/
private val cpmSubjectChangedPageMap: ArrayMap<String, Int> = ArrayMap()
var slideDiscoveryGamesPage = -1
@ -358,9 +363,68 @@ class CustomPageViewModel(
}
}
override fun onChangeABatch(subjectEntity: SubjectEntity) {
override fun onChangeABatch(subjectEntity: SubjectEntity) =
if (subjectEntity.isWechatColumnCPM) {
onChangeWGameCPMABatch(subjectEntity)
} else {
onChangeNormalGameABatch(subjectEntity)
}
/**
* 微信小游戏CPM的“换一批”功能实现
*
* @see <a href="https://jira.shanqu.cc/browse/GHZSCY-7167">【光环助手】CPM微信小游戏“换一批”功能优化</a>
*/
private fun onChangeWGameCPMABatch(subjectEntity: SubjectEntity) {
val subjectId = subjectEntity.id ?: return
val gameList = subjectChangedMap[subjectId]
val page = cpmSubjectChangedPageMap[subjectId] ?: let {
// 第一次点击“换一批”时,先缓存第一页的数据
subjectChangedMap[SubjectChanged(subjectId, 1)] = subjectEntity.data
2
}
val subjectChanged = SubjectChanged(subjectId, page)
val gameList = subjectChangedMap[subjectChanged]
if (gameList != null) {// 直接读取缓存数据
notifyWGameCPMABatchChanged(gameList, subjectId, page)
} else {
repository.loadChangeSubjectWGameCPM(page)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<List<GameEntity>>() {
override fun onResponse(response: List<GameEntity>?) {
if (response != null) {
subjectChangedMap[subjectChanged] = response
notifyWGameCPMABatchChanged(response, subjectId, page)
}
}
override fun onFailure(e: HttpException?) {
Utils.toast(getApplication(), "网络异常")
}
})
}
}
private fun notifyWGameCPMABatchChanged(gameList: List<GameEntity>, subjectId: String, page: Int) {
val nextPage: Int
val cpmGameList = if(gameList.isEmpty()) {
nextPage = 1// 已经到最后一页了,下一页是第一页
subjectChangedMap[SubjectChanged(subjectId, 1)]!!
} else {
nextPage = page + 1
gameList
}
cpmSubjectChangedPageMap[subjectId] = nextPage// 加载下一页数据
changeSubjectCustomPageItem(subjectId, ArrayList(cpmGameList))
}
/**
* 光环游戏的“换一批”功能实现
*/
private fun onChangeNormalGameABatch(subjectEntity: SubjectEntity) {
val subjectId = subjectEntity.id ?: return
val subjectChanged = SubjectChanged(subjectId, 2)
val gameList = subjectChangedMap[subjectChanged]
if (gameList != null) {
changeSubjectCustomPageItem(subjectId, getRandomGameList(subjectEntity.data, ArrayList(gameList)))
} else {
@ -370,7 +434,7 @@ class CustomPageViewModel(
.subscribe(object : Response<List<GameEntity>>() {
override fun onResponse(response: List<GameEntity>?) {
if (response != null) {
subjectChangedMap[subjectId] = response
subjectChangedMap[subjectChanged] = response
onChangeABatch(subjectEntity)
}
}
@ -760,5 +824,26 @@ class CustomPageViewModel(
repository.onClear()
}
class SubjectChanged(
val subjectId: String,
val page: Int
) {
companion object {
private const val HASH = 30
}
override fun hashCode(): Int {
return subjectId.hashCode() + page.hashCode() + HASH
}
override fun equals(other: Any?): Boolean {
if (other !is SubjectChanged) {
return false
}
return other.subjectId == subjectId
&& other.page == page
}
}
}

View File

@ -6,6 +6,8 @@ import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toDrawable
import com.gh.gamecenter.databinding.RecyclerContentLabelLaneItemBinding
import com.gh.gamecenter.home.custom.model.CustomPageData
@ -28,6 +30,10 @@ class ContentLabelLaneAdapter(
override fun onBindViewHolder(holder: ContentLabelChildViewHolder, position: Int) {
val item = getItem(position)
with(holder.binding) {
vBackground.background = R.drawable.bg_shape_content_label_lane_item.toDrawable(context)
tvTitle.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
tvSubTitle.setTextColor(com.gh.gamecenter.common.R.color.primary_theme.toColor(context))
ivIcon.goneIf(item.image.isBlank()){
ivIcon.displayGameIcon(item.image, null, null)
}

View File

@ -805,11 +805,13 @@ class CustomPageRepository private constructor(
}
fun loadChangeSubjectGame(subjectEntity: SubjectEntity): Observable<List<GameEntity>> =
if (subjectEntity.isWechatColumnCPM) {// 微信小游戏CPM专题的“换一批”接口
wGameSubjectCPMRemoteDataSource.getRecommendCPMList(2, 10).toObservable()
} else {
remoteDataSource.loadChangeSubjectGame(subjectEntity)
}
remoteDataSource.loadChangeSubjectGame(subjectEntity)
.map(RegionSettingHelper.filterGame)
.map(ApkActiveUtils.filterMapperList)
fun loadChangeSubjectWGameCPM(page: Int): Observable<MutableList<GameEntity>> =
wGameSubjectCPMRemoteDataSource.getEditorRecommendCPMList(page, 10)// 微信小游戏CPM专题的“换一批”接口
.toObservable()
.map(RegionSettingHelper.filterGame)
.map(ApkActiveUtils.filterMapperList)

View File

@ -65,7 +65,7 @@ class SubjectTracker(private val pageLocation: PageLocation) {
pageLocation.pageName,
subject?.id ?: "",
subject?.name ?: "",
"最近在玩",
"自定义页面",
item.componentStyle,
"",
)

View File

@ -363,7 +363,7 @@ class CommonContentHomeSlideWithCardsUi(
homeSlideCardItemBinding.cardIv.visibility = View.VISIBLE
// 防止重复加载图片导致闪烁
if (homeSubSlide.image != cardIv.getTag(R.string.tag_img_url_id)) {
ImageUtils.display(cardIv, homeSubSlide.image, false, AlphaGradientProcess())
ImageUtils.display(cardIv, homeSubSlide.image, true, AlphaGradientProcess())
cardIv.setTag(R.string.tag_img_url_id, homeSubSlide.image)
}
ConstraintSet().apply {
@ -398,7 +398,7 @@ class CommonContentHomeSlideWithCardsUi(
descTv.text = homeSubSlide.cardDesc
// 防止重复加载图片导致闪烁
if (homeSubSlide.image != cardIv.getTag(R.string.tag_img_url_id)) {
ImageUtils.display(cardIv, homeSubSlide.image, false, AlphaGradientProcess())
ImageUtils.display(cardIv, homeSubSlide.image, true, AlphaGradientProcess())
cardIv.setTag(R.string.tag_img_url_id, homeSubSlide.image)
}
ConstraintSet().apply {

View File

@ -40,7 +40,7 @@ class CustomGameGallerySlideViewHolder(
override fun bindView(item: CustomPageItem) {
super.bindView(item)
if (item is CustomSubjectItem) {
binding.cardView.setCardBackgroundColor(com.gh.gamecenter.common.R.color.ui_container_1.toColor(binding.root.context))
if (item.data == cachedSubject) return
cachedSubject = item.data
@ -77,7 +77,6 @@ class CustomGameGallerySlideViewHolder(
val gameList = item.data.data ?: emptyList()
(recyclerView.adapter as? GameGallerySlideAdapter)?.submitList(gameList)
}
binding.cardView.setCardBackgroundColor(com.gh.gamecenter.common.R.color.text_FAFAFA.toColor(binding.root.context))
}

View File

@ -192,9 +192,6 @@ class CustomGameItemViewHolder(
adLabelTv: TextView? = null,
canShowSubTitle: Boolean
) {
if (entity.id == gameSubtitleTv.getTag(com.gh.gamecenter.common.R.string.tag_game_name_id)) return
gameSubtitleTv.setTag(com.gh.gamecenter.common.R.string.tag_game_name_id, entity.id)
var showSubtitle = false
var showAdvancedDownload = false
if (canShowSubTitle && entity.serverLabel == null && entity.subtitle.isNotEmpty() && !entity.advanceDownload) {
@ -214,6 +211,9 @@ class CustomGameItemViewHolder(
setColor("#${entity.subtitleStyle?.background}".hexStringToIntColor())
}
}
} else {
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
background = R.drawable.bg_advance_download_game_subtitle.toDrawable(context)
}
}
}
@ -226,6 +226,10 @@ class CustomGameItemViewHolder(
background = R.drawable.bg_advance_download_game_subtitle.toDrawable(context)
}
}
if (entity.id == gameSubtitleTv.getTag(com.gh.gamecenter.common.R.string.tag_game_name_id)) return
gameSubtitleTv.setTag(com.gh.gamecenter.common.R.string.tag_game_name_id, entity.id)
if (showSubtitle || showAdvancedDownload) {
val minWidth =
if (showSubtitle) SUBTITLE_MIN_WIDTH.dip2px() else if (showAdvancedDownload) ADVANCED_DOWNLOAD_WIDTH.dip2px() else 0

View File

@ -109,7 +109,9 @@ class CustomHomeGameItemViewHolder(
item.linkColumn?.id ?: ""
)
}
binding.gameBrief.text = game.recommendText
binding.gameBrief.goneIf(game.recommendText.isEmpty()) {
binding.gameBrief.text = game.recommendText
}
binding.gameImage.visibleIf(game.showImage) {
if (game.isWechatMiniGame()) {
ImageUtils.display(binding.gameImage, game.banner)

View File

@ -53,6 +53,7 @@ class CustomHomeSlideListItemViewHolder(val binding: HomeSlideListItemCustomBind
ImageUtils.displayWithCallback(
binding.slideBackground,
homeSlide.image,
false,
object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
binding.bottomGradient.visibility = View.VISIBLE

View File

@ -67,6 +67,7 @@ class CustomHomeSubSlideListItemViewHolder(val binding: HomeSubSlideListItemCust
ImageUtils.displayWithCallback(
binding.slideBackground,
homeSlide.image,
false,
object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
if (homeSlide.placeholderColor.isNotEmpty() && homeSlide.linkGame != null) {

View File

@ -62,7 +62,11 @@ class HomeGameTestV2GameListViewHolder(
)
//开服日期
val gameTimeText = getGameTimeText(gameEntity)
val gameTimeText = if (gameEntity.openTest?.startPending == true) {
gameEntity.openTest?.startText ?: ""
} else {
getGameTimeText(gameEntity)
}
gameDes.text = gameTimeText
gameDes.isVisible = gameTimeText.isNotEmpty()

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