Compare commits

..

163 Commits

Author SHA1 Message Date
42d5d46e53 chore: 版本更新至 5.28.2 2023-07-18 16:13:09 +08:00
cdccc35703 Merge branch 'feature-GHZS-2946' into 'release'
fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2946

See merge request halo/android/assistant-android!1207
2023-07-18 16:08:44 +08:00
d3e2fea019 fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2946 2023-07-18 16:08:44 +08:00
f343841233 Merge branch 'fix/GHZS-2948' into 'release'
fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2948

See merge request halo/android/assistant-android!1206
2023-07-18 14:58:47 +08:00
f62083eff2 fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2948 2023-07-18 14:58:47 +08:00
8594e998c2 Merge branch 'fix/vspace_dialog_dismiss_issue' into 'release'
fix: 修复畅玩弹窗在组件安装完成以后的 dismiss 问题

See merge request halo/android/assistant-android!1205
2023-07-17 17:54:15 +08:00
6865706b0f fix: 修复畅玩弹窗在组件安装完成以后的 dismiss 问题 2023-07-17 17:50:23 +08:00
b6d8ca4d84 Merge branch 'feat/GHZS-2959' into 'release'
feat: 神策渠道调整 https://jira.shanqu.cc/browse/GHZS-2959

See merge request halo/android/assistant-android!1203
2023-07-17 16:14:05 +08:00
455e1f0432 feat: 神策渠道调整 https://jira.shanqu.cc/browse/GHZS-2959 2023-07-17 16:12:29 +08:00
15276cc4b3 Merge branch 'hotfix/v5.28.1-911/crashes' into 'release'
修复部分线上闪退

See merge request halo/android/assistant-android!1202
2023-07-17 11:53:17 +08:00
130a7cdf2a fix: 修复因为混淆造成的下载数据恢复闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/281841/?project=22 2023-07-17 11:08:11 +08:00
164ec0c368 fix: 捕抓首页 tab 的 roundToInt 闪退异常 2023-07-17 11:07:11 +08:00
991bd22511 Merge branch 'fix/sensors_log' into 'release'
fix: 修复畅玩助手下载弹窗错误上报安装点击事件的问题

See merge request halo/android/assistant-android!1199
2023-07-14 17:05:55 +08:00
df1ab5221d fix: 修复畅玩助手下载弹窗错误上报安装点击事件的问题 2023-07-14 16:41:51 +08:00
226d6c4f2c chore: 版本更新至 5.28.1 2023-07-13 17:25:06 +08:00
896adc9d36 Merge branch 'feature-data-watcher-patch' into 'release'
fix: Sentry312134...

See merge request halo/android/assistant-android!1198
2023-07-13 15:35:48 +08:00
0e33abebdd fix: Sentry312134... 2023-07-13 15:35:48 +08:00
c8ed126605 Merge branch 'fix/GHZS-2926' into 'release'
fix:【光环助手】游戏单封面图显示问题 https://jira.shanqu.cc/browse/GHZS-2926

See merge request halo/android/assistant-android!1196
2023-07-12 14:48:17 +08:00
b510a329b6 fix:【光环助手】游戏单封面图显示问题 https://jira.shanqu.cc/browse/GHZS-2926 2023-07-12 14:36:38 +08:00
2de1ba4e1d Merge branch 'fix/GHZS-2907' into 'release'
fix: 神策埋点—07/10测试 (3) https://jira.shanqu.cc/browse/GHZS-2907

See merge request halo/android/assistant-android!1195
2023-07-11 15:37:47 +08:00
e4a0f0e68b fix: 神策埋点—07/10测试 (3) https://jira.shanqu.cc/browse/GHZS-2907 2023-07-11 15:31:44 +08:00
c064f9d3a6 Merge branch 'feat/core_event_with_toast' into 'release'
fix: 特殊包上报比例为 1 时关键行为进行 toast 提示(方便测试)

See merge request halo/android/assistant-android!1190
2023-07-11 13:52:00 +08:00
759401d9ae Merge branch 'fix/CWZS-91' into 'release'
fix: 推送更新测试问题—测试问题07/06 https://jira.shanqu.cc/browse/CWZS-91

See merge request halo/android/assistant-android!1191
2023-07-11 13:51:53 +08:00
e56209d15e fix: 处理弹窗 dismiss 问题 2023-07-11 13:38:59 +08:00
c466ff1f21 fix: 处理弹窗 dismiss 问题 2023-07-11 11:51:41 +08:00
e09cf299f0 Merge branch 'feature-GHZS-2771-patch-3' into 'release'
fix: 支持xapk格式的apks文件解压-0706测试

See merge request halo/android/assistant-android!1193
2023-07-11 10:40:24 +08:00
25352ba609 fix: 支持xapk格式的apks文件解压-0706测试 2023-07-11 10:40:24 +08:00
3cd065cb6e fix: 处理弹窗 dismiss 问题 2023-07-10 16:21:01 +08:00
919a98ffe6 fix: 处理弹窗 dismiss 问题 2023-07-10 11:26:22 +08:00
eff84218a8 fix: 特殊包上报比例为 1 时关键行为进行 toast 提示(方便测试) 2023-07-07 11:32:44 +08:00
7c9c363422 fix: 推送更新测试问题—测试问题07/06 https://jira.shanqu.cc/browse/CWZS-91 2023-07-07 10:04:41 +08:00
8b1a38214c Merge branch 'feature-GHZS-2771-patch-2' into 'release'
feat: 支持xapk格式的apks文件解压—0705测试

See merge request halo/android/assistant-android!1185
2023-07-06 09:47:32 +08:00
2acde0af00 feat: 支持xapk格式的apks文件解压—0705测试 2023-07-06 09:47:32 +08:00
201c1207f9 Merge branch 'feature-GHZS-2771-patch-1' into 'release'
feat: 支持xapk格式的apks文件解压—0704测试

See merge request halo/android/assistant-android!1183
2023-07-05 14:24:55 +08:00
75d86b5a91 feat: 支持xapk格式的apks文件解压—0704测试 2023-07-05 14:24:55 +08:00
7976355e34 Merge branch 'release' into 'dev'
Release

See merge request halo/android/assistant-android!1178
2023-07-04 14:41:38 +08:00
a9097793ac Merge branch 'feature-forum-tag-icon-not-display' into 'release'
fix: 修复社区-推荐列表项论坛入口图标不显示以及点击无反应的问题

See merge request halo/android/assistant-android!1177
2023-07-04 13:38:53 +08:00
86e4ddd3f7 fix: 修复社区-推荐列表项论坛入口图标不显示以及点击无反应的问题 2023-07-04 12:45:53 +08:00
8312d8e5fe Merge branch 'feature-GHZS-2771-patch' into 'dev'
feat:支持xapk格式的apks文件解压—0620测试 https://jira.shanqu.cc/browse/GHZS-2771

See merge request halo/android/assistant-android!1174
2023-07-04 10:34:40 +08:00
98b4901d55 feat:支持xapk格式的apks文件解压—0620测试 https://jira.shanqu.cc/browse/GHZS-2771 2023-07-04 10:34:40 +08:00
8555673d71 Merge branch 'feat/GHZS-2797' into 'dev'
feat: 推广打包配置项增加关键行为上报 https://jira.shanqu.cc/browse/GHZS-2797

See merge request halo/android/assistant-android!1170
2023-06-30 17:43:55 +08:00
cfe4c243e6 feat: 推广打包配置项增加关键行为上报 https://jira.shanqu.cc/browse/GHZS-2797 2023-06-30 17:30:18 +08:00
c999ddf914 Merge branch 'fix/GHZS-2818' into 'dev'
fix: 【光环助手】神策埋点问题(1) https://jira.shanqu.cc/browse/GHZS-2818

See merge request halo/android/assistant-android!1169
2023-06-30 17:03:53 +08:00
f9004bf884 fix: 【光环助手】神策埋点问题(1) https://jira.shanqu.cc/browse/GHZS-2818 2023-06-30 16:50:29 +08:00
7794ef4acf fix: 【光环助手】神策埋点问题(1) https://jira.shanqu.cc/browse/GHZS-2818 2023-06-30 16:05:51 +08:00
1ef9c1fc23 Merge branch 'fix/vgame_download_flicker' into 'dev'
fix: 修复列表下载畅玩游戏时下载按钮闪烁并频繁切换状态的问题

See merge request halo/android/assistant-android!1166
2023-06-30 15:48:54 +08:00
2561767b9a Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/download/DownloadManager.java
#	dependencies.gradle
#	module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java
2023-06-30 14:34:01 +08:00
8bda0e178e Merge branch 'fix/GHZS-2818' into 'dev'
fix: 【光环助手】神策埋点问题(1) https://jira.shanqu.cc/browse/GHZS-2818

See merge request halo/android/assistant-android!1167
2023-06-30 14:10:27 +08:00
1dcc7654e8 Merge branch 'fix/wrong_game_category' into 'dev'
fix: 更正游戏类型在 downloadEntity 的记录

See merge request halo/android/assistant-android!1168
2023-06-30 11:54:34 +08:00
3579b9d808 fix: 更正游戏类型在 downloadEntity 的记录 2023-06-30 11:51:38 +08:00
c74663c082 fix: 【光环助手】神策埋点问题(1) https://jira.shanqu.cc/browse/GHZS-2818 2023-06-30 11:35:36 +08:00
848d352c60 fix: 【光环助手】神策埋点问题(1) https://jira.shanqu.cc/browse/GHZS-2818 2023-06-30 10:20:53 +08:00
5176766b29 fix: 修复列表下载畅玩游戏时下载按钮闪烁并频繁切换状态的问题 2023-06-30 10:10:47 +08:00
12cb9a4883 Merge branch 'fix/CWZS-86' into 'dev'
fix: 修复推送更新测试问题 https://jira.shanqu.cc/browse/CWZS-86

See merge request halo/android/assistant-android!1164
2023-06-29 14:08:18 +08:00
a30cc8c273 fix: 修复推送更新测试问题 https://jira.shanqu.cc/browse/CWZS-86 2023-06-29 13:55:19 +08:00
0f0620586b Merge branch 'fix/GHZS-2516' into 'dev'
fix: 【光环助手】神策首次事件取值的相关排查 (修复用户首次启动退出后再次热启动时用户第一次打开的标记仍为true的问题)...

See merge request halo/android/assistant-android!1163
2023-06-28 15:20:24 +08:00
b9e86dd67a fix: 【光环助手】神策首次事件取值的相关排查 (修复用户首次启动退出后再次热启动时用户第一次打开的标记仍为true的问题) https://jira.shanqu.cc/browse/GHZS-2516 2023-06-28 14:47:07 +08:00
9ce793d47e Merge branch 'fix/GHZS-2561' into 'dev'
fix:【光环助手】动态设置-公告文章支持通用链接(修改接口字段的处理方式)https://jira.shanqu.cc/browse/GHZS-2561

See merge request halo/android/assistant-android!1162
2023-06-28 11:31:37 +08:00
43cb18d6e0 fix:【光环助手】动态设置-公告文章支持通用链接(修改接口字段的处理方式)https://jira.shanqu.cc/browse/GHZS-2561 2023-06-28 11:26:42 +08:00
843aa4d1c8 Merge branch 'fix/format_check_crash' into 'dev'
fix: 处理 XAPK 类型检测闪退问题

See merge request halo/android/assistant-android!1161
2023-06-27 18:15:41 +08:00
1745ac91b7 fix: 处理 XAPK 类型检测闪退问题 2023-06-27 16:43:36 +08:00
20bc4a0dc8 Merge branch 'fix/direct_to_gamedetail_without_entrance_issue' into 'dev'
fix: 修复部分位置跳转游戏详情丢失 entrance 字段信息的问题

See merge request halo/android/assistant-android!1160
2023-06-27 15:20:48 +08:00
1105f1b92a feat: 测试包默认开启畅玩功能 2023-06-27 15:20:34 +08:00
53f00f00d3 fix: 修复部分位置跳转游戏详情丢失 entrance 字段信息的问题 2023-06-27 15:12:29 +08:00
330bcd72d7 Merge branch 'fix/concurrent_crash' into 'dev'
fix: 处理部分下载相关的 concurrent 闪退

See merge request halo/android/assistant-android!1157
2023-06-26 17:20:41 +08:00
b04231772b fix: 处理部分下载相关的 concurrent 闪退 2023-06-26 17:10:13 +08:00
ec1bbdc7d5 Merge branch 'feature-GHZS-2771' into 'dev'
feat:支持xapk格式的apks文件解压—0620测试 https://jira.shanqu.cc/browse/GHZS-2771

See merge request halo/android/assistant-android!1155
2023-06-26 16:48:30 +08:00
c685a02653 feat:支持xapk格式的apks文件解压—0620测试 https://jira.shanqu.cc/browse/GHZS-2771 2023-06-26 16:48:30 +08:00
6594bf14df Revert "Revert "Merge branch 'fix/sqlite_full_crash' into 'dev'""
This reverts commit 043f3c5d17.
2023-06-21 15:22:09 +08:00
655380d547 Merge branch 'hotfix/v5.27.1-891/cloud_archive_manager_crash' into 'release'
fix: 修复云存档管理页面点击下载按钮偶发的闪退问题...

See merge request halo/android/assistant-android!1153
2023-06-21 11:48:12 +08:00
da3948228f chore: 版本更新至 5.27.2 2023-06-21 11:39:33 +08:00
5c03119c32 fix: 修复云存档管理页面点击下载按钮偶发的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/289025/events/ba71db5b3538491fa2096ecf33fdfcf8/?project=22 2023-06-21 11:38:53 +08:00
2a496b680b Merge branch 'hotfix/v5.27.1-891/emulator_oaid_crash' into 'release'
fix: 修复模拟器上 OAID SDK 闪退的问题,在所有 postInit 操作前初始化 sentry

See merge request halo/android/assistant-android!1152
2023-06-21 11:26:36 +08:00
db535cf281 fix: 修复模拟器上 OAID SDK 闪退的问题,在所有 postInit 操作前初始化 sentry 2023-06-21 11:20:25 +08:00
c199582efc Merge branch 'hotfix/v5.27.1-891/emulator_oaid_crash' into 'release'
fix: 修复模拟器上 OAID SDK 闪退的问题

See merge request halo/android/assistant-android!1151
2023-06-21 11:02:06 +08:00
b53677a118 fix: 修复模拟器上 OAID SDK 闪退的问题 2023-06-21 10:56:24 +08:00
043f3c5d17 Revert "Merge branch 'fix/sqlite_full_crash' into 'dev'"
This reverts merge request !1147
2023-06-20 18:00:56 +08:00
68006dda38 Merge branch 'feature-GHZS-2754' into 'release'
fix:尝试修复部分线上闪退 https://jira.shanqu.cc/browse/GHZS-2754

See merge request halo/android/assistant-android!1149
2023-06-20 17:24:57 +08:00
b5cab193be fix:尝试修复部分线上闪退 https://jira.shanqu.cc/browse/GHZS-2754 2023-06-20 17:24:57 +08:00
6f2692296c Merge branch 'fix/sqlite_full_crash' into 'dev'
fix: 处理存储空间满了后的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/197777/?project=22&query=assigned%3Ame+status%3Aunresolved&sort=user&statsPeriod=14d

See merge request halo/android/assistant-android!1147
2023-06-20 17:16:25 +08:00
0bb7a53046 Merge branch 'fix/game_collection_hot_list' into 'dev'
fix: 修复游戏单热榜的游戏单宽度不能自适应的问题

See merge request halo/android/assistant-android!1146
2023-06-20 15:51:08 +08:00
25fe362912 fix: 修复游戏单热榜的游戏单宽度不能自适应的问题 2023-06-20 15:49:33 +08:00
6749d94c34 fix: 处理存储空间满了后的闪退问题 2023-06-20 15:25:54 +08:00
51f5ea1cd9 Merge branch 'fix/CWZS-85' into 'dev'
fix: 畅玩助手组件下载链接失效问题 https://jira.shanqu.cc/browse/CWZS-85

See merge request halo/android/assistant-android!1145
2023-06-20 14:08:55 +08:00
50a6d5e204 fix: 畅玩助手组件下载链接失效问题 https://jira.shanqu.cc/browse/CWZS-85 2023-06-20 14:02:33 +08:00
044e5646ec Merge branch 'fix/GHZS-2641' into 'dev'
fix: 游戏单功能优化-游戏单广场—0606测试 (修复正式包刷新轮换失效的问题) https://jira.shanqu.cc/browse/GHZS-2641

See merge request halo/android/assistant-android!1144
2023-06-20 11:23:35 +08:00
0ebf3d191d fix: 游戏单功能优化-游戏单广场—0606测试 (修复正式包刷新轮换失效的问题) https://jira.shanqu.cc/browse/GHZS-2641 2023-06-20 11:05:49 +08:00
bb81d91fd5 Merge branch 'release' of git.shanqu.cc:halo/android/assistant-android into release 2023-06-20 10:32:53 +08:00
7442da80e0 Merge branch 'fix/GHZS-2753' into 'dev'
fix: 尝试修复部分线上闪退 https://jira.shanqu.cc/browse/GHZS-2753

See merge request halo/android/assistant-android!1142
2023-06-19 17:00:54 +08:00
96c28907ec Merge branch 'feature-GHZS-2758' into 'dev'
fix:支持xapk格式的apks文件解压—0619测试 https://jira.shanqu.cc/browse/GHZS-2758

See merge request halo/android/assistant-android!1143
2023-06-19 16:52:03 +08:00
e9e7c2043e fix:支持xapk格式的apks文件解压—0619测试 https://jira.shanqu.cc/browse/GHZS-2758 2023-06-19 16:52:03 +08:00
eb5c55f046 ci: 处理特殊打包的编译问题 2023-06-19 16:32:29 +08:00
8f2a1ecaa1 fix: 尝试修复部分线上闪退 https://jira.shanqu.cc/browse/GHZS-2753 2023-06-19 16:31:49 +08:00
8dbe9c5772 Merge branch 'fix/border_color' into 'dev'
fix: 修改玩家创作榜用户头像边框深色模式颜色

See merge request halo/android/assistant-android!1141
2023-06-19 14:14:09 +08:00
6c911e09d3 fix: 修改玩家创作榜用户头像边框深色模式颜色 2023-06-19 14:13:26 +08:00
df557099ec Merge branch 'fix/GHZS-2717' into 'dev'
fix: 搭建评论数据面板—0615测试(修复部分上报位置遗漏问题) https://jira.shanqu.cc/browse/GHZS-2717

See merge request halo/android/assistant-android!1140
2023-06-19 14:09:40 +08:00
fedc91d37e fix: 搭建评论数据面板—0615测试(修复部分上报位置遗漏问题) https://jira.shanqu.cc/browse/GHZS-2717 2023-06-19 13:57:13 +08:00
27484a8306 Merge branch 'fix/GHZS-2752' into 'dev'
fix: 游戏单功能优化-游戏单热榜-前端部分—0619UI优化 https://jira.shanqu.cc/browse/GHZS-2752

See merge request halo/android/assistant-android!1139
2023-06-19 10:36:22 +08:00
42193d222a fix: 游戏单功能优化-游戏单热榜-前端部分—0619UI优化 https://jira.shanqu.cc/browse/GHZS-2752 2023-06-19 10:34:40 +08:00
ff02ccd839 Merge remote-tracking branch 'origin/dev' into dev-5.28.0 2023-06-19 09:51:15 +08:00
d1cc0853d4 Merge branch 'fix/vgame_backup_issue' into 'dev-5.28.0'
fix: 修复部分设备卸载重装后无法恢复畅玩历史数据的问题

See merge request halo/android/assistant-android!1138
2023-06-19 09:40:46 +08:00
51eb814a42 fix: 修复部分设备卸载重装后无法恢复畅玩历史数据的问题 2023-06-16 18:04:30 +08:00
6534c17cc0 Merge branch 'fix/GHZS-2641' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0606测试(修复筛选游戏单标签时请求接口缺少参数的问题) https://jira.shanqu.cc/browse/GHZS-2641

See merge request halo/android/assistant-android!1137
2023-06-16 16:57:54 +08:00
749a76a09e fix: 游戏单功能优化-游戏单广场—0606测试(修复筛选游戏单标签时请求接口缺少参数的问题) https://jira.shanqu.cc/browse/GHZS-2641 2023-06-16 14:53:04 +08:00
0f59f79495 Merge branch 'fix/GHZS-2744' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单热榜-前端部分—0616UI测试 https://jira.shanqu.cc/browse/GHZS-2744

See merge request halo/android/assistant-android!1136
2023-06-16 14:50:31 +08:00
af66a967b5 fix: 游戏单功能优化-游戏单热榜-前端部分—0616UI测试 https://jira.shanqu.cc/browse/GHZS-2744 2023-06-16 14:39:30 +08:00
9a9095bcf0 Merge branch 'feature-GHZS-2456-patch' into 'dev-5.28.0'
feat:补充支持xapk格式的apks一些需求 https://jira.shanqu.cc/browse/GHZS-2456

See merge request halo/android/assistant-android!1133
2023-06-16 13:51:35 +08:00
225f2becf3 feat:补充支持xapk格式的apks一些需求 https://jira.shanqu.cc/browse/GHZS-2456 2023-06-16 13:51:35 +08:00
a502fb64cb Merge branch 'fix/GHZS-2714' into 'dev-5.28.0'
feat: 启动事件埋点补充—0615测试(处理部分游戏类型为空情况) https://jira.shanqu.cc/browse/GHZS-2714

See merge request halo/android/assistant-android!1130
2023-06-16 10:26:41 +08:00
724fe8142c feat: 启动事件埋点补充—0615测试(处理部分游戏类型为空情况,但还需接口返回) https://jira.shanqu.cc/browse/GHZS-2714 2023-06-16 10:16:37 +08:00
dee5a0822d Merge branch 'fix/GHZS-2689' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0614测试 (0615测试) https://jira.shanqu.cc/browse/GHZS-2689

See merge request halo/android/assistant-android!1128
2023-06-16 09:51:43 +08:00
e826346ca9 Merge branch 'fix/GHZS-2685' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单热榜-前端部分—0614测试-客户端 (0615测试) https://jira.shanqu.cc/browse/GHZS-2685

See merge request halo/android/assistant-android!1129
2023-06-16 09:51:35 +08:00
06b43cde77 fix: 游戏单功能优化-游戏单广场—0614测试 (0615测试) https://jira.shanqu.cc/browse/GHZS-2689 2023-06-16 09:45:35 +08:00
ae5edad87b fix: 游戏单功能优化-游戏单热榜-前端部分—0614测试-客户端 (0615测试) https://jira.shanqu.cc/browse/GHZS-2685 2023-06-16 09:35:28 +08:00
c8916f5f33 Merge branch 'fix/GHZS-2641' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0606测试 https://jira.shanqu.cc/browse/GHZS-2641

See merge request halo/android/assistant-android!1127
2023-06-15 18:10:53 +08:00
04cca95435 Merge branch 'feature-update-lgl-library' into 'dev-5.28.0'
feat:更新LGLibrary指向

See merge request halo/android/assistant-android!1126
2023-06-15 17:52:55 +08:00
1bd3d8b044 feat:更新LGLibrary指向 2023-06-15 17:52:19 +08:00
4e79466cca fix: 游戏单功能优化-游戏单广场—0606测试 https://jira.shanqu.cc/browse/GHZS-2641 2023-06-15 17:40:20 +08:00
88093d0a8e Merge branch 'feature-GHZS-2456' into 'dev-5.28.0'
feat:支持xapk格式的apks文件解压—客户端 https://jira.shanqu.cc/browse/GHZS-2456

See merge request halo/android/assistant-android!1124
2023-06-15 17:06:10 +08:00
26adcc48f8 feat:支持xapk格式的apks文件解压—客户端 https://jira.shanqu.cc/browse/GHZS-2456 2023-06-15 17:06:10 +08:00
e94e86d901 Merge branch 'fix/GHZS-2472' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单热榜-前端部分—0614测试-客户端 https://jira.shanqu.cc/browse/GHZS-2685

See merge request halo/android/assistant-android!1125
2023-06-15 15:45:46 +08:00
73355a4103 fix: 游戏单功能优化-游戏单热榜-前端部分—0614测试-客户端 https://jira.shanqu.cc/browse/GHZS-2685
fix: 游戏单功能优化-游戏单热榜-前端部分—0614UI测试 https://jira.shanqu.cc/browse/GHZS-2686
2023-06-15 15:33:21 +08:00
794377fdad fix: 游戏单功能优化-游戏单广场—0614测试 https://jira.shanqu.cc/browse/GHZS-2689 2023-06-15 14:31:33 +08:00
1bff098369 Merge branch 'feat/GHZS-2603' into 'dev-5.28.0'
fix: 修复曝光 id 的传递问题 https://jira.shanqu.cc/browse/GHZS-2603

See merge request halo/android/assistant-android!1123
2023-06-15 13:54:11 +08:00
45c7638dee fix: 修复曝光 id 的传递问题 https://jira.shanqu.cc/browse/GHZS-2603 2023-06-15 13:52:30 +08:00
4c57092300 Merge branch 'feat/GHZS-2622' into 'dev-5.28.0'
feat: 启动事件埋点补充 https://jira.shanqu.cc/browse/GHZS-2622

See merge request halo/android/assistant-android!1121
2023-06-15 13:47:59 +08:00
1ddf9a667e feat: 启动事件埋点补充 https://jira.shanqu.cc/browse/GHZS-2622 2023-06-15 10:42:08 +08:00
84972e7ba7 Merge branch 'fix/GHZS-2687' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0614UI优化 https://jira.shanqu.cc/browse/GHZS-2687

See merge request halo/android/assistant-android!1120
2023-06-14 15:00:41 +08:00
03692ad753 fix: 游戏单功能优化-游戏单广场—0614UI优化 https://jira.shanqu.cc/browse/GHZS-2687 2023-06-14 14:59:12 +08:00
bb138fa25f Merge branch 'fix/GHZS-2669' into 'dev-5.28.0'
fix: 多渠道多版本配置-搜索管理功能优化—0612测试-客户端 https://jira.shanqu.cc/browse/GHZS-2669

See merge request halo/android/assistant-android!1118
2023-06-14 14:33:41 +08:00
c5024e670a Merge branch 'fix/GHZS-2674' into 'dev-5.28.0'
fix: 【光环助手】求版本下载跳转问题 https://jira.shanqu.cc/browse/GHZS-2674

See merge request halo/android/assistant-android!1117
2023-06-14 14:33:29 +08:00
fe5c92e988 fix: 【光环助手】求版本下载跳转问题 https://jira.shanqu.cc/browse/GHZS-2674 2023-06-14 14:22:48 +08:00
9b31bf4164 fix: 多渠道多版本配置-搜索管理功能优化—0612测试-客户端 https://jira.shanqu.cc/browse/GHZS-2669 2023-06-14 11:37:25 +08:00
c670ab722f Merge branch 'fix/GHZS-2658' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0609测试 https://jira.shanqu.cc/browse/GHZS-2658

See merge request halo/android/assistant-android!1115
2023-06-13 15:14:39 +08:00
fd4f3c25e7 fix: 游戏单功能优化-游戏单广场—0609测试 https://jira.shanqu.cc/browse/GHZS-2658 2023-06-13 15:09:46 +08:00
a14ea3708a Merge branch 'fix/GHZS-2658' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0609测试 https://jira.shanqu.cc/browse/GHZS-2658

See merge request halo/android/assistant-android!1114
2023-06-13 14:57:25 +08:00
c003240f16 Merge branch 'fix/GHZS-2576' into 'dev-5.28.0'
fix: 修复游戏详情页在正式环境下的闪退问题

See merge request halo/android/assistant-android!1113
2023-06-13 14:57:18 +08:00
891e3d93fb fix: 游戏单功能优化-游戏单广场—0609测试 https://jira.shanqu.cc/browse/GHZS-2658 2023-06-13 14:48:31 +08:00
af5ec74b9e Merge branch 'feat/GHZS-2644' into 'dev-5.28.0'
feat: 搭建评论数据面板(补充埋点) https://jira.shanqu.cc/browse/GHZS-2644

See merge request halo/android/assistant-android!1112
2023-06-13 13:39:57 +08:00
d2c4483455 feat: 搭建评论数据面板(补充埋点) https://jira.shanqu.cc/browse/GHZS-2644 2023-06-13 11:47:21 +08:00
3a156aa8c1 fix: 修复游戏详情页在正式环境下的闪退问题 2023-06-13 11:03:23 +08:00
60bd3ee9b2 Merge branch 'feature/GHZS-2485' into 'dev-5.28.0'
feat: 游戏单功能优化-游戏单热榜-前端部分—客户端 https://jira.shanqu.cc/browse/GHZS-2485

See merge request halo/android/assistant-android!1111
2023-06-13 10:53:34 +08:00
dacda1a858 feat: 游戏单功能优化-游戏单热榜-前端部分—客户端 https://jira.shanqu.cc/browse/GHZS-2485 2023-06-13 10:53:34 +08:00
265b5f6b57 Merge branch 'feat/GHZS-2502' into 'dev-5.28.0'
feat: 我的光环在设备无网络时的功能版块优化 https://jira.shanqu.cc/browse/GHZS-2502

See merge request halo/android/assistant-android!1109
2023-06-12 10:30:56 +08:00
b4bd6f250b feat: 我的光环在设备无网络时的功能版块优化 https://jira.shanqu.cc/browse/GHZS-2502 2023-06-12 10:25:35 +08:00
0f3ae5f085 Merge branch 'fix/GHZS-2656' into 'dev-5.28.0'
fix: 游戏单功能优化-游戏单广场—0609UI测试 https://jira.shanqu.cc/browse/GHZS-2656

See merge request halo/android/assistant-android!1108
2023-06-09 17:03:43 +08:00
3ab6cc202e fix: 游戏单功能优化-游戏单广场—0609UI测试 https://jira.shanqu.cc/browse/GHZS-2656 2023-06-09 17:03:05 +08:00
7a154bc130 Merge branch 'feature/GHZS-2576' into 'dev-5.28.0'
feat: 动态设置-公告文章支持通用链接—客户端 https://jira.shanqu.cc/browse/GHZS-2576

See merge request halo/android/assistant-android!1106
2023-06-09 15:35:07 +08:00
7cd6f2b0f4 feat: 动态设置-公告文章支持通用链接—客户端 https://jira.shanqu.cc/browse/GHZS-2576 2023-06-09 14:20:13 +08:00
8db2519f61 Merge branch 'feature-GHZS-2590' into 'dev-5.28.0'
feat:帖子更多操作图标UI样式替换—客户端 https://jira.shanqu.cc/browse/GHZS-2590

See merge request halo/android/assistant-android!1102
2023-06-08 16:57:35 +08:00
6b2902a73b feat:帖子更多操作图标UI样式替换—客户端 https://jira.shanqu.cc/browse/GHZS-2590 2023-06-08 16:53:19 +08:00
df7618bbda Merge branch 'feature-GHZS-2626' into 'dev-5.28.0'
feat:【光环助手】视频帖详情页UI展示问题 https://jira.shanqu.cc/browse/GHZS-2626

See merge request halo/android/assistant-android!1100
2023-06-08 15:44:12 +08:00
246983a097 feat:【光环助手】视频帖详情页UI展示问题 https://jira.shanqu.cc/browse/GHZS-2626 2023-06-08 15:42:01 +08:00
ca6146ad9a Merge branch 'feature-GHZS-2649' into 'dev-5.28.0'
feat:【光环助手】游戏礼包相关bug https://jira.shanqu.cc/browse/GHZS-2649

See merge request halo/android/assistant-android!1097
2023-06-08 11:03:06 +08:00
c647320abc feat:【光环助手】游戏礼包相关bug https://jira.shanqu.cc/browse/GHZS-2649 2023-06-08 10:59:07 +08:00
afd738454e Merge branch 'feat/GHZS-2645' into 'dev-5.28.0'
feat: 新增畅玩32位游戏类型 https://jira.shanqu.cc/browse/GHZS-2637

See merge request halo/android/assistant-android!1093
2023-06-07 14:04:40 +08:00
134cb327ec feat: 新增畅玩32位游戏类型 https://jira.shanqu.cc/browse/GHZS-2637 2023-06-07 14:01:57 +08:00
f50ce741ae Merge branch 'dev' into 'dev-5.28.0'
Dev

See merge request halo/android/assistant-android!1092
2023-06-07 11:51:27 +08:00
4547ba969e Merge branch 'dev' into 'dev-5.28.0'
Dev

See merge request halo/android/assistant-android!1087
2023-06-06 16:53:05 +08:00
0a4af78ac8 Merge branch 'dev' into 'dev-5.28.0'
合并 dev 变更

See merge request halo/android/assistant-android!1084
2023-06-06 14:36:18 +08:00
d38e1d1637 Merge branch 'feature/GHZS-2476' into 'dev-5.28.0'
feat: 游戏单功能优化-游戏单广场—客户端 https://jira.shanqu.cc/browse/GHZS-2476

See merge request halo/android/assistant-android!1076
2023-06-05 17:07:28 +08:00
0d3456cf97 feat: 游戏单功能优化-游戏单广场—客户端 https://jira.shanqu.cc/browse/GHZS-2476 2023-06-05 17:00:56 +08:00
f56529aa5b chore: 版本更新至 5.28.0 2023-05-31 11:49:46 +08:00
240 changed files with 5923 additions and 1461 deletions

View File

@ -71,8 +71,7 @@ android_build:
exit_codes: 137
only:
- dev
- dev-5.26.0
- dev-5.27.0
- dev-5.28.0
# 代码检查
sonarqube_analysis:
@ -103,8 +102,7 @@ sonarqube_analysis:
exit_codes: 137
only:
- dev
- dev-5.26.0
- dev-5.27.0
- dev-5.28.0
## 发送简易检测结果报告
send_sonar_report:
@ -122,8 +120,7 @@ send_sonar_report:
exit_codes: 137
only:
- dev
- dev-5.26.0
- dev-5.27.0
- dev-5.28.0
oss-upload&send-email:
tags:
@ -155,5 +152,4 @@ oss-upload&send-email:
- /usr/local/bin/python /ci-android-mail.py
only:
- dev
- dev-5.26.0
- dev-5.27.0
- dev-5.28.0

View File

@ -11,7 +11,7 @@ android {
String CONFIG_ID = ""
String FIRST_LAUNCH = ""
int ACTIVATE_REPORTING_RATIO = 0
int ACTIVATE_REPORTING_RATIO = 100
buildFeatures {
viewBinding true
@ -71,6 +71,11 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
String CORE_EVENT_GAME_CATEGORY = ""
// 推广用的关键事件游戏类型
buildConfigField "String", "CORE_EVENT_GAME_CATEGORY", "\"${CORE_EVENT_GAME_CATEGORY}\""
// 推广用的配置 id
buildConfigField "String", "CONFIG_ID", "\"${CONFIG_ID}\""
@ -334,6 +339,7 @@ dependencies {
implementation(project(':feature:oaid'))
implementation(project(':feature:floating-window'))
implementation(project(':feature:beizi_startup_ad'))
implementation(project(':feature:xapk-installer'))
}
File propFile = file('sign.properties')

View File

@ -33,4 +33,8 @@ class FlavorProviderImp : IFlavorProvider {
override fun logEvent(content: String) {
// do nothing
}
override fun logCoreEvent() {
// do nothing
}
}

View File

@ -42,6 +42,10 @@ class FlavorProviderImp : IFlavorProvider {
GdtHelper.logAction(content)
}
override fun logCoreEvent() {
// do nothing
}
companion object {
private const val GDT_DEFAULT_CHANNEL = "GDT_GHZS_01"
}

View File

@ -3,10 +3,13 @@ package com.gh.gamecenter.provider
import android.app.Activity
import android.app.Application
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.KuaishouHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.kwai.monitor.payload.TurboHelper
@ -42,6 +45,15 @@ class FlavorProviderImp : IFlavorProvider {
KuaishouHelper.onEvent(content)
}
override fun logCoreEvent() {
logEvent("EVENT_KEY_PATH_OPTIMIZATION")
if (BuildConfig.ACTIVATE_REPORTING_RATIO == 1) {
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast("关键行为 EVENT_KEY_PATH_OPTIMIZATION")
}, 500)
}
}
companion object {
private const val KUAISHOU_CHANNEL = "KS-GHZS-01"
}

View File

@ -106,8 +106,8 @@
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:largeHeap="true"
android:resizeableActivity="true"
android:networkSecurityConfig="@xml/network_security_config"
android:resizeableActivity="true"
android:theme="@style/AppCompatTheme.APP"
tools:replace="android:name,android:allowBackup"
tools:targetApi="n">
@ -756,6 +756,10 @@
android:name=".servers.gametest2.GameServerTestV2Activity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity"
android:screenOrientation="portrait" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
@ -826,6 +830,11 @@
</intent-filter>
</receiver>
<activity
android:name="com.gh.common.xapk.XapkInstallReceiver"
android:theme="@style/Theme.Transparent"
android:exported="false" />
<receiver
android:name="com.gh.gamecenter.receiver.ActivitySkipReceiver"
android:exported="true">

View File

@ -0,0 +1 @@
{"v":"5.9.1","fr":60,"ip":0,"op":60,"w":144,"h":144,"nm":"icon_change","ddd":0,"assets":[{"id":"comp_0","nm":"icon_change_detail","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"stroke1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[37.04,52.994,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.533,-0.143],[0.143,-0.533],[1.487,-1.304],[1.961,-0.258],[1.774,0.875],[0.709,0.661],[0,0],[0,0.445],[0,0],[-0.276,0],[0,0],[-0.013,0],[0,0],[0.315,-0.315],[0,0],[-0.682,-0.336],[-1.569,0.207],[-1.19,1.043],[-0.41,1.528]],"o":[[0.533,0.143],[-0.512,1.91],[-1.487,1.304],[-1.961,0.258],[-0.879,-0.433],[0,0],[-0.315,0.315],[0,0],[0,-0.276],[0,0],[0.013,0],[0,0],[0.445,0],[0,0],[0.555,0.508],[1.419,0.7],[1.569,-0.207],[1.19,-1.043],[0.143,-0.533]],"v":[[8.605,-4.301],[9.312,-3.076],[6.247,1.854],[0.958,4.25],[-4.77,3.304],[-7.163,1.652],[-8.493,2.982],[-9.347,2.628],[-9.347,-1.665],[-8.847,-2.165],[-8.161,-2.165],[-8.122,-2.165],[-4.554,-2.165],[-4.2,-1.311],[-5.748,0.237],[-3.885,1.51],[0.697,2.267],[4.928,0.35],[7.381,-3.594]],"c":true},"ix":2},"nm":"stroke1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.8,1,0.6],"ix":9}},"s":{"a":0,"k":[-5.347,-4.665],"ix":5},"e":{"a":0,"k":[8.653,-4.665],"ix":6},"t":1,"nm":"color1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"stroke1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"stroke2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[34.96,19.006,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.961,0.258],[-1.774,-0.875],[-0.709,-0.661],[0,0],[0,-0.445],[0,0],[0.276,0],[0,0],[0.012,0],[0,0],[-0.315,0.315],[0,0],[0.682,0.336],[1.569,-0.207],[1.19,-1.043],[0.41,-1.528],[0.533,0.143],[-0.143,0.533],[-1.487,1.304]],"o":[[1.961,-0.258],[0.879,0.433],[0,0],[0.315,-0.315],[0,0],[0,0.276],[0,0],[-0.012,0],[0,0],[-0.445,0],[0,0],[-0.555,-0.508],[-1.419,-0.7],[-1.569,0.207],[-1.19,1.043],[-0.143,0.533],[-0.533,-0.143],[0.512,-1.91],[1.487,-1.304]],"v":[[-0.958,-4.25],[4.77,-3.304],[7.163,-1.652],[8.493,-2.982],[9.347,-2.628],[9.347,1.665],[8.847,2.165],[8.16,2.165],[8.123,2.165],[4.554,2.165],[4.2,1.311],[5.748,-0.237],[3.885,-1.51],[-0.697,-2.267],[-4.928,-0.35],[-7.381,3.594],[-8.605,4.301],[-9.312,3.076],[-6.247,-1.854]],"c":true},"ix":2},"nm":"stroke2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.8,1,0.6],"ix":9}},"s":{"a":0,"k":[5.347,4.665],"ix":5},"e":{"a":0,"k":[-8.653,4.665],"ix":6},"t":1,"nm":"color2","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"stroke2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"icon_change_detail","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"t":36,"s":[360]}],"ix":10},"p":{"a":0,"k":[72,72,0],"ix":2,"l":2},"a":{"a":0,"k":[36,36,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":72,"h":72,"ip":0,"op":300,"st":0,"bm":0}],"markers":[]}

View File

@ -5,6 +5,7 @@ import android.app.Application
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.util.FloatingBackViewManager
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.SingletonWebActivity
import com.gh.gamecenter.SkipActivity
@ -61,6 +62,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
) {
VHelper.showFeedbackDialogIfLastSuccessfulLaunchedGameExitUnexpectedly(activity)
}
XapkInstaller.updateCurrentInstallStatus()
}
override fun onActivityPaused(activity: Activity) {

View File

@ -213,7 +213,7 @@ class DefaultJsApi(
VHelper.launch(context, packageName)
}
} else {
PackageUtils.launchApplicationByPackageName(context, packageName)
PackageLauncher.launchApp(context, packageName = packageName)
}
}
}

View File

@ -20,7 +20,7 @@ object FixedRateJobHelper {
private const val CHECKER_PERIOD: Long = 15 * 1000L
private const val TIME_PERIOD: Long = 10 * 60 * 1000L
private const val LOGHUB_PERIOD: Long = 2 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 5 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 1 * 60 * 1000L
private const val REGION_SETTING_PERIOD: Long = 60 * 1000L
private const val VIDEO_RECORD_PERIOD: Long = 60 * 1000L

View File

@ -1,6 +1,7 @@
package com.gh.common.chain
import android.content.Context
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.feature.entity.GameEntity
@ -8,14 +9,15 @@ import com.gh.gamecenter.feature.entity.GameEntity
class BrowserInstallHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
BrowserInstallHelper.showBrowserInstallHintDialog(context, gameEntity.isVGame(), object : EmptyCallback {
override fun onCallback() {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
BrowserInstallHelper.showBrowserInstallHintDialog(
context,
gameEntity.isVGame() || gameEntity.isSplitXApk()
) {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
})
}
}
}

View File

@ -0,0 +1,27 @@
package com.gh.common.chain
import android.content.Context
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.feature.entity.GameEntity
class UnsupportedFeatureHandler : ChainHandler() {
override fun handleRequest(
context: Context, gameEntity: GameEntity
) {
if (shouldShowUnsupportedFeatureDialog()) {
DialogHelper.showUnsupportedFeatureDialog(context)
} else {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}
/**
* TODO 检查某个版本是否支持指定的功能
*/
private fun shouldShowUnsupportedFeatureDialog(): Boolean = false
}

View File

@ -205,9 +205,6 @@ public class Config {
// 加载完设置后刷新下
PackageHelper.initList();
// 初始化畅玩相关的东西
VHelper.init(HaloApp.getInstance());
}
@Nullable
@ -308,6 +305,26 @@ public class Config {
return mVSetting;
}
/**
* 请求网络数据,尝试刷新畅玩相关配置
*/
@SuppressLint("CheckResult")
public static void refreshVSettingEntity() {
RetrofitManager.getInstance()
.getVApi().getSettings(BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<VSetting>() {
@Override
public void onSuccess(VSetting data) {
mVSetting = data;
SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
VHelper.init(HaloApp.getInstance());
}
});
}
@Nullable
public static GameGuidePopupEntity getGameGuidePopupEntity() {
return mGameGuidePopupEntity;
@ -385,16 +402,7 @@ public class Config {
}
});
RetrofitManager.getInstance()
.getVApi().getSettings(BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.subscribe(new BiResponse<VSetting>() {
@Override
public void onSuccess(VSetting data) {
mVSetting = data;
SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
}
});
refreshVSettingEntity();
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)

View File

@ -1,5 +1,6 @@
package com.gh.common.databind;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
@ -29,6 +30,7 @@ import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.OverseaDownloadHandler;
import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.chain.ValidateVSpaceHandler;
import com.gh.common.chain.VersionNumberHandler;
import com.gh.common.constant.Config;
@ -45,10 +47,12 @@ import com.gh.common.util.GameViewUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageLauncher;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.download.server.BrowserInstallHelper;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -63,6 +67,7 @@ import com.gh.gamecenter.common.view.DrawableView;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.NumberUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.databinding.KaifuDetailItemRowBinding;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.CommunityVideoEntity;
@ -398,6 +403,7 @@ public class BindingAdapters {
}
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new GamePermissionHandler());
builder.addHandler(new CheckStoragePermissionHandler());
builder.addHandler(new ValidateVSpaceHandler());
@ -410,7 +416,7 @@ public class BindingAdapters {
builder.addHandler(new CheckDownloadHandler());
builder.setProcessEndCallback(o -> {
download(progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
download(v.getContext(), progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
return null;
});
final ChainHandler chainHandler = builder.buildHandlerChain();
@ -419,6 +425,7 @@ public class BindingAdapters {
}
} else {
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new GamePermissionHandler());
builder.addHandler(new CertificationHandler());
builder.addHandler(new VersionNumberHandler());
@ -447,7 +454,7 @@ public class BindingAdapters {
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
download(progressBar, gameEntity, traceEvent, false, entrance, location);
download(v.getContext(), progressBar, gameEntity, traceEvent, false, entrance, location);
return;
}
@ -457,11 +464,11 @@ public class BindingAdapters {
}
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity);
VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity, null);
return;
}
PackageUtils.launchApplicationByPackageName(v.getContext(), gameEntity.getApk().get(0).getPackageName());
PackageLauncher.launchApp(v.getContext(), gameEntity, gameEntity.getApk().get(0).getPackageName());
} else {
DownloadDialog.showDownloadDialog(
v.getContext(),
@ -477,7 +484,7 @@ public class BindingAdapters {
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
if (gameEntity.isVGame()) {
VHelper.installOrLaunch(v.getContext(), gameEntity);
VHelper.installOrLaunch(v.getContext(), gameEntity, null);
return;
}
@ -673,12 +680,16 @@ public class BindingAdapters {
// 开始下载
private static void download(DownloadButton progressBar,
private static void download(Context context,
DownloadButton progressBar,
GameEntity gameEntity,
ExposureEvent traceEvent,
boolean isSubscribe,
String entrance,
String location) {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint));
}
String str = progressBar.getText().toString();
String method;
if (str.contains("更新")) {

View File

@ -48,6 +48,7 @@ object ExposureUtils {
}
if (!TextUtils.isEmpty(entity.id)) {
ExposureManager.log(exposureEvent)
ExposureManager.commitSavedExposureEvents(forcedUpload = true)
}
return exposureEvent
}

View File

@ -0,0 +1,119 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.provider.IDownloadButtonClickedProvider
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.packagehelper.PackageRepository
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
@Route(path = RouteConsts.provider.downloadButtonClickedHandler, name = "DownloadButton点击事件暴露服务")
class DownloadButtonClickedProviderImpl : IDownloadButtonClickedProvider {
override fun onClicked(downloadButton: DownloadButton) {
var gameId = ""
var gameName = ""
var gameCategory = ""
var gameTypeInChinese = ""
var downloadStatus = ""
var downloadStatusInChinese = ""
var gameSchemaType = ""
var packageName = ""
val boundedObject = downloadButton.getObject()
Utils.log("DownloadButtonClickedProviderImpl", "$downloadButton onClicked ${boundedObject?.javaClass}")
if (boundedObject != null) {
when (boundedObject) {
is GameEntity -> {
gameId = boundedObject.id
gameName = boundedObject.name ?: ""
gameCategory = boundedObject.category ?: ""
downloadStatus = if (boundedObject.isVGame()) {
"畅玩"
} else if (boundedObject.downloadStatus == "demo") {
"试玩"
} else {
"下载"
}
gameTypeInChinese = boundedObject.categoryChinese
downloadStatusInChinese = boundedObject.downloadStatusChinese
gameSchemaType = boundedObject.gameBitChinese
packageName = boundedObject.getUniquePackageName() ?: ""
}
is GameUpdateEntity -> {
gameId = boundedObject.id
gameName = boundedObject.name ?: ""
// 下载管理-更新页面,把下载状态都置为下载
downloadStatus = "下载"
gameTypeInChinese = boundedObject.categoryChinese
downloadStatusInChinese = boundedObject.downloadStatusChinese
packageName = boundedObject.packageName
}
is DownloadEntity -> {
gameId = boundedObject.gameId
gameName = boundedObject.name ?: ""
gameCategory = boundedObject.getGameCategory()
downloadStatus = if (boundedObject.isVGame()) "畅玩" else "下载"
packageName = boundedObject.packageName
}
}
// 上报 UI 状态为启动的点击事件 (样式为启动,或者文案包含启动都算能启动)
if (downloadButton.buttonStyle == DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
|| downloadButton.text.contains("启动")) {
// boundedObject 里找不到游戏类型时,尝试从已安装列表中获取
if (gameCategory.isEmpty() && packageName.isNotEmpty()) {
gameCategory = PackageRepository.gameInstalled.find { it.packageName == packageName }?.category ?: ""
}
NewFlatLogUtils.logGameLaunchButtonClicked(
gameId = gameId,
gameName = gameName,
location = downloadButton.getWidgetBusinessName(),
gameCategory = gameCategory,
downloadStatus = downloadStatus
)
}
// 预约状态不上报
if (downloadButton.buttonStyle != DownloadButton.ButtonStyle.RESERVABLE
&& downloadButton.buttonStyle != DownloadButton.ButtonStyle.RESERVED
) {
// 上报神策点击事件
SensorsBridge.trackEvent(
"DownLoadbuttonClick",
"game_id", gameId,
"game_name", gameName,
"game_type", gameTypeInChinese,
"download_status", downloadStatusInChinese,
"button_name", downloadButton.text,
"game_schema_type", gameSchemaType,
"page_name", GlobalActivityManager.getCurrentPageEntity().pageName,
"page_id", GlobalActivityManager.getCurrentPageEntity().pageId,
"page_business_id", GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
"last_page_name", GlobalActivityManager.getLastPageEntity().pageName,
"last_page_id", GlobalActivityManager.getLastPageEntity().pageId,
"last_page_business_id", GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
}
}
override fun init(context: Context?) {
// do nothing
}
}

View File

@ -9,7 +9,7 @@ import com.gh.gamecenter.manager.UpdateManager
@Route(path = RouteConsts.provider.updateManager, name = "UpdateManager暴露服务")
class UpdateManagerProviderImpl: IUpdateManagerProvider {
override fun checkUpdate(context: Context, isAutoCheck: Boolean, handler: Handler) {
override fun checkUpdate(context: Context, isAutoCheck: Boolean, handler: Handler?) {
UpdateManager.getInstance(context).checkUpdate(isAutoCheck, handler)
}

View File

@ -57,8 +57,7 @@ public class DataUtils {
return;
}
// 初始化 Sentry 约占用 90ms这里切换到子线程初始化
AppExecutor.getIoExecutor().execute(() -> initSentry(context, channel));
initSentry(context, channel);
}
private static void initSentry(Context context, String channel) {

View File

@ -24,6 +24,8 @@ import com.gh.vspace.VHelper;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import java.util.Objects;
/**
* Created by khy on 27/06/17.
* 详情下载工具类
@ -42,9 +44,7 @@ public class DetailDownloadUtils {
viewHolder.mMultiVersionDownloadTv.setVisibility(View.GONE);
}
if (viewHolder.gameEntity != null
&& Config.isShowDownload(viewHolder.gameEntity.getId())
&& !"光环助手".equals(viewHolder.gameEntity.getName())) {
if (viewHolder.gameEntity != null && Config.isShowDownload(viewHolder.gameEntity.getId()) && !"光环助手".equals(viewHolder.gameEntity.getName())) {
viewHolder.downloadBottom.setVisibility(View.VISIBLE);
} else {
viewHolder.downloadBottom.setVisibility(View.GONE);
@ -233,6 +233,13 @@ public class DetailDownloadUtils {
DownloadEntity downloadEntity = viewHolder.downloadEntity;
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
if (XapkUnzipStatus.SUCCESS.name().equals(xapkStatus) && XapkInstaller.INSTANCE.isInstalling(downloadEntity.getPath())) {
viewHolder.mDownloadPb.setText("游戏安装中");
viewHolder.mDownloadPb.setProgress(100);
viewHolder.mDownloadPb.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
return;
}
if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
String percent = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_PERCENT);
viewHolder.mDownloadPb.setText("游戏解压中 " + percent + "%");
@ -286,7 +293,7 @@ public class DetailDownloadUtils {
viewHolder.mDownloadPb.setText(R.string.launch);
viewHolder.mDownloadPb.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL) && !Objects.equals(Constants.XAPK_APKS_FORMAT, downloadEntity.getFormat())) {
viewHolder.mDownloadPb.setText(R.string.browser_install_install);
} else {
viewHolder.mDownloadPb.setText(R.string.install);
@ -307,13 +314,12 @@ public class DetailDownloadUtils {
}
}
} else {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL) && !Objects.equals(Constants.XAPK_APKS_FORMAT, downloadEntity.getFormat())) {
viewHolder.mDownloadPb.setText(R.string.browser_install_install);
} else {
viewHolder.mDownloadPb.setText(R.string.install);
}
if (downloadEntity.isPluggable()
&& PackagesManager.isInstalled(downloadEntity.getPackageName())) {
if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_PLUGIN);
} else {
viewHolder.mDownloadPb.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);

View File

@ -51,6 +51,7 @@ import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActi
import com.gh.gamecenter.game.commoncollection.detail.CommonCollectionDetailActivity
import com.gh.gamecenter.game.upload.GameSubmissionActivity
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
import com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
@ -219,8 +220,9 @@ object DirectUtils {
)
} else {
directToGameDetail(
context, linkEntity.link
?: "", BaseActivity.mergeEntranceAndPath(entrance, path)
context,
linkEntity.link ?: "",
entrance = BaseActivity.mergeEntranceAndPath(entrance, path)
)
}
}
@ -1877,7 +1879,9 @@ object DirectUtils {
entrance: String = "",
forumName: String = "",
gameCollectionTitle: String = "",
gameCollectionId: String = ""
gameCollectionId: String = "",
collectionName: String = "",
collectionId: String = ""
) {
val bundle = Bundle()
bundle.putString(KEY_TO, GameCollectionSquareActivity::class.java.name)
@ -1885,6 +1889,19 @@ object DirectUtils {
bundle.putString(KEY_FORUM_NAME, forumName)
bundle.putString(KEY_GAME_COLLECTION_TITLE, gameCollectionTitle)
bundle.putString(KEY_GAME_COLLECTION_ID, gameCollectionId)
bundle.putString(KEY_COLLECTION_ID, collectionId)
bundle.putString(KEY_COLLECTION_NAME, collectionName)
jumpActivity(context, bundle)
}
/**
* 跳转至游戏单热榜
*/
@JvmStatic
fun directToGameCollectionHotList(context: Context, entrance: String = "") {
val bundle = Bundle()
bundle.putString(KEY_TO, GameCollectionHotListActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance)
jumpActivity(context, bundle)
}

View File

@ -18,18 +18,20 @@ import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkInstaller.cancelUnzipTask
import com.gh.common.xapk.XapkInstaller.isInstalling
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.download.dialog.DownloadDialog
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.callback.CancelListener
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.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
@ -163,6 +165,8 @@ object DownloadItemUtils {
briefStyle: String? = null,
isShowRecommendStar: Boolean = false
) {
holder.gameDownloadBtn.putObject(gameEntity)
// 显示预约
if (gameEntity.isReservable) {
holder.multiVersionDownloadTv?.visibility = View.GONE
@ -263,18 +267,17 @@ object DownloadItemUtils {
}
}
} else if (gameEntity.getApk().size == 1) {
// 优先从下载管理获取 downloadEntity
var downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
// 找不到时,若类型为畅玩,尝试从畅玩数据库的快照中获取 downloadEntity。若存在代表游戏已下载并成功安装
if (downloadEntity == null && gameEntity.isVGame()) {
downloadEntity = VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
}
// 还是找不到时,尝试从 gameEntity 里找已绑定的 downloadEntity
if (downloadEntity == null) {
val entryMap: ArrayMap<String, DownloadEntity> = gameEntity.getEntryMap()
val apkEntity = gameEntity.getApk()[0]
if (entryMap.isNotEmpty()) {
downloadEntity = entryMap[apkEntity.getPlatform()]
}
downloadEntity = gameEntity.getEntryMap().getOrDefault(gameEntity.getUniquePlatform(), null)
}
if (downloadEntity != null) {
@ -297,6 +300,25 @@ object DownloadItemUtils {
DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
}
} else {
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
if (XapkUnzipStatus.SUCCESS.name == xapkStatus && isInstalling(downloadEntity.path)) {
progress = 100
setText(R.string.installing)
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
return
}
if (XapkUnzipStatus.UNZIPPING.name == xapkStatus) {
val percent = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_PERCENT]
progress = (java.lang.Float.valueOf(percent) * 10).toInt()
text = "$percent%"
buttonStyle = DownloadButton.ButtonStyle.XAPK_UNZIPPING
return
} else if (XapkUnzipStatus.FAILURE.name == xapkStatus) {
setText(R.string.install)
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
return
}
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
setText(R.string.install)
}
@ -307,6 +329,7 @@ object DownloadItemUtils {
DownloadButton.ButtonStyle.NORMAL
}
}
DownloadStatus.pause,
DownloadStatus.timeout,
DownloadStatus.neterror,
@ -317,9 +340,11 @@ object DownloadItemUtils {
buttonStyle = DownloadButton.ButtonStyle.NORMAL
setText(R.string.resume)
}
DownloadStatus.cancel -> {
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation)
}
else -> {
// do nothing
}
@ -396,7 +421,7 @@ object DownloadItemUtils {
}
// 更改进度条和提示文本的状态
fun changeStatus(
private fun changeStatus(
context: Context,
holder: GameViewHolder,
downloadEntity: DownloadEntity,
@ -421,6 +446,7 @@ object DownloadItemUtils {
holder.gameDownloadBtn.text = downloadEntity.percent.toString() + "%"
}
}
DownloadStatus.waiting -> {
if (isMultiVersion) {
holder.gameDownloadTips?.visibility = View.VISIBLE
@ -429,6 +455,7 @@ object DownloadItemUtils {
holder.gameDownloadBtn.buttonStyle = DownloadButton.ButtonStyle.WAITING
holder.gameDownloadBtn.text = context.getString(R.string.waiting)
}
DownloadStatus.pause,
DownloadStatus.timeout,
DownloadStatus.neterror,
@ -443,6 +470,7 @@ object DownloadItemUtils {
holder.gameDownloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
holder.gameDownloadBtn.text = context.getString(R.string.resume)
}
DownloadStatus.done -> {
if (isMultiVersion) {
holder.gameDownloadTips?.visibility = View.VISIBLE
@ -462,6 +490,7 @@ object DownloadItemUtils {
holder.gameDownloadBtn.progress = 1000
holder.gameDownloadBtn.setText(R.string.hundred_percent)
}
else -> {
holder.gameDownloadTips?.visibility = View.GONE
}
@ -592,13 +621,15 @@ object DownloadItemUtils {
refreshCallback: EmptyCallback?,
allStateClickCallback: EmptyCallback?
) {
// 为 downloadButton 添加游戏实体,供点击的时候上报用
downloadBtn.putObject(gameEntity)
val gamePermissionDialogFragment = (context as AppCompatActivity).supportFragmentManager.findFragmentByTag(
GamePermissionDialogFragment::class.java.name
) as GamePermissionDialogFragment?
gamePermissionDialogFragment?.dismissAllowingStateLoss()
if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
downloadBtn.setOnClickListener {
logDownloadButtonClick(gameEntity, downloadBtn)
DialogHelper.showDialog(
context,
"提示",
@ -618,7 +649,6 @@ object DownloadItemUtils {
if (gameEntity.isSpecialDownload()) {
val info = RegionSettingHelper.getGameSpecialDownloadInfo(gameEntity.id) ?: return
downloadBtn.setOnClickListener {
logDownloadButtonClick(gameEntity, downloadBtn)
DialogHelper.showDialog(
context,
"提示",
@ -659,14 +689,12 @@ object DownloadItemUtils {
ReservationHelper.reserve(
context,
gameEntity.id,
gameEntity.name ?: "",
object : EmptyCallback {
override fun onCallback() {
LogUtils.logReservation(gameEntity, traceEvent)
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
})
gameEntity.name ?: ""
) {
LogUtils.logReservation(gameEntity, traceEvent)
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
}
}
} else {
@ -708,16 +736,13 @@ object DownloadItemUtils {
val gameH5Download = RegionSettingHelper.getGameH5DownloadByGameId(gameEntity.id)
if (gameH5Download != null) {
downloadBtn.setOnClickListener {
logDownloadButtonClick(gameEntity, downloadBtn)
DialogUtils.showGameH5DownloadDialog(context, gameEntity, gameH5Download)
}
return
}
if (gameEntity.getApk().size == 0 && gameEntity.h5Link != null) {
downloadBtn.setOnClickListener {
logDownloadButtonClick(gameEntity, downloadBtn)
allStateClickCallback?.onCallback()
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.name)
val linkEntity = gameEntity.h5Link
val isPlay = "play" == linkEntity!!.type // 是否为开始玩
if (isPlay) {
@ -734,7 +759,6 @@ object DownloadItemUtils {
}
} else if (gameEntity.getApk().size == 1) {
downloadBtn.setOnClickListener {
logDownloadButtonClick(gameEntity, downloadBtn)
val clickRunnable = EmptyCallback {
allStateClickCallback?.onCallback()
clickCallback?.onCallback()
@ -795,6 +819,7 @@ object DownloadItemUtils {
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
if (str == context.getString(R.string.download)) {
ChainBuilder().apply {
addHandler(UnsupportedFeatureHandler())
addHandler(UpdateNewSimulatorHandler())
addHandler(GamePermissionHandler())
addHandler(BrowserInstallHandler())
@ -812,6 +837,7 @@ object DownloadItemUtils {
DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
} else if (str == context.getString(R.string.attempt)) {
ChainBuilder().apply {
addHandler(UnsupportedFeatureHandler())
addHandler(UpdateNewSimulatorHandler())
addHandler(GamePermissionHandler())
addHandler(BrowserInstallHandler())
@ -830,6 +856,7 @@ object DownloadItemUtils {
DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
} else if (str == context.getString(R.string.smooth)) {
ChainBuilder().apply {
addHandler(UnsupportedFeatureHandler())
addHandler(GamePermissionHandler())
addHandler(PackageCheckHandler())
addHandler(DownloadDialogHelperHandler())
@ -846,9 +873,6 @@ object DownloadItemUtils {
.buildHandlerChain()
?.handleRequest(context, gameEntity)
} else if (str.contains("")) {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "插件化", gameEntity.name)
}
if (gameEntity.pluggableCollection != null) {
DownloadDialog.showDownloadDialog(context, gameEntity, traceEvent, entrance, location)
} else {
@ -913,42 +937,40 @@ object DownloadItemUtils {
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity)
return
}
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "启动", gameEntity.name)
}
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk()[0].packageName)
PackageLauncher.launchApp(context, gameEntity, gameEntity.getApk()[0].packageName)
} else if (str == context.getString(R.string.update)) {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "更新", gameEntity.name)
}
if (gameEntity.isVGame()) {
VHelper.updateOrReDownload(gameEntity)
return
}
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
override fun onCallback() {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name
) { isSubscribe: Boolean ->
update(context, gameEntity, entrance, location, isSubscribe, traceEvent)
}
}
})
} else {
var downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
if (downloadEntity == null && gameEntity.getApk().size == 1) {
val entryMap: ArrayMap<String, DownloadEntity> = gameEntity.getEntryMap()
val apkEntity = gameEntity.getApk()[0]
if (entryMap.isNotEmpty()) {
downloadEntity = entryMap[apkEntity.getPlatform()]
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk) {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name
) { isSubscribe: Boolean ->
update(context, gameEntity, entrance, location, isSubscribe, traceEvent)
}
}
} else {
var downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
// 找不到时,若类型为畅玩,尝试从畅玩数据库的快照中获取 downloadEntity。若存在代表游戏已下载并成功安装
if (downloadEntity == null && gameEntity.isVGame()) {
downloadEntity = VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
}
// 还是找不到时,尝试从 gameEntity 里找已绑定的 downloadEntity
if (downloadEntity == null) {
downloadEntity = gameEntity.getEntryMap().getOrDefault(gameEntity.getUniquePlatform(), null)
}
if (downloadEntity != null) {
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
if (XapkUnzipStatus.SUCCESS.name == xapkStatus && isInstalling(downloadEntity.path)) {// 安装过程中避免重复点击
return
}
if (XapkUnzipStatus.UNZIPPING.name == xapkStatus) {
cancelUnzipTask(downloadEntity)
return
@ -957,9 +979,11 @@ object DownloadItemUtils {
context.getString(R.string.resume) -> {
DownloadManager.getInstance().resume(downloadEntity, true)
}
context.getString(R.string.waiting) -> {
Utils.toast(context, "最多只能同时下载三个任务,请稍等")
}
else -> {
DownloadManager.getInstance().pause(downloadEntity.url)
}
@ -980,7 +1004,7 @@ object DownloadItemUtils {
) {
if (gameEntity.getApk().isEmpty()) return
val msg = FileUtils.isCanDownload(context, gameEntity.getApk()[0].size)
val msg = FileUtils.isCanDownload(context, gameEntity.getApk()[0].size ?: "")
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(
context,
@ -991,7 +1015,13 @@ object DownloadItemUtils {
isSubscribe,
traceEvent
)
Utils.toast(context, gameEntity.name + "已加入下载队列")
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
if (downloadBtn is DownloadButton) {
downloadBtn.text = "0%"
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
@ -1012,10 +1042,16 @@ object DownloadItemUtils {
isSubscribe: Boolean,
traceEvent: ExposureEvent?
) {
val msg = FileUtils.isCanDownload(context, gameEntity.getApk()[0].size)
val msg = FileUtils.isCanDownload(context, gameEntity.getApk()[0].size ?: "")
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent)
Utils.toast(context, gameEntity.name + "已加入下载队列")
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
if (downloadBtn is DownloadButton) {
downloadBtn.setText(R.string.downloading)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN
@ -1045,9 +1081,11 @@ object DownloadItemUtils {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
PackageUtils.isCanPluggable(apkEntity) -> {
DialogHelper.showPluginDialog(context) { PackageInstaller.uninstall(context, path) }
}
else -> {
PackageInstaller.install(context, downloadEntity)
}
@ -1066,23 +1104,4 @@ object DownloadItemUtils {
) {
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, traceEvent)
}
private fun logDownloadButtonClick(gameEntity: GameEntity, downloadBtn: View) {
val buttonName = if (downloadBtn is DownloadButton) downloadBtn.text else ""
SensorsBridge.trackEvent(
"DownLoadbuttonClick",
"game_id", gameEntity.id,
"game_name", gameEntity.name ?: "",
"game_type", gameEntity.categoryChinese,
"download_status", gameEntity.downloadStatusChinese,
"button_name", buttonName,
"game_schema_type", gameEntity.gameBitChinese,
"page_name", GlobalActivityManager.getCurrentPageEntity().pageName,
"page_id", GlobalActivityManager.getCurrentPageEntity().pageId,
"page_business_id", GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
"last_page_name", GlobalActivityManager.getLastPageEntity().pageName,
"last_page_id", GlobalActivityManager.getLastPageEntity().pageId,
"last_page_business_id", GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
}

View File

@ -16,7 +16,6 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.entity.SuggestType
import com.gh.gamecenter.common.eventbus.EBShowDialog
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.eventbus.EBDownloadStatus
@ -24,18 +23,13 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.SimulatorEntity
import com.gh.gamecenter.feature.utils.PlatformUtils
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.pkg.PkgHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.*
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
object DownloadObserver {
@ -45,7 +39,7 @@ object DownloadObserver {
// TODO 修复因为更改内存对象造成的双重下载完成事件问题,具体触发代码见 DownloadDao.updateSnapshotList
private var mDoneDebouncePair: Pair<String, Long>? = null
private const val TEA_EVENT_DOWNLOAD_COMPLETE = "game_addiction"
private const val CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED = "CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED"
// 如果在WIFI状态下,下载自动暂停,则再重试一遍
@JvmStatic
@ -210,10 +204,7 @@ object DownloadObserver {
} else {
statDoneEvent(downloadEntity)
if (!SPUtils.getBoolean(TEA_EVENT_DOWNLOAD_COMPLETE)) {
HaloApp.getInstance().flavorProvider.logEvent(TEA_EVENT_DOWNLOAD_COMPLETE)
SPUtils.setBoolean(TEA_EVENT_DOWNLOAD_COMPLETE, true)
}
logCoreEventIfNeeded(downloadEntity.getGameCategory())
GameActivityDownloadHelper.clear()
@ -392,7 +383,7 @@ object DownloadObserver {
"DownloadProcessFinish",
"game_id", downloadEntity.gameId,
"game_name", downloadEntity.meta[Constants.GAME_NAME] ?: "",
"game_type", downloadEntity.meta[Constants.GAME_TYPE] ?: "",
"game_type", downloadEntity.meta[Constants.GAME_CATEGORY_IN_CHINESE] ?: "",
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
@ -452,4 +443,21 @@ object DownloadObserver {
DataLogUtils.uploadHijack(mApplication, downloadEntity)
}
/**
* 根据预设的游戏类型上报关键事件(下载完成事件)
*/
private fun logCoreEventIfNeeded(gameCategory: String) {
val category = PkgHelper.getCoreEventGameCategory()
val categoryMatched = if (category == "standard" || category.isNullOrEmpty()) {
true
} else {
gameCategory == category
}
if (!SPUtils.getBoolean(CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED) && categoryMatched) {
HaloApp.getInstance().flavorProvider.logCoreEvent()
SPUtils.setBoolean(CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED, true)
}
}
}

View File

@ -15,6 +15,7 @@ import com.gh.common.simulator.SimulatorDownloadManager
import com.gh.common.simulator.SimulatorGameManager
import com.gh.download.DownloadManager
import com.gh.download.dialog.DownloadDialog
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.constant.Constants
@ -26,6 +27,7 @@ import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.MtaHelper
@ -183,6 +185,12 @@ object GameActivityDownloadHelper {
str != context.getString(R.string.launch)
) {
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
when {
str == context.getString(R.string.download) || str == context.getString(R.string.attempt) -> {
@ -205,6 +213,12 @@ object GameActivityDownloadHelper {
}
else -> {
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
}
}
}
@ -348,7 +362,7 @@ object GameActivityDownloadHelper {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "启动", gameEntity.name)
}
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk()[0].packageName)
PackageLauncher.launchApp(context, gameEntity, gameEntity.getApk()[0].packageName)
}
// 处理更新状态
@ -424,6 +438,12 @@ object GameActivityDownloadHelper {
), entrance, location, isSubscribe, traceEvent
)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
ToastUtils.toast(msg)
}
@ -443,6 +463,12 @@ object GameActivityDownloadHelper {
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, apk, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
ToastUtils.toast(msg)
}
@ -483,6 +509,12 @@ object GameActivityDownloadHelper {
) {
DownloadManager.createDownload(context, apk, gameEntity, "更新", entrance, location, isSubscribe, traceEvent)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
}
@SuppressLint("CheckResult")

View File

@ -8,6 +8,7 @@ import androidx.annotation.WorkerThread;
import com.gh.common.constant.Config;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
@ -180,7 +181,8 @@ public class GameUtils {
if (gameEntity.isVGame()) {
return context.getString(R.string.smooth);
} else {
if ("smooth".equals(gameEntity.getDownloadStatus())) {
if (Constants.V_GAME.equals(gameEntity.getDownloadStatus())
|| Constants.V_GAME_32.equals(gameEntity.getDownloadStatus())) {
GameEntity.GameCategory gameCategory = gameEntity.getGameCategory();
if (gameCategory.equals(GameEntity.GameCategory.ONLINE_GAME)
|| gameCategory.equals(GameEntity.GameCategory.INTERNATIONAL_ONLINE_GAME)) {

View File

@ -786,7 +786,7 @@ public class LibaoUtils {
, "关闭", "启动游戏"
, () -> {
if (LibaoUtils.isAppInstalled(context, libaoEntity.getPackageName())) {
PackageUtils.launchApplicationByPackageName(context, libaoEntity.getPackageName());
PackageLauncher.launchApp(context, null, libaoEntity.getPackageName());
} else {
Utils.toast(context, "请安装游戏:" + libaoEntity.getGame().getName()
+ PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform()) + "");

View File

@ -23,6 +23,9 @@ object NewFlatLogUtils {
private const val KEY_TEXT = "text"
private const val KEY_BUTTON_TYPE = "button_type"
private const val KEY_BBS_ID = "bbs_id"
private const val KEY_GAME_CATEGORY = "game_category"
private const val KEY_DOWNLOAD_STATE = "download_state"
private const val KEY_LOCATION = "location"
private const val EVENT_LOGIN_FROM_GHZS_SHOW = "halo_fun_login_from_ghzs_show"
private const val EVENT_LOGIN_FROM_GHZS_CLICK = "halo_fun_login_from_ghzs_click"
@ -118,7 +121,7 @@ object NewFlatLogUtils {
fun logHaloFunGameDetailJumpClick(downloadStatus: String, gameId: String) {
val json = json {
KEY_EVENT to "halo_fun_game_detail_jump_click"
"download_state" to downloadStatus
KEY_DOWNLOAD_STATE to downloadStatus
KEY_GAME_ID to gameId
parseAndPutMeta().invoke(this)
}
@ -684,7 +687,7 @@ object NewFlatLogUtils {
val json = json {
KEY_EVENT to "halo_self_publish_content"
"tab_name" to tabName
"location" to location
KEY_LOCATION to location
parseAndPutMeta().invoke(this)
}
log(json)
@ -1052,10 +1055,11 @@ object NewFlatLogUtils {
}
//游戏单广场浏览时长
fun logGameCollectSquareStayTime(interval: Long) {
fun logGameCollectSquareStayTime(interval: Long, source: String) {
val json = json {
KEY_EVENT to "game_collect_square_stay_time"
"interval" to interval
"source" to source
parseAndPutMeta().invoke(this)
}
log(json)
@ -1479,7 +1483,7 @@ object NewFlatLogUtils {
) {
val json = json {
KEY_EVENT to "game_detail_comment_tab_game_comment_click"
"location" to location
KEY_LOCATION to location
"tag" to tag
"filter_tag_name" to filter
"button" to button
@ -1521,7 +1525,7 @@ object NewFlatLogUtils {
) {
val json = json {
KEY_EVENT to "game_detail_comment_tab_game_comment_detail_click"
"location" to location
KEY_LOCATION to location
"tag" to tag
"filter_tag_name" to filter
"button" to button
@ -1623,7 +1627,7 @@ object NewFlatLogUtils {
val json = json {
"event" to "game_test_detail_game_category_click"
"tab_name" to tabName
"game_category" to gameCategory
KEY_GAME_CATEGORY to gameCategory
"game_test_start_type" to gameTestStartType
parseAndPutMeta().invoke(this)
}
@ -1658,7 +1662,7 @@ object NewFlatLogUtils {
val json = json {
"event" to "game_test_home_more_click"
"text" to text //右上角文案,包括:全部、更多
"location" to location //新游开测所处位置,包括:首页、版块
KEY_LOCATION to location //新游开测所处位置,包括:首页、版块
"block_id" to blockId //新游开测所处位置为“版块”上报版块ID
"block_name" to blockName //新游开测所处位置为“版块”,上报版块名称
"link_type" to linkType //右上角文案为“更多”时的链接类型
@ -1685,7 +1689,7 @@ object NewFlatLogUtils {
) {
val json = json {
"event" to "game_test_home_recommend_tag_click"
"location" to location //新游开测所处位置,包括:首页、版块
KEY_LOCATION to location //新游开测所处位置,包括:首页、版块
"block_id" to blockId //新游开测所处位置为“版块”上报版块ID
"block_name" to blockName //新游开测所处位置为“版块”,上报版块名称
"tag_id" to tagId //点击推荐标签的ID
@ -1733,7 +1737,7 @@ object NewFlatLogUtils {
) {
val json = json {
"event" to "game_test_home_view"
"location" to location //新游开测所处位置,包括:首页、版块
KEY_LOCATION to location //新游开测所处位置,包括:首页、版块
"block_id" to blockId //新游开测所处位置为“版块”上报版块ID
"block_name" to blockName //新游开测所处位置为“版块”,上报版块名称
"interval" to interval //内容在屏幕可见范围完整展示的时长
@ -1988,7 +1992,7 @@ object NewFlatLogUtils {
"type" to homeSubSlide.cardType
"text" to homeSubSlide.cardText
"count_num" to countNum
"location" to location
KEY_LOCATION to location
"link_type" to homeSubSlide.linkType
"link_id" to homeSubSlide.linkId
"link_text" to homeSubSlide.linkText
@ -2185,4 +2189,155 @@ object NewFlatLogUtils {
}
log(json, "event", false)
}
// 游戏单广场刷新
@JvmStatic
fun logGameCollectionSquareFlush(action: String, countNum: Int) {
val json = json {
KEY_EVENT to "game_list_square_flush"
"action" to action
"count_num" to countNum
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏详情点击公告文章
@JvmStatic
fun logGameDetailNoticeClick(gameId: String, gameName: String, linkId: String, linkType: String, linkText: String) {
val json = json {
KEY_EVENT to "game_detail_notice_click"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
"link_id" to linkId
"link_type" to linkType
"link_text" to linkText
parseAndPutMeta().invoke(this)
}
log(json)
}
// 启动游戏(UI被点击)
fun logGameLaunchButtonClicked(
gameId: String,
gameName: String,
location: String,
gameCategory: String,
downloadStatus: String
) {
val json = json {
KEY_EVENT to "game_launch_button_click"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_LOCATION to location
KEY_GAME_CATEGORY to gameCategory
KEY_DOWNLOAD_STATE to downloadStatus
parseAndPutMeta().invoke(this)
}
log(json)
}
// 启动游戏(具体实现逻辑)
fun logGameLaunch(
gameId: String,
gameName: String,
gameCategory: String,
downloadStatus: String
) {
val json = json {
KEY_EVENT to "game_launch"
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
KEY_GAME_CATEGORY to gameCategory
KEY_DOWNLOAD_STATE to downloadStatus
parseAndPutMeta().invoke(this)
}
log(json)
}
// 进入游戏单热榜
@JvmStatic
fun logGameCollectionHotListEnter(entrance: String) {
val json = json {
KEY_EVENT to "game_list_hot_rank_enter"
"entrance" to entrance
parseAndPutMeta().invoke(this)
}
log(json)
}
// 离开游戏单热榜
@JvmStatic
fun logGameCollectionHotListExit(interval: Long, tabName: String) {
val json = json {
KEY_EVENT to "game_list_hot_rank_exit"
"interval" to interval
"tab_name" to tabName
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏热榜点击tab
@JvmStatic
fun logGameCollectionHotListTabClick(tabName: String, collectionId: String, collectionName: String) {
val json = json {
KEY_EVENT to "game_hot_rank_tab_click"
"tab_name" to tabName
"game_list_collection_id" to collectionId
"game_list_collection_name" to collectionName
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏热榜tab浏览
@JvmStatic
fun logGameCollectionHotListTabView(interval: Int, tabName: String, collectionId: String, collectionName: String) {
val json = json {
KEY_EVENT to "game_hot_rank_tab_view"
"interval" to interval
"tab_name" to tabName
"game_list_collection_id" to collectionId
"game_list_collection_name" to collectionName
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏单热榜点击
@JvmStatic
fun logGameCollectionHotListClick(tabName: String, collectionId: String, collectionName: String, text: String) {
val json = json {
KEY_EVENT to "game_list_hot_rank_click"
"tab_name" to tabName
"game_list_collection_id" to collectionId
"game_list_collection_name" to collectionName
"text" to text
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏单合集点击
fun logGameListCollectionClick(
source: String,
blockName: String,
blockId: String,
collectionName: String,
collectionId: String,
text: String
) {
val json = json {
KEY_EVENT to "game_list_collection_click"
"source" to source
"block_name" to blockName
"block_id" to blockId
"game_list_collection_id" to collectionId
"game_list_collection_name" to collectionName
"text" to text
parseAndPutMeta().invoke(this)
}
log(json)
}
}

View File

@ -1657,13 +1657,22 @@ object NewLogUtils {
}
//进入游戏单广场
fun logEnterGameCollectionSquare(entrance: String, forumName: String = "", title: String = "", id: String = "") {
fun logEnterGameCollectionSquare(
entrance: String,
forumName: String = "",
gameCollectionTitle: String = "",
gameCollectionId: String = "",
collectionName: String = "",
collectionId: String = ""
) {
val json = json {
KEY_EVENT to "enter_game_collect_square"
KEY_ENTRANCE to entrance
"forum_name" to forumName
"game_collect_title" to title
"game_collect_id" to id
"game_collect_title" to gameCollectionTitle
"game_collect_id" to gameCollectionId
"game_list_collection_name" to collectionName
"game_list_collection_id" to collectionId
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
@ -1671,9 +1680,10 @@ object NewLogUtils {
}
//进入选择标签
fun logEnterGameCollectionTag() {
fun logEnterGameCollectionTag(source: String) {
val json = json {
KEY_EVENT to "enter_game_collect_tag_location"
"source" to source
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
@ -1681,11 +1691,12 @@ object NewLogUtils {
}
//筛选游戏单标签
fun logFilterGameCollectionTag(tagCategory: String, tagName: String) {
fun logFilterGameCollectionTag(tagCategory: String, tagName: String, source: String) {
val json = json {
KEY_EVENT to "filter_game_collect_tag"
"filter_tag_category" to tagCategory
"filter_tag_name" to tagName
"source" to source
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}
@ -1693,9 +1704,10 @@ object NewLogUtils {
}
//点击安利墙卡片
fun logClickGameCollectionAmway() {
fun logClickGameCollectionAmway(tabName: String) {
val json = json {
KEY_EVENT to "click_game_collect_recommend_card"
"tab_name" to tabName
KEY_TIMESTAMP to System.currentTimeMillis() / 1000
parseAndPutMeta().invoke(this)
}

View File

@ -1,14 +1,19 @@
package com.gh.common.util
import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller.SessionCallback
import android.net.Uri
import android.os.Build
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.gh.common.dialog.InstallPermissionDialogFragment
import com.gh.common.xapk.XapkInstallReceiver
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.BuildConfig
@ -16,6 +21,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
@ -142,6 +148,32 @@ object PackageInstaller {
context.startActivity(installIntent)
}
fun installMultiple(
context: Context,
pkgPath: String,
sessionId: Int = -1
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return
}
val installer = context.packageManager.packageInstaller
val session = installer.openSession(sessionId)
// 监听安装回调的组件可以是Activity、Service或者是BroadcastReceiver
val intent = Intent(context, XapkInstallReceiver::class.java)
.also {
it.putExtra(XapkInstallReceiver.KEY_PACKAGE_PATH, pkgPath)
}
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_CANCEL_CURRENT
}
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
// 提交数据流并执行安装
session.commit(pendingIntent.intentSender)
}
/**
* 获取启动安装意图
*
@ -216,7 +248,8 @@ object PackageInstaller {
}
private fun getFileSuffixByFormat(format: String?): String {
return if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
return if (format == Constants.XAPK_FORMAT
|| format == Constants.XAPK_APKS_FORMAT) {
XapkInstaller.XAPK_EXTENSION_NAME
} else {
"apk"

View File

@ -0,0 +1,54 @@
package com.gh.common.util
import android.content.Context
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.GameInstall
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.packagehelper.PackageRepository
object PackageLauncher {
/*
* 启动应用
*/
@JvmStatic
fun launchApp(
context: Context,
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) {
context.startActivity(intent)
} else {
ToastUtils.toast("启动失败")
}
} catch (e: Exception) {
ToastUtils.toast( "启动失败")
}
}
}

View File

@ -746,9 +746,11 @@ public class PackageUtils {
}
/*
/**
* 启动应用
* 请使用 PackageLauncher.launchApp()
*/
@Deprecated
public static void launchApplicationByPackageName(Context context, String packageName) {
try {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);

View File

@ -66,7 +66,7 @@ object RealNameHelper {
"game_name",
downloadEntity.name ?: "",
"game_type",
downloadEntity.meta[Constants.GAME_TYPE] ?: ""
downloadEntity.meta[Constants.GAME_CATEGORY_IN_CHINESE] ?: ""
)
val contentText = if (downloadEntity.status == DownloadStatus.done) {

View File

@ -0,0 +1,59 @@
package com.gh.common.xapk
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class XapkInstallReceiver : Activity() {
companion object {
const val KEY_PACKAGE_PATH = "package_path"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
overridePendingTransition(0, 0)
handleIntent(this, intent)
}
private fun handleIntent(context: Context, intent: Intent) {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val installIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
if (installIntent != null) {
context.startActivity(installIntent)
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_PENDING_USER_ACTION)
finish()
}
}
PackageInstaller.STATUS_FAILURE,
PackageInstaller.STATUS_FAILURE_ABORTED,
PackageInstaller.STATUS_FAILURE_BLOCKED,
PackageInstaller.STATUS_FAILURE_CONFLICT,
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
PackageInstaller.STATUS_FAILURE_INVALID,
PackageInstaller.STATUS_FAILURE_STORAGE -> {
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
finish()
}
else -> {
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS)
finish()
}
}
}
private fun updatePendingSessionInfoStatus(intent: Intent, status: Int) {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
if (!installPackagePath.isNullOrEmpty()) {
val pendingSessionInfo = XapkInstaller.getPendingSessionInfo(installPackagePath)
pendingSessionInfo?.updateStatus(status)
}
}
}

View File

@ -2,20 +2,30 @@ package com.gh.common.xapk
import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import com.gh.common.util.*
import com.gh.download.DownloadDataHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.utils.debugOnly
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SentryHelper
import com.gh.gamecenter.xapk.XApkUnZipper
import com.gh.gamecenter.xapk.core.XApkFile
import com.gh.gamecenter.xapk.core.XApkUnZipCallback
import com.gh.gamecenter.xapk.core.XApkUnZipEntry
import com.gh.gamecenter.xapk.core.XApkUnZipOutputFactory
import com.gh.gamecenter.xapk.io.NonSplitApksOutput
import com.gh.gamecenter.xapk.io.OBBFileOutput
import com.gh.gamecenter.xapk.io.SplitApksOutput
import com.gh.gamecenter.xapk.io.XApkFileOutput
import com.gh.gamecenter.xapk.pi.IPackageInstaller
import com.gh.ndownload.NDataChanger
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import java.text.DecimalFormat
import java.io.File
import java.util.*
/**
@ -28,7 +38,8 @@ import java.util.*
* apk文件这解压的gh-files文件夹中
*/
@SuppressLint("StaticFieldLeak")
object XapkInstaller : IXapkUnzipListener {
object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path"
const val XAPK_EXTENSION_NAME = "xapk"
@ -42,8 +53,14 @@ object XapkInstaller : IXapkUnzipListener {
private var mContext = HaloApp.getInstance().application.applicationContext
// 是否需要开启特定线程处理
private val mXapkUnzipThreadMap = Collections.synchronizedMap(HashMap<String, XapkUnzipThread>())
private val mXApkUnZipper = XApkUnZipper(this)
.also {
it.registerCallback(this)
}
private val mDownloadEntityMap = Collections.synchronizedMap(HashMap<String, DownloadEntity>())
private val mPendingSessionInfoMap = HashMap<String, XapkPendingSessionInfo>()
// 按并行解压
@JvmStatic
@ -63,122 +80,227 @@ object XapkInstaller : IXapkUnzipListener {
}
private fun unzipXapkFile(downloadEntity: DownloadEntity) {
if (mXapkUnzipThreadMap[downloadEntity.path] == null) {
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压开始")
val xapkUnzipThread = XapkUnzipThread(downloadEntity, this)
xapkUnzipThread.start()
mXapkUnzipThreadMap[downloadEntity.path] = xapkUnzipThread
} else {
debugOnly {
Utils.log("unzip", "重复解压,该文件解压已在队列中")
}
}
mXApkUnZipper.unzip(
XApkUnZipEntry(
downloadEntity.path,
File(downloadEntity.path)
)
)
mDownloadEntityMap[downloadEntity.path] = downloadEntity
}
override fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long) {
AppExecutor.uiExecutor.execute {
val df = DecimalFormat("#.0")
var percent = 0.0
tryCatchInRelease {
percent = df.format((unzipProgress / unzipSize.toFloat()) * 100).toDouble()
}
downloadEntity.meta[XAPK_UNZIP_PERCENT] = percent.toString()
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
@JvmStatic
fun cancelUnzipTask(downloadEntity: DownloadEntity) {
mXApkUnZipper.cancel(downloadEntity.path)
}
override fun onProgress(apk: XApkFile, progress: Float) {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = String.format("%.2f", progress * 100)
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
}
debugOnly {
Utils.log("unzip", "onProgress->" + (unzipProgress / unzipSize.toFloat()))
Utils.log("unzip", "onProgress->$progress")
}
}
override fun onNext(downloadEntity: DownloadEntity, unzipPath: String) {
if (PACKAGE_EXTENSION_NAME == unzipPath.getExtension()) {
downloadEntity.meta[XAPK_PACKAGE_PATH_TAG] = unzipPath
override fun onSuccess(apk: XApkFile, installer: IPackageInstaller) {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压成功")
}
debugOnly {
Utils.log("unzip", "onNext->$unzipPath")
Utils.log("unzip", "onSuccess->${downloadEntity.path}")
}
installer.install(mContext)
}
/**
* 取消解压回调
*
* 取消后的表现与下载完成一致
*/
override fun onCancel(downloadEntity: DownloadEntity) {
mXapkUnzipThreadMap.remove(downloadEntity.path)
override fun onError(apk: XApkFile, exception: Throwable) {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name
AppExecutor.uiExecutor.execute {
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
}
override fun onFailure(downloadEntity: DownloadEntity, exception: Exception) {
mXapkUnzipThreadMap.remove(downloadEntity.path)
AppExecutor.uiExecutor.execute {
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name
AppExecutor.ioExecutor.execute {
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage
)
}
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage
)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压失败")
}
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压失败")
debugOnly {
Utils.log("unzip", "onFailure->$exception")
}
}
override fun onSuccess(downloadEntity: DownloadEntity) {
mXapkUnzipThreadMap.remove(downloadEntity.path)
AppExecutor.uiExecutor.execute {
val pkgPath = downloadEntity.meta[XAPK_PACKAGE_PATH_TAG]
if (pkgPath == null) {
Utils.toast(mContext, "下载出错,请重新下载!")
return@execute
}
PackageInstaller.install(mContext, downloadEntity.isPlugin, pkgPath, downloadEntity)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
override fun onCancel(apk: XApkFile) {
val downloadEntity = mDownloadEntityMap.remove(apk.file.path) ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
}
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压成功")
override fun onNext(apk: XApkFile, fileName: String) {
debugOnly {
Utils.log("unzip", "onSuccess->${downloadEntity.path}")
Utils.log("unzip", "onNext->$fileName")
}
}
@JvmStatic
fun cancelUnzipTask(downloadEntity: DownloadEntity) {
val xapkUnzipThread = mXapkUnzipThreadMap[downloadEntity.path]
if (xapkUnzipThread != null) {
xapkUnzipThread.canceled = true
fun getPendingSessionInfo(packagePath: String): XapkPendingSessionInfo? = mPendingSessionInfoMap[packagePath]
fun isInstalling(packagePath: String): Boolean = mPendingSessionInfoMap.containsKey(packagePath)
/**
* 通知XAPK安装完成
*/
fun onInstalled(packagePath: String) {
val downloadEntity = mDownloadEntityMap.remove(packagePath) ?: return
mPendingSessionInfoMap.remove(packagePath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.INSTALLED.name
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装成功")
}
}
fun onInstallCanceled(packagePath: String) {
val downloadEntity = mDownloadEntityMap.remove(packagePath) ?: return
mPendingSessionInfoMap.remove(packagePath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装取消")
}
}
/**
* 更新当前XAPK安装状态, 主要针对以下出现安装结果回调异常的情况:
* 1. 用户触碰安装弹窗(原生Android系统)区域外导致安装取消
*/
fun updateCurrentInstallStatus() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || mPendingSessionInfoMap.isEmpty()) {
return
}
val updateList = mutableListOf<XapkPendingSessionInfo>()
for (pendingSessionInfoEntry in mPendingSessionInfoMap) {
val pendingSessionInfo = pendingSessionInfoEntry.value
if (pendingSessionInfo.getStatus() == XapkPendingSessionInfo.STATUS_PENDING_USER_ACTION) {// 用户触摸安装弹窗外部区域取消安装后,更新安装状态
val installer = mContext.packageManager.packageInstaller
val sessionId = pendingSessionInfo.sessionId
if (sessionId != -1) {
val sessionInfo = installer.getSessionInfo(sessionId)
// 表示用户点击了安装弹窗外部区域
if (sessionInfo != null && sessionInfo.progress <= 0.8F) {
AppExecutor.ioExecutor.execute {
installer.abandonSession(sessionInfo.sessionId)
}
pendingSessionInfo.updateStatus(XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
}
}
}
val installStatus = pendingSessionInfo.getStatus()
if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_CANCELED
|| installStatus == XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS
) {
updateList.add(pendingSessionInfo)
}
}
for (pendingSessionInfo in updateList) {
val downloadEntity = mDownloadEntityMap[pendingSessionInfo.path] ?: continue
val installStatus = pendingSessionInfo.getStatus()
if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS) {
onInstalled(downloadEntity.path)
} else if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_CANCELED) {
onInstallCanceled(downloadEntity.path)
}
}
}
override fun onCreateOBBOutput(apk: XApkFile): XApkFileOutput<Unit> {
return OBBFileOutput()
}
override fun onCreateApkOutput(apk: XApkFile): XApkFileOutput<IPackageInstaller> {
val isMultiApks = apk.manifest.isMultiApks
return if (isMultiApks) {
SplitApksOutput(mContext.applicationContext) {
SplitApksInstaller(apk, it)
}
} else {
onCancel(downloadEntity) // 刷新页面
NonSplitApksOutput {
NonSplitApkInstaller(apk, it)
}
}
}
private class SplitApksInstaller(
private val xApkFile: XApkFile,
private val sessionId: Int,
) : IPackageInstaller {
override fun install(context: Context) {
val downloadEntity = mDownloadEntityMap[xApkFile.file.path] ?: return
val applicationContext = context.applicationContext
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
NDataChanger.notifyDataChanged(downloadEntity)
PackageInstaller.installMultiple(applicationContext, downloadEntity.path, sessionId)
}
}
}
private class NonSplitApkInstaller(
private val xApkFile: XApkFile,
private val file: File
) : IPackageInstaller {
override fun install(context: Context) {
val downloadEntity = mDownloadEntityMap[xApkFile.file.path] ?: return
PackageInstaller.install(
context,
downloadEntity.isPlugin,
file.absolutePath,
downloadEntity
)
}
}
}
@ -187,5 +309,7 @@ enum class XapkUnzipStatus(status: String) {
UNZIPPING("unzipping"),
SUCCESS("success"),
CANCEL("cancel"),
INSTALLING("installing"),
INSTALLED("installed"),
FAILURE("failure");
}

View File

@ -0,0 +1,21 @@
package com.gh.common.xapk
class XapkPendingSessionInfo(
val path: String,
val sessionId: Int = -1
) {
companion object {
const val STATUS_INIT = -1
const val STATUS_PENDING_USER_ACTION = 0
const val STATUS_INSTALL_SUCCESS = 1
const val STATUS_INSTALL_CANCELED = 2
}
private var status = STATUS_INIT
internal fun updateStatus(status: Int) {
this.status = status
}
fun getStatus(): Int = status
}

View File

@ -128,7 +128,7 @@ object DownloadDataHelper {
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("certification", RealNameHelper.getCertificationStatus())
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
payloadObject.put("task_num", NDataChanger.downloadingTaskUrlSet.size)
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
e.printStackTrace()
@ -214,7 +214,7 @@ object DownloadDataHelper {
payloadObject.put("certification", RealNameHelper.getCertificationStatus())
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("launch_ms", startupTime)
payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
payloadObject.put("task_num", NDataChanger.downloadingTaskUrlSet.size)
if (parallel != null) {
payloadObject.put("parallel", parallel)
}
@ -276,7 +276,7 @@ object DownloadDataHelper {
payloadObject.put("speed", speed)
}
} else {
payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
payloadObject.put("task_num", NDataChanger.downloadingTaskUrlSet.size)
}
payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
if (downloadEntity.status == DownloadStatus.resume) {
@ -329,7 +329,7 @@ object DownloadDataHelper {
if (parallel != null) {
payloadObject.put("parallel", parallel)
}
payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
payloadObject.put("task_num", NDataChanger.downloadingTaskUrlSet.size)
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
e.printStackTrace()
@ -352,7 +352,8 @@ object DownloadDataHelper {
* 在后台唤醒的情况下 下载状态可能无法修正
* see [DownloadManager.initDownloadService]
*/
if (downloadEntity.status == DownloadStatus.downloading && NDataChanger.downloadingTasks[downloadEntity.url] != null) {
if (downloadEntity.status == DownloadStatus.downloading
&& NDataChanger.downloadingTaskUrlSet.contains(downloadEntity.url)) {
var sheet = mDownloadHeartbeatSheet[downloadEntity.url]
if (sheet == null) {
sheet = JSONObject()

View File

@ -61,7 +61,6 @@ import com.lightgame.download.DownloadDao;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import com.lightgame.download.DownloadStatusListener;
import com.lightgame.download.DownloadTask;
import com.lightgame.download.FileUtils;
import com.lightgame.download.HttpDnsManager;
import com.lightgame.utils.Utils;
@ -284,6 +283,7 @@ public class DownloadManager implements DownloadStatusListener {
String path;
String downloadId = PackageInstaller.createDownloadId(gameEntity.getName());
String gameCategory = gameEntity.getCategory();
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
path = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/" + gameEntity.getName() + "." + apkEntity.getFormat();
@ -316,6 +316,7 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setGameId(gameEntity.getId());
downloadEntity.setEntrance(entrance);
downloadEntity.setLocation(location);
downloadEntity.setFormat(apkEntity.getFormat());
downloadEntity.setVersionName(apkEntity.getVersion());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.APK_MD5, apkEntity.getMd5());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.DOWNLOAD_ID, downloadId);
@ -323,9 +324,11 @@ public class DownloadManager implements DownloadStatusListener {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_SUBSCRIPT, gameEntity.getIconSubscript());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.IS_PLATFORM_RECOMMEND, apkEntity.getRecommend() != null ? "true" : "false");
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_NAME, gameEntity.getName());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_TYPE, gameEntity.getCategoryChinese());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_CATEGORY_IN_CHINESE, gameEntity.getCategoryChinese());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.AD_ICON_ACTIVE, String.valueOf(gameEntity.getAdIconActive()));
ExtensionsKt.addMetaExtra(downloadEntity, Constants.IS_AD_DATA, String.valueOf(gameEntity.isAdData()));
ExtensionsKt.putGameCategory(downloadEntity, gameCategory != null ? gameCategory : "");
ExtensionsKt.addMetaExtra(downloadEntity, Constants.APK_SIZE, apkEntity.getSize());
if (gameEntity.getIconFloat() != null) {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_FLOAT_TOP_TEXT, gameEntity.getIconFloat().getUpperLeftText());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_FLOAT_TOP_COLOR, gameEntity.getIconFloat().getUpperLeftColor());
@ -545,7 +548,7 @@ public class DownloadManager implements DownloadStatusListener {
* 任务是否已经下载中
*/
public boolean isTaskDownloading(String url) {
if (NDataChanger.INSTANCE.getDownloadingTasks().get(url) != null) {
if (NDataChanger.INSTANCE.getDownloadingTaskUrlSet().contains(url)) {
Utils.log(DownloadManager.class.getSimpleName(), url + "正在下载!");
return true;
}
@ -867,12 +870,8 @@ public class DownloadManager implements DownloadStatusListener {
private void cancelAndNotify(DownloadEntity entry, boolean cancelSilently) {
mDownloadDao.removeErrorMessage(entry.getUrl());
DownloadTask task = NDataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
if (task != null) {
task.cancel();
// 改任务队列的状态
NDataChanger.INSTANCE.getDownloadingTasks().remove(entry.getUrl());
}
// 改任务队列的状态
NDataChanger.INSTANCE.getDownloadingTaskUrlSet().remove(entry.getUrl());
NDataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
if (!cancelSilently) {
NDataChanger.INSTANCE.notifyDataChanged(entry);
@ -886,8 +885,10 @@ public class DownloadManager implements DownloadStatusListener {
* 暂停所有正在下载的任务
*/
public void pauseAll() {
for (DownloadEntity entity : NDataChanger.INSTANCE.getDownloadEntries().values()) {
pause(entity.getUrl());
synchronized (NDataChanger.INSTANCE.getDownloadEntries()) {
for (DownloadEntity entity : NDataChanger.INSTANCE.getDownloadEntries().values()) {
pause(entity.getUrl());
}
}
Utils.log(DownloadManager.class.getSimpleName(), "pause all");
}
@ -913,10 +914,10 @@ public class DownloadManager implements DownloadStatusListener {
* 3.检查是否显示下载通知栏
*/
public void initDownloadService() {
final List<String> urlList = new ArrayList<>(NDataChanger.INSTANCE.getDownloadingTasks().keySet());
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlList.contains(downloadEntity.getUrl()) &&
(downloadEntity.getStatus().equals(DownloadStatus.downloading)
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);

View File

@ -6,6 +6,7 @@ import com.gh.common.util.ConcernUtils
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageUtils
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.loghub.LoghubUtils
@ -110,6 +111,10 @@ object PackageObserver {
runOnIoThread { FileUtils.deleteFile(mDownloadEntity.path) }
}
if (mDownloadEntity.format == Constants.XAPK_FORMAT) {
XapkInstaller.onInstalled(mDownloadEntity.path)
}
DownloadManager.getInstance().cancel(mDownloadEntity.url, false, true, false)
if (SPUtils.getBoolean(Constants.SP_CONCERN_GAME, true)) { //设置页面控制是否安装后自动关注

View File

@ -178,9 +178,18 @@ class DownloadDialog : BaseDraggableDialogFragment() {
for (i in 0 until it.itemCount) {
val apkEntity = itemList[i].normal ?: continue
val apkCollection = apkEntity.apkCollection
if (apkCollection != null && apkCollection.name == mPlatformName) {
scrollAndDownload(recyclerView, false, i)
break
if (apkCollection != null) {
if (apkCollection.name == mPlatformName) {
scrollAndDownload(recyclerView, false, i)
break
} else {
apkCollection.saveApkEntity?.forEach { entity ->
if (entity.getPlatformName() == mPlatformName || entity.packageName == mPackageName) {
scrollAndDownload(recyclerView, false, i)
}
}
break
}
}
if (apkEntity.getPlatformName() == mPlatformName || apkEntity.packageName == mPackageName) {
scrollAndDownload(recyclerView, true, i)

View File

@ -10,12 +10,9 @@ import com.gh.common.constant.Config
import com.gh.common.dialog.CertificationDialog
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.dialog.PackageCheckDialogFragment
import com.gh.common.util.*
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.DownloadDialogHelper
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.DownloadManagerActivity
@ -244,7 +241,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_下载"
}
DownloadDialogItemStatus.LAUNCH -> {
PackageUtils.launchApplicationByPackageName(it.context, apkEntity.packageName)
PackageLauncher.launchApp(it.context, gameEntity, apkEntity.packageName)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_启动"
}
@ -352,54 +349,46 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
if (msg.isNullOrEmpty()) {
BrowserInstallHelper.showBrowserInstallHintDialog(
context,
gameEntity.isVGame(),
object : EmptyCallback {
override fun onCallback() {
DownloadDialogHelper.findAvailableDialogAndShow(
gameEntity.isVGame() || gameEntity.isSplitXApk()
) {
DownloadDialogHelper.findAvailableDialogAndShow(
context,
gameEntity,
apkEntity
) {
PackageCheckDialogFragment.show(
context as AppCompatActivity,
gameEntity
) {
CertificationDialog.showCertificationDialog(
context,
gameEntity,
apkEntity,
object : EmptyCallback {
override fun onCallback() {
PackageCheckDialogFragment.show(
context as AppCompatActivity,
gameEntity,
object : ConfirmListener {
override fun onConfirm() {
CertificationDialog.showCertificationDialog(
context,
gameEntity,
object : ConfirmListener {
override fun onConfirm() {
DialogUtils.checkDownload(
context,
apkEntity.size,
gameEntity.id,
gameEntity.name
) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent
)
gameEntity
) {
DialogUtils.checkDownload(
context,
apkEntity.size,
gameEntity.id,
gameEntity.name
) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent
)
DeviceRemindDialog.showDeviceRemindDialog(
context,
gameEntity
)
}
}
})
}
})
}
})
DeviceRemindDialog.showDeviceRemindDialog(
context,
gameEntity
)
}
}
}
})
}
}
} else {
Utils.toast(context, msg)
}

View File

@ -17,6 +17,7 @@ import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.feature.entity.GameEntity
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
@ -93,6 +94,10 @@ object BrowserInstallHelper {
return false
}
@JvmStatic
fun shouldAutoSwitchAssistantInstall(gameEntity: GameEntity): Boolean =
isUseBrowserToInstallEnabled() && shouldUseBrowserToInstall() && gameEntity.isSplitXApk()
/**
* 是否显示使用浏览器来安装弹窗
*/
@ -144,7 +149,8 @@ object BrowserInstallHelper {
val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.CHINA)
var contentText = "当前安装方式为助手安装,如果出现游戏无法安装的问题,可选择切换安装方式为“浏览器安装”"
if (manufacturer == "OPPO" || manufacturer == "VIVO") {
contentText = "当前安装方式为助手安装,下载安装游戏需要验证账户密码或指纹。如需免密码安装,可选择切换安装方式为“浏览器安装”"
contentText =
"当前安装方式为助手安装,下载安装游戏需要验证账户密码或指纹。如需免密码安装,可选择切换安装方式为“浏览器安装”"
}
DialogHelper.showDialog(

View File

@ -198,7 +198,6 @@ public class MainActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
showAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null;
HaloApp.getInstance().initFresco();
HaloApp.getInstance().isAlreadyUpAndRunning = true;
super.onCreate(savedInstanceState);
@ -319,6 +318,8 @@ public class MainActivity extends BaseActivity {
// 默认配置为空时重试
if (Config.getSettings() == null) {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
}
// 耗时操作
@ -803,6 +804,15 @@ public class MainActivity extends BaseActivity {
ToastUtils.showToast("游戏启动失败,请联系客服反馈相关信息");
return;
}
VHelper.INSTANCE.logLaunchButtonClicked(
gamePackageName,
null,
null,
null,
"桌面快捷图标"
);
ToastUtils.showToast("游戏启动中,请稍后~");
handler.postDelayed(() -> {
VHelper.postOnInitialized(() -> {
@ -1064,6 +1074,8 @@ public class MainActivity extends BaseActivity {
if (busNetworkState.isNetworkConnected()) {
if (Config.getSettings() == null) {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
}
mPackageViewModel.checkData();

View File

@ -403,7 +403,7 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToGameCollectionDetail(this, path, ENTRANCE_BROWSER, "", null);
break;
case HOST_GAME_COLLECTION_SQUARE:
DirectUtils.directToGameCollectionSquare(this, ENTRANCE_BROWSER, "", "", "");
DirectUtils.directToGameCollectionSquare(this, ENTRANCE_BROWSER, "", "", "", "", "");
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页

View File

@ -51,6 +51,7 @@ import java.io.IOException
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
/**
* 引导页面
@ -79,6 +80,7 @@ class SplashScreenActivity : BaseActivity() {
mIsNewForThisVersion =
mSharedPreferences!!.getBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), true)
HaloApp.getInstance().isNewForThisVersion = mIsNewForThisVersion
HaloApp.getInstance().isBrandNewInstall = SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)
// 用户不是新版本,但应用最后更新时间不是上次的时间代表用户重新安装了当前版本
if (!mIsNewForThisVersion) {
@ -104,12 +106,11 @@ class SplashScreenActivity : BaseActivity() {
guideLayout.adapter = GuidePagerAdapter()
// 判断是不是光环的新用户
if (SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)) {
if (HaloApp.getInstance().isBrandNewInstall) {
// 引导页需用户点击 “立即体验” 按钮才进入首页所以这里不能置为true
// https://git.ghzs.com/pm/halo-app-issues/-/issues/1422第3点
// mStartMainActivityDirectly = true;
SPUtils.setLong(Constants.SP_INITIAL_USAGE_TIME, System.currentTimeMillis())
HaloApp.getInstance().isBrandNewInstall = true
if (!PackageFlavorHelper.IS_TEST_FLAVOR) {
showPrivacyDialog(guideLayout)
} else {
@ -188,20 +189,6 @@ class SplashScreenActivity : BaseActivity() {
private fun showPrivacyDialog(guideLayout: ViewPager) {
NewPrivacyPolicyDialogFragment.show(this, null) { isSuccess: Boolean ->
if (isSuccess) {
// guideLayout.visibility = View.VISIBLE
// SPUtils.setBoolean(Constants.SP_BRAND_NEW_USER, false)
//
// // 恢复畅玩数据
// VHelper.recoverVDataIfPossible()
//
// requestPermission()
//
// // 检查是否有旧版本光环,有就删掉
// AppExecutor.ioExecutor.execute { deleteOutdatedUpdatePackage() }
// if (mStartMainActivityDirectly) {
// launchMainActivity()
// }
mShouldPrefetchData = false
prefetchData()
@ -226,12 +213,10 @@ class SplashScreenActivity : BaseActivity() {
} else {
DialogUtils.showPrivacyPolicyDisallowDialog(
this,
PrivacyPolicyEntity.createDefaultData(),
object : EmptyCallback {
override fun onCallback() {
showPrivacyDialog(guideLayout)
}
})
PrivacyPolicyEntity.createDefaultData()
) {
showPrivacyDialog(guideLayout)
}
}
}
}
@ -312,19 +297,7 @@ class SplashScreenActivity : BaseActivity() {
private fun doFlavorInit() {
HaloApp.getInstance().flavorProvider.init(HaloApp.getInstance(), this, PkgHelper.getActivateRatio())
val whiteListChannel = arrayListOf(
"GH_206",
"KS-GHZS-KY1",
"KS-GHZS-MC1",
"GDT_GHZS_MC1",
"T11-GH-APPDY-ZC01",
"T7-GH-APPDY-KY03",
"T8-GH-APPUX-KY04",
"T1-GHZS-MC01",
"T4-GHZS-MC03"
)
if (whiteListChannel.contains(HaloApp.getInstance().channel) || PackageFlavorHelper.IS_TEST_FLAVOR) {
if (HaloApp.getInstance().channel == "GH_206" || PackageFlavorHelper.IS_TEST_FLAVOR) {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
}
}
@ -440,11 +413,8 @@ class SplashScreenActivity : BaseActivity() {
@AfterPermissionGranted(REQUEST_PERMISSION_TAG)
private fun checkAndRequestPermission() {
if (EasyPermissions.hasPermissions(this, *mPermissions)) {
// 恢复畅玩数据
VHelper.recoverVDataIfPossible()
onPermissionsGranted(REQUEST_PERMISSION_TAG, ArrayList(mPermissions.toList()))
// 检查是否有旧版本光环,有就删掉
runOnIoThread { deleteOutdatedUpdatePackage() }
if (mStartMainActivityDirectly) {
if (com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0L) {
showGitLogDialogIfNeeded()
@ -467,6 +437,17 @@ class SplashScreenActivity : BaseActivity() {
}
}
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>?) {
super.onPermissionsGranted(requestCode, perms)
if (perms?.contains(Manifest.permission.READ_EXTERNAL_STORAGE) == true) {
// 恢复畅玩数据
VHelper.recoverVDataIfPossible()
// 检查是否有旧版本光环,有就删掉
runOnIoThread { deleteOutdatedUpdatePackage() }
}
}
// 检查下载文件夹下是否有旧版本的光环助手的包,有则删除
private fun deleteOutdatedUpdatePackage() {
try {

View File

@ -208,9 +208,9 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
}
holder.binding.libaodetailName.setText(mLibaoEntity.getName());
if (TextUtils.isEmpty(mLibaoEntity.getPlatform())) {
holder.binding.libaodetailName.setText(mLibaoEntity.getGame().getName());
holder.binding.libaodetailGameName.setText(mLibaoEntity.getGame().getName());
} else {
holder.binding.libaodetailName.setText((mLibaoEntity.getGame().getName() + " - " +
holder.binding.libaodetailGameName.setText((mLibaoEntity.getGame().getName() + " - " +
PlatformUtils.getInstance(mContext).getPlatformName(mLibaoEntity.getPlatform())));
}

View File

@ -12,7 +12,6 @@ import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import com.airbnb.lottie.LottieAnimationView;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CertificationHandler;
import com.gh.common.chain.ChainBuilder;
@ -23,14 +22,13 @@ import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.OverseaDownloadHandler;
import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.chain.UpdateNewSimulatorHandler;
import com.gh.common.chain.ValidateVSpaceHandler;
import com.gh.common.chain.VersionNumberHandler;
import com.gh.common.constant.Config;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.GameOffServiceDialogFragment;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryHelper;
@ -38,41 +36,43 @@ import com.gh.common.simulator.NewSimulatorGameManager;
import com.gh.common.simulator.SimulatorDownloadManager;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageLauncher;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.common.util.DialogUtils;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.common.util.LogUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.eventbus.EBScroll;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.teenagermode.TeenagerModeActivity;
import com.gh.vspace.VDownloadManagerActivity;
import com.gh.vspace.VHelper;
import com.gh.vspace.VSpaceLoadingActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
@ -121,6 +121,8 @@ public class DetailViewHolder {
final OnDetailDownloadClickListener listener = new OnDetailDownloadClickListener(this, entrance, name, title, traceEvent);
mDownloadPb.setOnClickListener(listener);
ExtensionsKt.putWidgetBusinessName(mDownloadPb, "游戏详情页");
ExtensionsKt.putObject(mDownloadPb, gameEntity);
restoreDialogFragment();
}
@ -138,13 +140,13 @@ public class DetailViewHolder {
}
static class OnDetailDownloadClickListener implements View.OnClickListener {
private DetailViewHolder mViewHolder;
private GameEntity mGameEntity;
private final DetailViewHolder mViewHolder;
private final GameEntity mGameEntity;
private DownloadEntity mDownloadEntity;
private String mEntrance;
private String mName;
private String mTitle;
private ExposureEvent mTraceEvent;
private final String mEntrance;
private final String mName;
private final String mTitle;
private final ExposureEvent mTraceEvent;
public OnDetailDownloadClickListener(DetailViewHolder viewHolder, String entrance, String name, String title, ExposureEvent traceEvent) {
mViewHolder = viewHolder;
@ -158,67 +160,7 @@ public class DetailViewHolder {
@Override
public void onClick(View v) {
if (mViewHolder.mDownloadPb.getButtonStyle() != DownloadButton.ButtonStyle.RESERVABLE && mViewHolder.mDownloadPb.getButtonStyle() != DownloadButton.ButtonStyle.RESERVED) {
SensorsBridge.trackEvent(
"DownLoadbuttonClick",
"game_id", mGameEntity.getId(),
"game_name", mGameEntity.getName(),
"game_type", mGameEntity.getCategoryChinese(),
"download_status", mGameEntity.getDownloadStatusChinese(),
"button_name", mViewHolder.mDownloadPb.getText(),
"game_schema_type", mGameEntity.getGameBitChinese(),
"page_name", GlobalActivityManager.getCurrentPageEntity().getPageName(),
"page_id", GlobalActivityManager.getCurrentPageEntity().getPageId(),
"page_business_id", GlobalActivityManager.getCurrentPageEntity().getPageBusinessId(),
"last_page_name", GlobalActivityManager.getLastPageEntity().getPageName(),
"last_page_id", GlobalActivityManager.getLastPageEntity().getPageId(),
"last_page_business_id", GlobalActivityManager.getLastPageEntity().getPageBusinessId()
);
}
// 这个 switch 纯粹是为了 MTA和上报光能任务 统计用的
switch (mViewHolder.mDownloadPb.getButtonStyle()) {
case DOWNLOADING_PLUGIN:
MtaHelper.onEvent("游戏详情_新", "插件化中", mGameEntity.getName());
break;
case DOWNLOADING_NORMAL:
MtaHelper.onEvent("游戏详情_新", "下载中", mGameEntity.getName());
break;
case NONE:
MtaHelper.onEvent("游戏详情_新", "关闭下载", mGameEntity.getName());
break;
case NORMAL:
MtaHelper.onEvent("游戏详情_新", "下载", mGameEntity.getName());
break;
case PLUGIN:
MtaHelper.onEvent("游戏详情_新", "插件化", mGameEntity.getName());
break;
case INSTALL_PLUGIN:
MtaHelper.onEvent("游戏详情_新", "安装插件化", mGameEntity.getName());
break;
case INSTALL_NORMAL:
MtaHelper.onEvent("游戏详情_新", "安装", mGameEntity.getName());
break;
case RESERVABLE:
MtaHelper.onEvent("游戏详情_新", "预约", mGameEntity.getName());
break;
case LAUNCH_OR_OPEN:
if (!mGameEntity.getApk().isEmpty()) {
}
break;
}
// 由于部分状态不包含在 downloadType 里,所以还是需要手动获取下载按钮文字判断点击时的状态
String downloadText = mViewHolder.mDownloadPb.getText().toString();
if (downloadText.contains("打开")) {
MtaHelper.onEvent("游戏详情_新", "打开", mGameEntity.getName());
} else if (downloadText.contains("启动")) {
MtaHelper.onEvent("游戏详情_新", "启动", mGameEntity.getName());
} else if (downloadText.contains("更新")) {
MtaHelper.onEvent("游戏详情_新", "更新", mGameEntity.getName());
}
v.setTag(null);
if (mViewHolder.mDownloadPb.getButtonStyle() != DownloadButton.ButtonStyle.INSTALL_NORMAL
&& mViewHolder.mDownloadPb.getButtonStyle() != DownloadButton.ButtonStyle.INSTALL_PLUGIN
&& mViewHolder.mDownloadPb.getButtonStyle() != DownloadButton.ButtonStyle.LAUNCH_OR_OPEN) {
@ -236,6 +178,9 @@ public class DetailViewHolder {
if (mDownloadEntity != null) {
String xapkStatus = mDownloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
if (XapkUnzipStatus.SUCCESS.name().equals(xapkStatus) && XapkInstaller.INSTANCE.isInstalling(mDownloadEntity.getPath())) {// 安装过程中避免重复点击
return;
}
if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
XapkInstaller.cancelUnzipTask(mDownloadEntity);
return;
@ -261,15 +206,12 @@ public class DetailViewHolder {
String offStatus = mGameEntity.getDownloadOffStatus();
if (offStatus != null && !"off".equals(offStatus)) {
if ("dialog".equals(offStatus)) {
// MtaHelper.onEvent("游戏下载状态按钮", "查看详情", mGameEntity.getName());
showOffServiceDialog(mGameEntity.getDownloadOffDialog());
} else if ("toast".equals(offStatus)) {
// MtaHelper.onEvent("游戏下载状态按钮", "关闭且toast", mGameEntity.getName());
EventBus.getDefault().post(new EBReuse(GameDetailFragment.SKIP_RATING));
Utils.toast(mViewHolder.context, "该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~");
}
} else {
// MtaHelper.onEvent("游戏下载状态按钮", "暂无下载", mGameEntity.getName());
Utils.toast(mViewHolder.context, "该游戏已关闭下载");
}
break;
@ -282,9 +224,8 @@ public class DetailViewHolder {
DataLogUtils.uploadGameLog(mViewHolder.context, mGameEntity.getId(), mGameEntity.getName(), mEntrance);
}
case PLUGIN:
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new UpdateNewSimulatorHandler());
builder.addHandler(new GamePermissionHandler());
builder.addHandler(new CheckStoragePermissionHandler());
@ -347,11 +288,11 @@ public class DetailViewHolder {
}
if (mGameEntity.isVGame()) {
VHelper.installOrLaunch(mViewHolder.context, mGameEntity);
VHelper.installOrLaunch(mViewHolder.context, mGameEntity, null);
return;
}
PackageUtils.launchApplicationByPackageName(mViewHolder.context, mGameEntity.getApk().get(0).getPackageName());
PackageLauncher.launchApp(mViewHolder.context, mGameEntity, mGameEntity.getApk().get(0).getPackageName());
} else {
GamePermissionDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity, mGameEntity.getInfo(), () -> {
PermissionHelper.checkStoragePermissionBeforeAction(mViewHolder.context, () -> {
@ -389,7 +330,7 @@ public class DetailViewHolder {
}
if (mGameEntity.isVGame()) {
VHelper.installOrLaunch(v.getContext(), mGameEntity);
VHelper.installOrLaunch(v.getContext(), mGameEntity, null);
return;
}
@ -436,7 +377,6 @@ public class DetailViewHolder {
}
break;
case H5_GAME:
MtaHelper.onEvent("H5页面", "入口", "详情页_" + mGameEntity.getName());
LinkEntity linkEntity = mGameEntity.getH5Link();
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
@ -482,7 +422,7 @@ public class DetailViewHolder {
}
if (mDownloadEntity != null) {
if (downloadText.contains("继续加载")) {
if (mViewHolder.mDownloadPb.getText().contains("继续加载")) {
DownloadManager.getInstance().resume(mDownloadEntity, true);
} else {
DownloadManager.getInstance().pause(mDownloadEntity.getUrl());

View File

@ -43,6 +43,7 @@ class AmwayAdapter(
context: Context,
private var mViewModel: AmwayViewModel,
private var mBasicExposureSource: List<ExposureSource>,
private var mUseAlternativeLayout: Boolean,
private var mLayoutManager: RecyclerView.LayoutManager
) : ListAdapter<AmwayListItemData>(context), IExposable {
@ -102,6 +103,7 @@ class AmwayAdapter(
mViewModel,
mEntityList[position],
mEntityList[position].blockPosition,
mUseAlternativeLayout,
mBasicExposureSource
)
}
@ -203,6 +205,7 @@ class AmwayAdapter(
viewModel: AmwayViewModel,
itemData: AmwayListItemData,
blockPosition: Int,
useAlternativeLayout: Boolean,
basicExposureSource: List<ExposureSource>
) {
val context = binding.root.context
@ -269,9 +272,22 @@ class AmwayAdapter(
}
binding.commentContainer.setOnClickListener {
val exposureSource = if (useAlternativeLayout) {
arrayListOf(ExposureSource("新首页"), ExposureSource("安利墙"))
} else {
arrayListOf(ExposureSource("安利墙"))
}.toJson()
val intent = RatingReplyActivity.getIntent(
context, amway.game.id, amway.comment, false, viewModel.entrance
?: "", EntranceConsts.ENTRANCE_AMWAY
context = context,
gameId = amway.game.id,
gameEntity = null,
comment = amway.comment,
commentId = amway.comment.id,
showKeyboardIfReplyListIsEmpty = false,
exposureSource = exposureSource,
entrance = viewModel.entrance ?: "",
path = EntranceConsts.ENTRANCE_AMWAY
)
SyncDataBetweenPageHelper.startActivityForResult(
binding.root.context,

View File

@ -145,7 +145,8 @@ class AmwayFragment : LazyListFragment<AmwayListItemData, AmwayViewModel>() {
}
add(ExposureSource("安利墙", ""))
}
mAdapter = AmwayAdapter(requireContext(), mViewModel, basicExposureSource, mLayoutManager)
mAdapter =
AmwayAdapter(requireContext(), mViewModel, basicExposureSource, mUseAlternativeLayout, mLayoutManager)
}
return mAdapter!!
}

View File

@ -193,6 +193,8 @@ class CategoryV2ListAdapter(
true,
"star&brief"
)
holder.binding.downloadBtn.putWidgetBusinessName("分类列表")
} else if (holder is FooterViewHolder) {
holder.run {
initItemPadding()

View File

@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.util.SparseArray
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@ -13,6 +14,7 @@ import android.widget.PopupWindow
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.syncpage.ISyncAdapterHandler
import com.gh.common.util.*
@ -30,6 +32,10 @@ import com.gh.gamecenter.databinding.ItemGameCollectionFlexTagBinding
import com.gh.gamecenter.databinding.PopupHistoryOptionBinding
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.TagInfoEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
import com.gh.gamecenter.history.ManageOption
@ -39,12 +45,19 @@ import com.google.android.flexbox.FlexboxLayout
class GamesCollectionAdapter(
context: Context,
private val mViewModel: GamesCollectionViewModel,
) : ListAdapter<GamesCollectionEntity>(context), ISyncAdapterHandler {
) : ListAdapter<GamesCollectionEntity>(context), ISyncAdapterHandler, IExposable {
private var mCurrentOption = ManageOption.OPTION_MANAGER
private var mPopWindow: PopupWindow? = null
private var mPopupBinding: PopupHistoryOptionBinding? = null
var selectItems = arrayListOf<String>()
private var mExposureEventArray: SparseArray<ExposureEvent>? = null
override fun setListData(updateData: MutableList<GamesCollectionEntity>?) {
mExposureEventArray = SparseArray(updateData?.size ?: 0)
super.setListData(updateData)
}
override fun getItemCount(): Int {
return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
@ -102,6 +115,19 @@ class GamesCollectionAdapter(
when (holder) {
is GameCollectionItemViewHolder -> {
val itemEntity = mEntityList[position]
val exposureEvent = ExposureEvent.createEvent(
GameEntity().apply {
sequence = position
},
listOf(
ExposureSource("个人主页", ""),
ExposureSource("游戏单", "${itemEntity.title}+${itemEntity.id}")
),
null,
ExposureType.EXPOSURE
)
mExposureEventArray?.put(position, exposureEvent)
holder.binding.run {
ImageUtils.display(poster, itemEntity.cover)
nameTv.text = itemEntity.title
@ -117,7 +143,7 @@ class GamesCollectionAdapter(
gameThree.goneIf(it < 3)
}
moreNumTv.goneIf((itemEntity.count?.game ?: 0) < 4)
moreNumTv.goneIf((itemEntity.count?.game ?: 0) < 4 || itemEntity.games?.size == 0)
moreNumTv.text = "+ " + ((itemEntity.count?.game ?: 0) - 3)
tagContainer.goneIf(itemEntity.count?.game != 0)
timeTv.text = TimeUtils.getFormatTime(itemEntity.time?.update ?: 0, "MM - dd")
@ -235,7 +261,8 @@ class GamesCollectionAdapter(
GameCollectionDetailActivity.getIntent(
mContext,
itemEntity.id,
isScrollToCommentArea = true
isScrollToCommentArea = true,
exposureSourceList = ArrayList(exposureEvent.source)
)
)
}
@ -294,7 +321,13 @@ class GamesCollectionAdapter(
} else {
if (mCurrentOption == ManageOption.OPTION_MANAGER) {
NewLogUtils.logEnterGameCollectionDetail(itemEntity.title, itemEntity.id)
mContext.startActivity(GameCollectionDetailActivity.getIntent(mContext, itemEntity.id))
mContext.startActivity(
GameCollectionDetailActivity.getIntent(
mContext,
itemEntity.id,
exposureSourceList = ArrayList(exposureEvent.source)
)
)
} else {
if (selectItems.contains(itemEntity.id)) {
selectItems.remove(itemEntity.id)
@ -459,4 +492,8 @@ class GamesCollectionAdapter(
checkAllCb.isChecked = selectItems.size == mEntityList.size
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? = mExposureEventArray!!.get(pos)
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = null
}

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter.collection
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import com.gh.common.exposure.ExposureListener
import com.gh.gamecenter.common.constant.EntranceConsts.*
import com.gh.gamecenter.common.view.SpacingItemDecoration
import com.gh.gamecenter.R
@ -76,6 +77,8 @@ class GamesCollectionFragment : ListFragment<GamesCollectionEntity, GamesCollect
mListViewModel.publishLiveData.observe(viewLifecycleOwner) {
mListViewModel.load(LoadType.REFRESH)
}
mListRv.addOnScrollListener(ExposureListener(this, provideListAdapter()))
}
override fun onLoadEmpty() {

View File

@ -137,8 +137,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
}
}
adapter.getUrlMap().put(PackageUtils.getPackageNameByPath(HaloApp.getInstance().getApplication(),
downloadEntity.getPath()), downloadEntity.getUrl());
adapter.getUrlMap().put(downloadEntity.getPackageName(), downloadEntity.getUrl());
// 用户焦点在下载管理页面时有任务完成,直接把所有下载完成的任务标记为已读
DownloadManager.getInstance().markDownloadedTaskAsRead();

View File

@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageLauncher;
import com.gh.common.util.PackageUtils;
import com.gh.common.xapk.XapkDialogHelper;
import com.gh.gamecenter.common.entity.IconFloat;
@ -210,7 +211,11 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
} else if (XapkUnzipStatus.SUCCESS.name().equals(xapkStatus)) {
viewHolder.binding.dmItemTvStartorpause.setButtonStyle(DownloadButton.ButtonStyle.XAPK_SUCCESS);
viewHolder.binding.dmItemTvStartorpause.setProgress(1000);
viewHolder.binding.dmItemTvStartorpause.setText(R.string.hundred_percent);
if (XapkInstaller.INSTANCE.isInstalling(downloadEntity.getPath())) {
viewHolder.binding.dmItemTvStartorpause.setText(R.string.installing);
} else {
viewHolder.binding.dmItemTvStartorpause.setText(R.string.install);
}
}
if (xapkStatus != null && !xapkStatus.isEmpty()) {
xapkStatusMap.put(downloadEntity.getUrl(), xapkStatus);
@ -264,12 +269,15 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
viewHolder.binding.dmItemTvStartorpause.setOnClickListener(v -> {
String str = ((DownloadButton) v).getText();
final String url = downloadEntity.getUrl();
final String currentXApkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
DownloadManager.getInstance().put(url, System.currentTimeMillis());
if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
if (XapkUnzipStatus.SUCCESS.name().equals(currentXApkStatus) && XapkInstaller.INSTANCE.isInstalling(downloadEntity.getPath())) {
return;
} else if (XapkUnzipStatus.UNZIPPING.name().equals(currentXApkStatus)) {
XapkInstaller.cancelUnzipTask(downloadEntity);
return;
} else if (XapkUnzipStatus.FAILURE.name().equals(xapkStatus)
|| XapkUnzipStatus.SUCCESS.name().equals(xapkStatus)) {
} else if (XapkUnzipStatus.FAILURE.name().equals(currentXApkStatus)
|| XapkUnzipStatus.SUCCESS.name().equals(currentXApkStatus)) {
PermissionHelper.checkStoragePermissionBeforeAction(mContext, () -> {
final String path = downloadEntity.getPath();
if (downloadEntity.isPluggable()
@ -334,7 +342,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
}
});
} else if (str.equals(mContext.getString(R.string.launch))) {
PackageUtils.launchApplicationByPackageName(mContext, downloadEntity.getPackageName());
PackageLauncher.launchApp(mContext, null, downloadEntity.getPackageName());
}
break;
case redirected:
@ -629,8 +637,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
statusMap.put(downloadEntity.getUrl(), downloadEntity.getStatus().name());
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
if (!ExtensionsKt.isSimulatorGame(downloadEntity)) {
urlMap.put(PackageUtils.getPackageNameByPath(mContext,
downloadEntity.getPath()), downloadEntity.getUrl());
urlMap.put(downloadEntity.getPackageName(), downloadEntity.getUrl());
mDownloadedList.add(downloadEntity);
}
} else {

View File

@ -15,12 +15,11 @@ import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.common.exposure.IExposable
import com.gh.common.simulator.SimulatorGameManager.isSimulatorGame
import com.gh.common.util.*
import com.gh.common.util.DownloadItemUtils.setOnClickListener
import com.gh.common.util.DownloadItemUtils.updateItem
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.utils.putWidgetBusinessName
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.feature.databinding.GameItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
@ -92,17 +91,18 @@ class NewInstalledGameFragmentAdapter(context: Context, private var mViewModel:
}
binding.gameName.text = name
generateExposureEvent(gameEntity)
setOnClickListener(
DownloadItemUtils.setOnClickListener(
binding.root.context,
binding.downloadBtn,
gameEntity,
1,
this@NewInstalledGameFragmentAdapter,
"(我的光环-已安装)", "我的光环-已安装" + ":" + gameEntity.name,
gameEntity.exposureEvent // , () -> MtaHelper.onEvent("下载管理", "已安装", binding.downloadBtn.getText().toString())
gameEntity.exposureEvent
)
updateItem(binding.root.context, gameEntity, GameViewHolder(binding), !gameEntity.isPluggable)
holder.itemView.setOnClickListener { v: View? ->
binding.downloadBtn.putWidgetBusinessName("下载管理")
DownloadItemUtils.updateItem(binding.root.context, gameEntity, GameViewHolder(binding), !gameEntity.isPluggable)
holder.itemView.setOnClickListener {
DataCollectionUtils.uploadClick(binding.root.context, "列表", "我的光环-我的游戏", gameEntity.name)
GameDetailActivity.startGameDetailActivity(
binding.root.context,

View File

@ -19,8 +19,6 @@ import com.gh.download.DownloadManager
import com.gh.download.dialog.DownloadDialog
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.CurrentActivityHolder
@ -335,6 +333,8 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
}
}
updateBtn.putWidgetBusinessName("下载管理")
updateBtn.putObject(update)
updateBtn.setOnClickListener {
val str: String = updateBtn.text.toString()
if ("更新" == str || str.contains("")) {
@ -380,7 +380,7 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
}
}
} else if (updateBtn.context.getString(R.string.launch) == str) {
PackageUtils.launchApplicationByPackageName(updateBtn.context, update.packageName)
PackageLauncher.launchApp(updateBtn.context, packageName = update.packageName)
} else if (updateBtn.context.getString(R.string.resume) == str) {
if (downloadEntity != null) {
DownloadManager.getInstance().resume(downloadEntity, true)
@ -401,21 +401,6 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
updateBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
}
}
SensorsBridge.trackEvent(
"DownLoadbuttonClick",
"game_id", update.id,
"game_name", update.name ?: "",
"game_type", update.categoryChinese,
"download_status", update.downloadStatusChinese,
"button_name", str,
"page_name", GlobalActivityManager.getCurrentPageEntity().pageName,
"page_id", GlobalActivityManager.getCurrentPageEntity().pageId,
"page_business_id", GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
"last_page_name", GlobalActivityManager.getLastPageEntity().pageName,
"last_page_id", GlobalActivityManager.getLastPageEntity().pageId,
"last_page_business_id", GlobalActivityManager.getLastPageEntity().pageBusinessId
)
}
}

View File

@ -16,11 +16,8 @@ import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.SensorsBridge.trackEvent
import com.gh.gamecenter.common.utils.addMetaExtra
import com.gh.gamecenter.common.utils.secondOrNull
import com.gh.gamecenter.common.utils.toProperReadableSize
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.utils.GsonUtils.toJson
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
@ -78,7 +75,9 @@ class UpdatableGameViewModel(
// 有闪退日志说这个 update 实体可能为空,实在看不原因 (
if (update == null) continue
// 筛选仅下载管理出现的插件化更新
if (update.isShowPlugin(PluginLocation.only_index) && update.downloadStatus != "smooth") {
if (update.isShowPlugin(PluginLocation.only_index)
&& update.downloadStatus != Constants.V_GAME
&& update.downloadStatus != Constants.V_GAME_32) {
val platform =
PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform)
if (!platform.isNullOrEmpty() && "官方版" != platform) {
@ -590,7 +589,8 @@ class UpdatableGameViewModel(
downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId)
downloadEntity.addMetaExtra(Constants.APK_MD5, update.md5)
downloadEntity.addMetaExtra(Constants.GAME_NAME, update.name)
downloadEntity.addMetaExtra(Constants.GAME_TYPE, update.categoryChinese)
downloadEntity.addMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE, update.categoryChinese)
downloadEntity.putGameCategory(update.category ?: "")
if (update.iconFloat != null) {
downloadEntity.addMetaExtra(Constants.GAME_ICON_FLOAT_TOP_TEXT, update.iconFloat?.upperLeftText)
downloadEntity.addMetaExtra(Constants.GAME_ICON_FLOAT_TOP_COLOR, update.iconFloat?.upperLeftColor)

View File

@ -0,0 +1,27 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.feature.entity.PersonalEntity
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
data class GameCollectionPlayerCreationEntity(
@SerializedName("tip_link")
val tipLink: LinkEntity? = null,
val data: List<PlayerCreationItem>? = ArrayList()
)
@Parcelize
data class GameCollectionHotListTab(
@SerializedName("_id")
val id: String = "",
val name: String = "",
var position: Int = -1
) : Parcelable
data class PlayerCreationItem(
val user: PersonalEntity? = null,
@SerializedName("game_list")
val gameList: GamesCollectionEntity? = null
)

View File

@ -18,6 +18,8 @@ data class GameInstall(
var installTime: Long = 0,
var version: String = "",
var isSmoothGame: Boolean = false, // 是否是畅玩游戏
var downloadStatus: String? = "", // 下载状态,对应 GameEntity 的 downloadStatus
var category: String? = "", // 类型,对应 GameEntity 的 category
var tag: Any? = null
) {
@ -35,6 +37,8 @@ data class GameInstall(
gameInstall.version = PackageUtils.getVersionNameByPackageName(installedPkgName) ?: "unknown"
gameInstall.packageName = installedPkgName
gameInstall.isSmoothGame = game.isVGame()
gameInstall.downloadStatus = game.downloadStatus
gameInstall.category = game.category
return gameInstall
}
}

View File

@ -1,5 +1,6 @@
package com.gh.gamecenter.entity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.IconFloat
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.entity.*
@ -60,7 +61,7 @@ data class GameUpdateEntity(
val downloadStatusChinese: String
get() = when (downloadStatus) {
"on" -> "开启"
"smooth" -> "畅玩"
Constants.V_GAME, Constants.V_GAME_32 -> "畅玩"
"appointment" -> "预约"
"demo" -> "试玩"
else -> ""

View File

@ -83,7 +83,7 @@ class ForumArticleAskListFragment : LazyListFragment<AnswerEntity, ForumArticleA
mListRv.setBackgroundColor(R.color.background_white.toColor(requireContext()))
mScrollCalculatorHelper = ForumScrollCalculatorHelper(R.id.horizontalVideoView, R.id.verticalVideoView, 0)
requireView().setBackgroundColor(R.color.background_white.toColor(requireContext()))
view?.setBackgroundColor(R.color.background_white.toColor(requireContext()))
mSkeletonScreen = Skeleton.bind(mBinding.listSkeleton)
.shimmer(true)
@ -142,13 +142,16 @@ class ForumArticleAskListFragment : LazyListFragment<AnswerEntity, ForumArticleA
override fun onLoadRefresh() {
super.onLoadRefresh()
requireView().setBackgroundColor(R.color.background_white.toColor(requireContext()))
// Fixhttps://sentry.shanqu.cc/organizations/lightgame/issues/288994/?project=22&query=LazyListFragment&statsPeriod=14d
// Fragment在内存泄露的情况下调用requireView()会触发崩溃这里替换为getView()方法
// TODO 解决Fragment内存泄露的问题
view?.setBackgroundColor(R.color.background_white.toColor(requireContext()))
}
override fun onLoadDone() {
super.onLoadDone()
requireView().setBackgroundColor(Color.TRANSPARENT)
AppExecutor.uiExecutor.executeWithDelay(Runnable {
view?.setBackgroundColor(Color.TRANSPARENT)
mBaseHandler.postDelayed(Runnable {
tryCatchInRelease {
scroll()
mScrollCalculatorHelper?.onScrollStateChanged(mListRv, RecyclerView.SCROLL_STATE_IDLE)
@ -158,12 +161,12 @@ class ForumArticleAskListFragment : LazyListFragment<AnswerEntity, ForumArticleA
override fun onLoadError() {
super.onLoadError()
requireView().setBackgroundColor(Color.TRANSPARENT)
view?.setBackgroundColor(Color.TRANSPARENT)
}
override fun onLoadEmpty() {
super.onLoadEmpty()
requireView().setBackgroundColor(Color.TRANSPARENT)
view?.setBackgroundColor(Color.TRANSPARENT)
}
override fun hideRefreshingLayout() {

View File

@ -773,7 +773,18 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
// 这里的 selectedPosition 指的是应该被高亮显示的 position
val selectedPosition = (position + positionOffset).roundToInt()
val selectedPosition = try {
(position + positionOffset).roundToInt()
} catch (e: IllegalArgumentException) {
// roundToInt() 方法有时候会报 Cannot round NaN value. 错误
// https://sentry.shanqu.cc/organizations/lightgame/issues/301377/?project=22
SentryHelper.onEvent(
"HOME_NAN_POSITION",
"value",
"$position+$positionOffset=(${position + positionOffset})"
)
position
}
val positionOffsetOnRealSelectedPosition = if (positionOffset >= 0.5) {
positionOffset - 1
} else {
@ -797,8 +808,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
// positionOffset 小于零,表示 indicator 当前位置处于选中的 tab 的左边
val indicatorOnLeft = positionOffset < 0F
val selectedTabBinding = mTabBindingList[selectedPosition]
val selectedTabImageStyle = mTabImageStyleList[selectedPosition]
val selectedTabBinding = mTabBindingList.safelyGetInRelease(selectedPosition) ?: return
val selectedTabImageStyle = mTabImageStyleList.safelyGetInRelease(selectedPosition) ?: return
// 前一个 tab、当前选中的 tab、后一个 tab 的显示比例
val preScaleRatio = 1 + abs(positionOffset) / 4

View File

@ -58,7 +58,7 @@ class WelcomeDialogFragment : BaseDialogFragment() {
DirectUtils.directToGameDetail(
requireContext(),
mWelcomeEntity?.link!!,
EntranceConsts.ENTRANCE_WELCOME
entrance = EntranceConsts.ENTRANCE_WELCOME
)
}
EntranceConsts.HOST_COLUMN -> {

View File

@ -1140,7 +1140,9 @@ class GameFragmentAdapter(
DirectUtils.directToGameCollectionSquare(
mContext,
"版块内容列表",
mViewModel.blockData?.name ?: ""
mViewModel.blockData?.name ?: "",
collectionName = column.name ?: "",
collectionId = column.id ?: ""
)
}
"column_test_v2" -> {
@ -1231,7 +1233,13 @@ class GameFragmentAdapter(
}
}
gameItemData.exposureEventList = exposureList
holder.bindGameCollectionList(gameCollectionItemDataList, "版块内容列表")
holder.bindGameCollectionList(
gameCollectionItemDataList,
"版块内容列表",
mBasicExposureSource,
mViewModel.blockData?.link ?: "",
mViewModel.blockData?.name ?: ""
)
}
private fun bindGameDoubleCard(holder: DoubleCardViewHolder, position: Int) {

View File

@ -961,7 +961,9 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
GameCollectionListItemData(
gameCollectionItem = item,
gameStartPosition = position,
outerSequence = subjectEntity.outerSequence + 1
outerSequence = subjectEntity.outerSequence + 1,
collectionId = subjectEntity.id ?: "",
collectionName = subjectEntity.name ?: "",
)
)
position += if (item.count?.game!! > 2) 3 else if (item.games?.size == 0) 0 else

View File

@ -105,6 +105,8 @@ class GameHorizontalSlideAdapter(
},
true
)
holder.binding.simpleGameContainer.downloadBtn.putWidgetBusinessName("横向专题列表")
}
}

View File

@ -61,14 +61,12 @@ class RankGameItem(val rankItemUi: RankGameItemUi) {
"专题合集-排行榜-$columnName:${gameEntity.name}",
exposureEvent,
clickCallback = null,
refreshCallback = object : EmptyCallback {
override fun onCallback() {
DownloadItemUtils.updateItem(root.context, gameEntity, GameViewHolder(root).also {
it.gameDownloadBtn = downloadTv
it.gameDownloadTips = downloadTipsLottie
it.multiVersionDownloadTv = multiVersionDownloadTv
}, true)
}
refreshCallback = {
DownloadItemUtils.updateItem(root.context, gameEntity, GameViewHolder(root).also {
it.gameDownloadBtn = downloadTv
it.gameDownloadTips = downloadTipsLottie
it.multiVersionDownloadTv = multiVersionDownloadTv
}, true)
},
allStateClickCallback = null
)
@ -78,6 +76,8 @@ class RankGameItem(val rankItemUi: RankGameItemUi) {
it.gameDownloadTips = downloadTipsLottie
it.multiVersionDownloadTv = multiVersionDownloadTv
}, true)
downloadTv.putWidgetBusinessName("专题合集")
}
}
}

View File

@ -120,6 +120,9 @@ class GameVerticalAdapter(
gameRatingTv.setTextColor(gameRatingTextColor)
gameRatingTv.text = gameRatingText
// 没错,产品就把这个通用样式叫推荐榜单专题
downloadTv.putWidgetBusinessName("推荐榜单专题")
// Fuck this view holder
val tempViewHolder =
holder.placeholderGameViewHolder ?: GameViewHolder(this@run.root).apply {

View File

@ -15,7 +15,6 @@ class GameVerticalSlideViewHolder(val binding: GameVerticalSlideItemBinding) :
verticalSlide: SubjectEntity,
itemClick: (Int, GameEntity) -> Unit,
transparentBackground: Boolean = false,
showGameIconGif: Boolean = true
): SpanCountPagerSnapHelper {
val context = binding.root.context
val spanCount = verticalSlide.list

View File

@ -8,6 +8,8 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
class GameCollectionDetailActivity : ToolBarActivity() {
@ -69,13 +71,17 @@ class GameCollectionDetailActivity : ToolBarActivity() {
gameCollectionId: String,
topCommentId: String = "",
isFromSquare: Boolean = false,
isScrollToCommentArea: Boolean = false
isScrollToCommentArea: Boolean = false,
exposureSourceList: ArrayList<ExposureSource>? = null
): 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)
if (exposureSourceList != null) {
bundle.putParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST, exposureSourceList)
}
return getTargetIntent(
context,
GameCollectionDetailActivity::class.java,

View File

@ -54,6 +54,7 @@ open class GameCollectionDetailAdapter(
private val type: AdapterType,
val mEntrance: String,
val mViewModel: GameCollectionDetailViewModel,
private val mBasicExposureSource: List<ExposureSource>? = null,
commentClosure: ((CommentEntity) -> Unit)? = null
) : BaseCommentAdapter(context, mViewModel, type, mEntrance, commentClosure), IExposable {
@ -121,7 +122,6 @@ open class GameCollectionDetailAdapter(
)
)
else -> super.onCreateViewHolder(parent, viewType)
}
}
@ -607,10 +607,16 @@ open class GameCollectionDetailAdapter(
initServerType(gameEntity)
val exposureSources = ArrayList<ExposureSource>().apply {
add(ExposureSource("游戏单", "${mViewModel.gameCollectionTitle}+${mViewModel.gameCollectionId}"))
add(
ExposureSource(
"游戏单详情",
"${mViewModel.gameCollectionTitle}+${mViewModel.gameCollectionId}"
)
)
}
val exposureEvent = ExposureEvent.createEvent(
val exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity,
mBasicExposureSource ?: arrayListOf(),
exposureSources,
null,
ExposureType.EXPOSURE
@ -637,6 +643,7 @@ open class GameCollectionDetailAdapter(
exposureEvent
)
}
binding.gameItemIncluded.downloadBtn.putWidgetBusinessName("游戏单")
DownloadItemUtils.setOnClickListener(
mContext,

View File

@ -44,6 +44,7 @@ import com.gh.gamecenter.entity.GamesCollectionDetailEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.login.user.UserManager
@ -111,13 +112,18 @@ class GameCollectionDetailFragment :
)
)
override fun provideListAdapter() =
mAdapter ?: GameCollectionDetailAdapter(
override fun provideListAdapter(): GameCollectionDetailAdapter {
val basicExposureSource =
requireArguments().getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
?: arrayListOf()
return mAdapter ?: GameCollectionDetailAdapter(
requireContext(),
BaseCommentAdapter.AdapterType.COMMENT,
mEntrance,
mListViewModel
mListViewModel,
basicExposureSource
).apply { mAdapter = this }
}
override fun getItemDecoration() = null
@ -768,6 +774,7 @@ class GameCollectionDetailFragment :
override fun onResume() {
super.onResume()
mElapsedHelper?.resetCounting()
mElapsedHelper?.resumeCounting()
DownloadManager.getInstance().addObserver(mDataWatcher)
if (!mIsPauseTopVideo) {
@ -808,6 +815,7 @@ class GameCollectionDetailFragment :
com.gh.common.util.NewFlatLogUtils.logGameCollectStayTime(stayTime, it.id, it.title)
}
mElapsedHelper?.pauseCounting()
mElapsedHelper?.elapsedTime?.let {
if (it >= 3) {
val trackEvent = JSONObject()

View File

@ -23,7 +23,7 @@ class GameCollectionCommentConversationAdapter(
type: AdapterType,
mEntrance: String,
commentClosure: ((CommentEntity) -> Unit)? = null
) : GameCollectionDetailAdapter(context, type, mEntrance, mViewModel, commentClosure) {
) : GameCollectionDetailAdapter(context, type, mEntrance, mViewModel, null, commentClosure) {
var topCommentVH: TopCommentItemViewHolder? = null

View File

@ -0,0 +1,26 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.os.Bundle
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.core.utils.DisplayUtils
class GameCollectionHotListActivity : BaseActivity() {
override fun getLayoutId(): Int {
return R.layout.activity_amway
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DisplayUtils.transparentStatusBar(this)
val containerFragment = supportFragmentManager.findFragmentByTag(
GameCollectionHotListWrapperFragment::class.java.name
)
?: GameCollectionHotListWrapperFragment().with(intent.extras)
supportFragmentManager.beginTransaction()
.replace(R.id.placeholder, containerFragment, GameCollectionHotListWrapperFragment::class.java.name)
.commitAllowingStateLoss()
}
}

View File

@ -0,0 +1,197 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.content.Context
import android.graphics.Typeface
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ItemGameCollectionHotListBinding
import com.gh.gamecenter.entity.GameCollectionHotListTab
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
class GameCollectionHotListAdapter(
context: Context,
private val mTabEntity: GameCollectionHotListTab? = null,
private val mViewModel: GameCollectionHotListViewModel,
private val mEntrance: String,
private val mPath: String,
private val mBasicExposureSource: List<ExposureSource>
) : ListAdapter<GameCollectionListItemData>(context), IExposable {
private val mCoverWidth = (DisplayUtils.getScreenWidth() - 40F.dip2px()) / 2
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == ItemViewType.ITEM_FOOTER) {
FooterViewHolder(
mLayoutInflater.inflate(
R.layout.refresh_footerview,
parent,
false
)
)
} else {
GameCollectionHotListItemViewHolder(parent.toBinding())
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameCollectionHotListItemViewHolder) {
val itemData = mEntityList[position]
itemData.exposureEvent = ExposureEvent.createEventWithSourceConcat(
GameEntity().apply {
outerSequence = mTabEntity?.position
sequence = position
},
mBasicExposureSource,
listOf(
ExposureSource(
"游戏单",
"${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id}"
)
)
)
val entity = itemData.gameCollectionItem
holder.binding.run {
root.background = R.drawable.background_shape_white_radius_8.toDrawable(mContext)
titleTv.setTextColor(R.color.text_title.toColor(mContext))
userTv.setTextColor(R.color.text_subtitle.toColor(mContext))
gameCountTv.setTextColor(R.color.text_subtitleDesc.toColor(mContext))
rankIv.goneIf(position > 2) {
rankIv.setImageResource(
when (position) {
0 -> R.drawable.icon_leaderboard_1
1 -> R.drawable.icon_leaderboard_2
else -> R.drawable.icon_leaderboard_3
}
)
}
rankTv.goneIf(position < 3) {
rankTv.typeface = Typeface.createFromAsset(mContext.assets, "fonts/d_din_bold_only_number.ttf")
rankTv.text = "${position + 1}"
}
stampIv.goneIf(entity?.stamp.isNullOrEmpty())
stampIv.setBackgroundResource(if (entity?.stamp == "official") R.drawable.label_game_collection_official else R.drawable.label_game_collection_special_choice)
titleTv.text = entity?.title
userTv.text = entity?.user?.name
coverImage.setTag(ImageUtils.TAG_TARGET_WIDTH, mCoverWidth)
ImageUtils.display(coverImage, entity?.cover)
ImageUtils.display(userIv, entity?.user?.icon)
val gameIcons = arrayListOf(gameImage1, gameImage2, gameImage3)
val games = entity?.games ?: arrayListOf()
gameIcons.forEachIndexed { index, gameIcon ->
gameIcon.goneIf(games.size < index + 1) {
val gameEntity = games[index].toGameEntity()
gameIcon.displayGameIcon(gameEntity)
gameIcon.setBorderColor(R.color.background_white)
gameIcon.setOnClickListener {
NewFlatLogUtils.logGameCollectionHotListClick(
mTabEntity?.name ?: "",
mTabEntity?.id ?: "",
mTabEntity?.name ?: "",
"游戏"
)
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity.id,
BaseActivity.mergeEntranceAndPath(mEntrance, mPath),
itemData.exposureEvent
)
}
}
}
gameCountTv.goneIf(games.isEmpty())
titleTv.maxLines = if (games.isEmpty()) 2 else 1
titleTv.layoutParams = (titleTv.layoutParams as ConstraintLayout.LayoutParams).apply {
topMargin = if (games.isEmpty()) 10F.dip2px() else 32F.dip2px()
}
entity?.count?.let { gameCountTv.text = "+${it.game - games.size}" }
listOf(userIv, userTv).forEach {
it.setOnClickListener {
NewFlatLogUtils.logGameCollectionHotListClick(
mTabEntity?.name ?: "",
mTabEntity?.id ?: "",
mTabEntity?.name ?: "",
"个人主页"
)
DirectUtils.directToHomeActivity(mContext, entity?.user?.id, 0, mEntrance, mPath)
}
}
root.setOnClickListener {
NewFlatLogUtils.logGameCollectionHotListClick(
mTabEntity?.name ?: "",
mTabEntity?.id ?: "",
mTabEntity?.name ?: "",
"游戏单"
)
DirectUtils.directToGameCollectionDetail(
it.context,
entity?.id ?: "",
mEntrance,
mPath,
itemData.exposureEvent
)
}
}
}
if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
holder.hint.setTextColor(ContextCompat.getColor(mContext, R.color.text_B3B3B3))
val lp = holder.itemView.layoutParams as RecyclerView.LayoutParams
lp.height = DisplayUtils.dip2px(48F)
lp.width = ViewGroup.LayoutParams.MATCH_PARENT
holder.itemView.layoutParams = lp
}
}
override fun getItemCount(): Int = if (mEntityList.isNotEmpty()) mEntityList.size + 1 else 0
override fun getEventByPosition(pos: Int): ExposureEvent? {
return mEntityList[pos].exposureEvent
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return mEntityList[pos].exposureEventList
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
val layoutManager = recyclerView.layoutManager
if (layoutManager is GridLayoutManager) {
layoutManager.spanSizeLookup = object : SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
if (getItemViewType(position) == ItemViewType.ITEM_FOOTER) {
return layoutManager.spanCount
}
return 1
}
}
}
}
class GameCollectionHotListItemViewHolder(val binding: ItemGameCollectionHotListBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,109 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.os.Bundle
import android.view.View
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.R
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
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.core.utils.TimeElapsedHelper
import com.gh.gamecenter.entity.GameCollectionHotListTab
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
class GameCollectionHotListFragment : ListFragment<GameCollectionListItemData, GameCollectionHotListViewModel>() {
private lateinit var mBasicExposureSource: List<ExposureSource>
private lateinit var mExposureListener: ExposureListener
private lateinit var mViewModel: GameCollectionHotListViewModel
private var mAdapter: GameCollectionHotListAdapter? = null
private var mTabEntity: GameCollectionHotListTab? = null
private val mElapsedHelper by lazy { TimeElapsedHelper() }
private var mIsLoadDone = false
override fun provideListAdapter(): GameCollectionHotListAdapter {
if (mAdapter == null) {
mAdapter = GameCollectionHotListAdapter(
requireContext(),
mTabEntity,
mViewModel,
mEntrance,
arguments?.getString(EntranceConsts.KEY_PATH) ?: "",
mBasicExposureSource
)
}
return mAdapter as GameCollectionHotListAdapter
}
override fun provideListViewModel(): GameCollectionHotListViewModel {
mViewModel = viewModelProvider(GameCollectionHotListViewModel.Factory(mTabEntity?.id ?: ""))
return mViewModel
}
override fun onCreate(savedInstanceState: Bundle?) {
mTabEntity = requireArguments().getParcelable(EntranceConsts.KEY_TAB)
mBasicExposureSource =
listOf(ExposureSource("游戏单热榜", ""), ExposureSource("游戏单合集", mTabEntity?.id ?: ""))
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (mListRefresh != null) {
mListRefresh!!.setColorSchemeResources(R.color.theme)
mListRefresh!!.setOnRefreshListener(this)
}
mLayoutManager = FixGridLayoutManager(requireContext(), 2)
mListRv.setPadding(16F.dip2px(), 0, 16F.dip2px(), 0)
(mListRv.itemAnimator as DefaultItemAnimator?)!!.supportsChangeAnimations = false
mListRv.layoutManager = mLayoutManager
mListRv.adapter = provideListAdapter()
mExposureListener = ExposureListener(this, provideListAdapter())
mListRv.addOnScrollListener(mExposureListener)
if (mReuseNoConn != null) mReuseNoConn!!.setOnClickListener { view1: View? -> onLoadRefresh() }
}
override fun getItemDecoration(): RecyclerView.ItemDecoration {
return GridSpacingItemDecoration(2, 8F.dip2px(), false, 0)
}
override fun onPause() {
super.onPause()
mElapsedHelper.pauseCounting()
NewFlatLogUtils.logGameCollectionHotListTabView(
mElapsedHelper.elapsedTime,
mTabEntity?.name ?: "",
mTabEntity?.id ?: "",
mTabEntity?.name ?: ""
)
}
override fun onResume() {
super.onResume()
mElapsedHelper.resetCounting()
mElapsedHelper.resumeCounting()
if (mIsLoadDone) {
onChanged(mViewModel.obsListData.value)
}
}
override fun onChanged(ts: MutableList<GameCollectionListItemData>?) {
if (ts != null) {
if (mIsLoadDone) {
super.onChanged(ts)
}
mIsLoadDone = true
}
}
fun setListRefreshEnable(enable: Boolean) {
mListRefresh?.isEnabled = enable
}
}

View File

@ -0,0 +1,48 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.Observable
class GameCollectionHotListViewModel(application: Application, private val mCollectionId: String) :
ListViewModel<GamesCollectionEntity, GameCollectionListItemData>(application) {
private val mApi = RetrofitManager.getInstance().api
override fun provideDataObservable(page: Int): Observable<MutableList<GamesCollectionEntity>> {
return mApi.getGameCollectionHotList(mCollectionId)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
var position = 0
val itemDataList = ArrayList<GameCollectionListItemData>()
for (item in it) {
item.games = RegionSettingHelper.filterSimpleGame(item.games)
itemDataList.add(
GameCollectionListItemData(
gameCollectionItem = item,
gameStartPosition = position,
isGameCollectionItem = true
)
)
position += if (item.count?.game!! > 2) 3 else if (item.games?.size == 0) 0 else item.count?.game ?: 0
}
mResultLiveData.postValue(itemDataList)
mLoadStatusLiveData.postValue(LoadStatus.INIT_OVER)
}
}
class Factory(private val mCollectionId: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return GameCollectionHotListViewModel(HaloApp.getInstance().application, mCollectionId) as T
}
}
}

View File

@ -0,0 +1,241 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.TimeElapsedHelper
import com.gh.gamecenter.databinding.FragmentGameCollectionHotListWrapperBinding
import com.gh.gamecenter.entity.GameCollectionHotListTab
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import kotlin.math.abs
class GameCollectionHotListWrapperFragment : LazyFragment() {
private lateinit var mBinding: FragmentGameCollectionHotListWrapperBinding
private lateinit var mViewModel: GameCollectionHotListWrapperViewModel
private val mTabEntityList = arrayListOf<GameCollectionHotListTab>()
private var mAdapter: FragmentStateAdapter? = null
private var mIsCollapsed = false
override fun getRealLayoutId(): Int = R.layout.fragment_game_collection_hot_list_wrapper
override fun onFragmentPause() {
super.onFragmentPause()
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
if (mTabEntityList.isNotEmpty()) {
NewFlatLogUtils.logGameCollectionHotListExit(
stayTime,
mTabEntityList.safelyGetInRelease(mBinding.viewPager.currentItem)?.name ?: ""
)
}
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
mViewModel = viewModelProvider()
mViewModel.hotListTabListLiveData.observe(this) {
if (it != null) {
mTabEntityList.clear()
mTabEntityList.add(GameCollectionHotListTab(name = PLAYER_CREATION_TAB_NAME, position = 0))
mTabEntityList.addAll(it)
initViewPager()
initTabLayout()
} else {
mBinding.reuseNoConnection.root.visibility = View.VISIBLE
}
}
NewFlatLogUtils.logGameCollectionHotListEnter(mEntrance)
}
override fun onRealLayoutInflated(inflatedView: View) {
super.onRealLayoutInflated(inflatedView)
mBinding = FragmentGameCollectionHotListWrapperBinding.bind(inflatedView)
}
override fun initRealView() {
super.initRealView()
mBinding.run {
ViewCompat.setOnApplyWindowInsetsListener(appbar) { _, insets ->
(toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin =
insets.systemWindowInsetTop
insets.consumeSystemWindowInsets()
}
val collapsingTrigger = 66F.dip2px() + DisplayUtils.getStatusBarHeight(requireContext().resources)
toolbar.setNavigationOnClickListener { requireActivity().finish() }
collapsingToolbar.scrimVisibleHeightTrigger = collapsingTrigger
collapsingToolbar.scrimShownAction = {
mIsCollapsed = it
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && it)
changeToolbarStyle(it)
}
appbar.addOnOffsetChangedListener { _, verticalOffset ->
val absOffset = abs(verticalOffset)
val invisibleOffset = DisplayUtils.dip2px(30F)
if (absOffset <= invisibleOffset) {
titleTv.alpha = 1 - (absOffset.toFloat() / invisibleOffset)
} else {
titleTv.alpha = 0F
}
val currentFragment = childFragmentManager.findFragmentByTag("f${mBinding.viewPager.currentItem}")
if (currentFragment is GameCollectionPlayerCreationFragment) {
currentFragment.setListRefreshEnable(absOffset <= 2)
} else if (currentFragment is GameCollectionHotListFragment) {
currentFragment.setListRefreshEnable(absOffset <= 2)
}
}
reuseNoConnection.connectionReloadTv.setOnClickListener {
reuseNoConnection.root.visibility = View.GONE
mViewModel.getGameCollectionHotListTab()
}
}
}
private fun changeToolbarStyle(isCollapsed: Boolean) {
if (isCollapsed) {
mBinding.titleTv.alpha = 1F
mBinding.titleTv.visibility = View.VISIBLE
mBinding.titleTv.setTextColor(R.color.text_black.toColor(requireContext()))
mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back)
mBinding.collapsingToolbar.setContentScrimColor(R.color.background_white.toColor(requireContext()))
mBinding.tabContainer.setBackgroundColor(R.color.background_white.toColor(requireContext()))
mBinding.tabLayout.layoutParams = (mBinding.tabLayout.layoutParams as ConstraintLayout.LayoutParams).apply {
topMargin = 12F.dip2px()
}
} else {
mBinding.titleTv.visibility = View.GONE
mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back_light)
mBinding.collapsingToolbar.setContentScrimColor(R.color.background.toColor(requireContext()))
mBinding.tabContainer.background = null
mBinding.tabLayout.layoutParams = (mBinding.tabLayout.layoutParams as ConstraintLayout.LayoutParams).apply {
topMargin = 8F.dip2px()
}
}
}
private fun initTabLayout() {
mBinding.tabLayout.run {
TabLayoutMediator(this, mBinding.viewPager) { tab, position ->
val tabEntity = mTabEntityList.safelyGetInRelease(position)
val view = LayoutInflater.from(context).inflate(R.layout.game_collection_hot_list_tab_item, null)
view.findViewById<TextView>(R.id.tab_title)?.text = tabEntity?.name
tab.customView = view
updateTabStyle(tab, position == mBinding.viewPager.currentItem)
}.attach()
val firstTabView = (getChildAt(0) as ViewGroup).getChildAt(0)
firstTabView.layoutParams = (firstTabView.layoutParams as LinearLayout.LayoutParams).also {
it.leftMargin = 16F.dip2px()
}
val lastTabView = (getChildAt(0) as ViewGroup).getChildAt(mTabEntityList.size - 1)
lastTabView.layoutParams = (lastTabView.layoutParams as LinearLayout.LayoutParams).also {
it.rightMargin = 8F.dip2px()
}
addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
updateTabStyle(tab, true)
val tabEntity = mTabEntityList.safelyGetInRelease(tab.position)
NewFlatLogUtils.logGameCollectionHotListTabClick(
tabEntity?.name ?: "",
tabEntity?.id ?: "",
tabEntity?.name ?: ""
)
}
override fun onTabUnselected(tab: TabLayout.Tab) {
updateTabStyle(tab, false)
}
override fun onTabReselected(tab: TabLayout.Tab) {
updateTabStyle(tab, true)
}
})
}
}
private fun updateTabStyle(tab: TabLayout.Tab, isChecked: Boolean) {
tab.customView?.background =
if (isChecked) R.drawable.bg_game_collection_hot_list_tab_selected.toDrawable(requireContext()) else R.drawable.bg_game_collection_hot_list_tab_unselected.toDrawable(
requireContext()
)
tab.customView?.findViewById<TextView>(R.id.tab_title)?.run {
setTextColor(
if (isChecked) R.color.theme_font.toColor(requireContext()) else R.color.text_subtitleDesc.toColor(
requireContext()
)
)
}
}
private fun initViewPager() {
mAdapter = object : FragmentStateAdapter(this) {
override fun getItemCount(): Int = mTabEntityList.size
override fun createFragment(position: Int): Fragment {
val tabEntity = mTabEntityList.safelyGetInRelease(position)
return if (position == 0) {
GameCollectionPlayerCreationFragment().with(
bundleOf(
EntranceConsts.KEY_ENTRANCE to mEntrance,
EntranceConsts.KEY_PATH to "游戏单热榜"
)
)
} else {
GameCollectionHotListFragment().with(
bundleOf(
EntranceConsts.KEY_TAB to tabEntity,
EntranceConsts.KEY_ENTRANCE to mEntrance,
EntranceConsts.KEY_PATH to "游戏单热榜"
)
)
}
}
}
mBinding.viewPager.adapter = mAdapter
mBinding.viewPager.isUserInputEnabled = false
mBinding.viewPager.offscreenPageLimit = 3
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && mIsCollapsed)
for (i in 0 until mBinding.tabLayout.tabCount) {
val tab = mBinding.tabLayout.getTabAt(i)
if (tab != null) {
updateTabStyle(tab, tab.isSelected)
}
}
}
companion object {
const val PLAYER_CREATION_TAB_NAME = "#玩家创作榜"
}
}

View File

@ -0,0 +1,46 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.entity.GameCollectionHotListTab
import com.gh.gamecenter.entity.GameCollectionPlayerCreationEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import retrofit2.HttpException
class GameCollectionHotListWrapperViewModel(application: Application) : AndroidViewModel(application) {
private val mApi = RetrofitManager.getInstance().api
val hotListTabListLiveData = MutableLiveData<List<GameCollectionHotListTab>?>()
init {
getGameCollectionHotListTab()
}
fun getGameCollectionHotListTab() {
mApi.gameCollectionHotListTab
.compose(observableToMain())
.subscribe(object : Response<List<GameCollectionHotListTab>>() {
override fun onResponse(response: List<GameCollectionHotListTab>?) {
super.onResponse(response)
response?.let {
val hotListTabList = ArrayList<GameCollectionHotListTab>()
it.forEachIndexed { index, entity ->
hotListTabList.add(entity.apply {
position = index + 1
})
}
hotListTabListLiveData.postValue(hotListTabList)
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
hotListTabListLiveData.postValue(null)
}
})
}
}

View File

@ -0,0 +1,210 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.content.Context
import android.graphics.Typeface
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ItemGameCollectionPlayerCreationBinding
import com.gh.gamecenter.databinding.ItemGameCollectionPlayerCreationHeaderBinding
import com.gh.gamecenter.entity.PlayerCreationItem
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.login.user.UserManager
class GameCollectionPlayerCreationAdapter(
context: Context,
private val mViewModel: GameCollectionPlayerCreationViewModel,
private val mEntrance: String,
private val mPath: String,
) : ListAdapter<PlayerCreationItem>(context) {
private var mTipLinkEntity: LinkEntity? = null
fun setTipData(linkEntity: LinkEntity) {
mTipLinkEntity = linkEntity
notifyItemChanged(0)
}
override fun getItemViewType(position: Int): Int {
return if (position == 0) ItemViewType.ITEM_HEADER else if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.ITEM_FOOTER ->
FooterViewHolder(
mLayoutInflater.inflate(
R.layout.refresh_footerview,
parent,
false
)
)
ItemViewType.ITEM_HEADER -> GameCollectionPlayerCreationHeaderItemViewHolder(parent.toBinding())
else -> GameCollectionPlayerCreationItemViewHolder(parent.toBinding())
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameCollectionPlayerCreationHeaderItemViewHolder) {
mTipLinkEntity?.let { link ->
holder.binding.run {
tipsTv.text = link.text
tipsTv.setTextColor(R.color.text_subtitleDesc.toColor(mContext))
tipsIv.setOnClickListener {
DirectUtils.directToLinkPage(mContext, link, "", "")
}
}
}
}
if (holder is GameCollectionPlayerCreationItemViewHolder) {
val realPosition = position - 1
val entity = mEntityList[realPosition]
holder.binding.run {
root.setCardBackgroundColor(R.color.background_white.toColor(mContext))
gameCollectionCv.setCardBackgroundColor(R.color.background_space.toColor(mContext))
rankTv.setTextColor(R.color.text_subtitleDesc.toColor(mContext))
userNameTv.setTextColor(R.color.text_title.toColor(mContext))
userFansAndVoteCountTv.setTextColor(R.color.text_subtitleDesc.toColor(mContext))
gameCollectionCountTv.setTextColor(R.color.text_subtitle.toColor(mContext))
gameCollectionTitleTv.setTextColor(R.color.text_subtitle.toColor(mContext))
rankIv.goneIf(realPosition > 2) {
rankIv.setImageResource(
when (realPosition) {
0 -> R.drawable.icon_leaderboard_1
1 -> R.drawable.icon_leaderboard_2
else -> R.drawable.icon_leaderboard_3
}
)
}
rankTv.goneIf(realPosition < 3) {
rankTv.typeface = Typeface.createFromAsset(mContext.assets, "fonts/d_din_bold_only_number.ttf")
rankTv.text = "${realPosition + 1}"
}
userNameTv.text = entity.user?.name
userFansAndVoteCountTv.text = "${entity.user?.count?.fans}粉丝 ${entity.user?.count?.vote}赞同"
userAvatar.display(entity.user?.iconBorder?.url, entity.user?.icon)
followTv.goneIf(entity.user?.id == UserManager.getInstance().userId)
badgeIv.goneIf(entity?.user?.badge == null) {
ImageUtils.display(badgeIv, entity.user?.badge?.icon)
}
badgeIv.setOnClickListener {
DialogUtils.showViewBadgeDialog(mContext, entity?.user?.badge) {
DirectUtils.directToBadgeWall(
mContext,
entity?.user?.id,
entity?.user?.name,
entity?.user?.icon
)
}
}
entity?.user?.me?.let {
followTv.text = if (it.isFollower) "已关注" else "关注"
followTv.setTextColor(
if (it.isFollower) R.color.text_subtitleDesc.toColor(mContext) else R.color.theme_font.toColor(
mContext
)
)
followTv.background =
if (it.isFollower) R.drawable.button_round_gray_light.toDrawable(mContext) else R.drawable.button_round_primary_light.toDrawable(
mContext
)
followTv.setOnClickListener { view ->
mContext.ifLogin("板块成员") {
if (entity.user.id == UserManager.getInstance().userId) return@ifLogin
debounceActionWithInterval(view.id) {
NewFlatLogUtils.logGameCollectionHotListClick(
GameCollectionHotListWrapperFragment.PLAYER_CREATION_TAB_NAME,
"",
"",
"关注"
)
if (it.isFollower) {
mViewModel.followingCommand(entity.user.id, false) {
it.isFollower = false
notifyItemChanged(position)
}
} else {
mViewModel.followingCommand(entity.user.id, true) {
it.isFollower = true
notifyItemChanged(position)
}
}
}
}
}
}
gameCollectionCountTv.text = "${entity.user?.count?.gameList}"
gameCollectionTitleTv.text = entity?.gameList?.title
listOf(
userAvatar,
userNameTv,
userFansAndVoteCountTv,
gameCollectionCountTv,
gameCollectionIv
).forEach {
it.setOnClickListener {
NewFlatLogUtils.logGameCollectionHotListClick(
GameCollectionHotListWrapperFragment.PLAYER_CREATION_TAB_NAME,
"",
"",
"个人主页"
)
DirectUtils.directToHomeActivity(mContext, entity?.user?.id, 0, mEntrance, mPath)
}
}
listOf(gameCollectionTitleTv, moreIv).forEach {
it.setOnClickListener {
NewFlatLogUtils.logGameCollectionHotListClick(
GameCollectionHotListWrapperFragment.PLAYER_CREATION_TAB_NAME,
"",
"",
"游戏单"
)
DirectUtils.directToGameCollectionDetail(
mContext,
entity?.gameList?.id ?: "",
mEntrance,
mPath,
ExposureEvent.createEvent(null, listOf(ExposureSource("游戏单热榜-玩家创作榜")))
)
}
}
}
}
if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
holder.hint.setTextColor(ContextCompat.getColor(mContext, R.color.text_B3B3B3))
val lp = holder.itemView.layoutParams as RecyclerView.LayoutParams
lp.height = DisplayUtils.dip2px(48F)
lp.width = ViewGroup.LayoutParams.MATCH_PARENT
holder.itemView.layoutParams = lp
}
}
override fun getItemCount(): Int = if (mEntityList.isNotEmpty()) mEntityList.size + 2 else 0
class GameCollectionPlayerCreationItemViewHolder(val binding: ItemGameCollectionPlayerCreationBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
class GameCollectionPlayerCreationHeaderItemViewHolder(val binding: ItemGameCollectionPlayerCreationHeaderBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,71 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.core.utils.TimeElapsedHelper
import com.gh.gamecenter.entity.GamesCollectionEntity
class GameCollectionPlayerCreationFragment :
ListFragment<GamesCollectionEntity, GameCollectionPlayerCreationViewModel>() {
private val mElapsedHelper by lazy { TimeElapsedHelper() }
private lateinit var mViewModel: GameCollectionPlayerCreationViewModel
private var mAdapter: GameCollectionPlayerCreationAdapter? = null
override fun provideListAdapter(): GameCollectionPlayerCreationAdapter {
if (mAdapter == null) {
mAdapter =
GameCollectionPlayerCreationAdapter(
requireContext(),
provideListViewModel(),
mEntrance,
arguments?.getString(EntranceConsts.KEY_PATH) ?: ""
)
}
return mAdapter as GameCollectionPlayerCreationAdapter
}
override fun provideListViewModel(): GameCollectionPlayerCreationViewModel {
mViewModel = viewModelProvider()
return mViewModel
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel.topLinkLiveData.observeNonNull(this) {
mAdapter?.setTipData(it)
}
}
override fun onPause() {
super.onPause()
mElapsedHelper.pauseCounting()
NewFlatLogUtils.logGameCollectionHotListTabView(
mElapsedHelper.elapsedTime,
GameCollectionHotListWrapperFragment.PLAYER_CREATION_TAB_NAME,
"",
""
)
}
override fun onResume() {
super.onResume()
mElapsedHelper.resetCounting()
mElapsedHelper.resumeCounting()
}
override fun getItemDecoration(): RecyclerView.ItemDecoration {
mItemDecoration = VerticalItemDecoration(context, 8F, false)
return mItemDecoration
}
fun setListRefreshEnable(enable: Boolean) {
mListRefresh?.isEnabled = enable
}
}

View File

@ -0,0 +1,95 @@
package com.gh.gamecenter.gamecollection.hotlist
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.entity.AmwayCommentEntity
import com.gh.gamecenter.entity.GameCollectionPlayerCreationEntity
import com.gh.gamecenter.entity.PlayerCreationItem
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.SingleEmitter
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
class GameCollectionPlayerCreationViewModel(application: Application) :
ListViewModel<PlayerCreationItem, PlayerCreationItem>(application) {
private val mApi = RetrofitManager.getInstance().api
val topLinkLiveData = MutableLiveData<LinkEntity>()
override fun provideDataObservable(page: Int): Observable<MutableList<PlayerCreationItem>>? = null
override fun provideDataSingle(page: Int): Single<MutableList<PlayerCreationItem>> {
return Single.create {
if (page == 1) {
getGameCollectionPlayerCreation(it)
} else {
it.onSuccess(arrayListOf())
}
}
}
private fun getGameCollectionPlayerCreation(emitter: SingleEmitter<MutableList<PlayerCreationItem>>) {
mApi.gameCollectionPlayerCreation
.compose(observableToMain())
.subscribe(object : Response<GameCollectionPlayerCreationEntity>() {
override fun onResponse(response: GameCollectionPlayerCreationEntity?) {
super.onResponse(response)
response?.run {
tipLink?.let { topLinkLiveData.postValue(it) }
data?.let { emitter.onSuccess(ArrayList(it)) }
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
mLoadStatusLiveData.postValue(LoadStatus.INIT_FAILED)
}
})
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
mResultLiveData.postValue(it)
}
}
fun followingCommand(userId: String, isFollow: Boolean, onSuccess: () -> Unit) {
val observable = if (isFollow) {
mApi.postFollowing(userId)
} else {
mApi.deleteFollowing(userId)
}
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
onSuccess.invoke()
if (isFollow) {
Utils.toast(getApplication(), R.string.concern_success)
} else {
Utils.toast(getApplication(), R.string.concern_cancel)
}
EventBus.getDefault().post(EBUserFollow(userId, isFollow))
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
Utils.toast(getApplication(), R.string.loading_failed_hint)
}
})
}
}

View File

@ -22,7 +22,7 @@ class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBi
private val mLooperHandle = LooperHandle(this)
private val mSlideLooperKey = 333
fun bindAmway(amwayList: List<AmwayCommentEntity>) {
fun bindAmway(amwayList: List<AmwayCommentEntity>, viewModel: GameCollectionSquareViewModel) {
mAdapter.setAmwayList(amwayList)
binding.amwayVp.run {
if (adapter is GameCollectionAmwayAdapter) return
@ -32,7 +32,7 @@ class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBi
startAutoPlay()
}
binding.root.setOnClickListener {
NewLogUtils.logClickGameCollectionAmway()
NewLogUtils.logClickGameCollectionAmway(GameCollectionSquareViewModel.getOrderChineseByName(viewModel.view))
DirectUtils.directToAmway(binding.root.context)
NewLogUtils.logEnterGameCollectionAmway()
}

View File

@ -21,7 +21,7 @@ import com.lightgame.adapter.BaseRecyclerAdapter
class GameCollectionBannerAdapter(
context: Context,
private val isHome: Boolean = false,
private val mViewModel: GameCollectionSquareViewModel,
var mBannerList: List<CarouselEntity> = emptyList(),
private var mAmwayListItem: List<AmwayCommentEntity>? = null,
private val mEntrance: String = "",
@ -29,15 +29,15 @@ class GameCollectionBannerAdapter(
) :
BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
fun submitList(updateList: List<CarouselEntity>?, amwayList: List<AmwayCommentEntity>? = null) {
mBannerList = if (updateList.isNullOrEmpty()) emptyList() else ArrayList(updateList)
mAmwayListItem = if (amwayList.isNullOrEmpty()) emptyList() else ArrayList(amwayList)
fun submitList(updateList: List<CarouselEntity>? = null, amwayList: List<AmwayCommentEntity>? = null) {
updateList?.let { mBannerList = ArrayList(it) }
amwayList?.let { mAmwayListItem = ArrayList(it) }
AppExecutor.uiExecutor.execute {
notifyDataSetChanged()
}
}
private fun shouldShowAmway(position: Int) = isHome && getActualPosition(position) == getActualSize() - 1
private fun shouldShowAmway(position: Int) = getActualPosition(position) == getActualSize() - 1
override fun getItemViewType(position: Int) = if (shouldShowAmway(position)) ITEM_AMWAY else ITEM_BANNER
@ -53,7 +53,7 @@ class GameCollectionBannerAdapter(
holder.bindBanner(entity, getActualPosition(position))
}
} else if (holder is GameCollectionAmwayViewHolder) {
mAmwayListItem?.let { holder.bindAmway(it) }
mAmwayListItem?.let { holder.bindAmway(it, mViewModel) }
}
}
@ -68,7 +68,7 @@ class GameCollectionBannerAdapter(
return actualPosition
}
fun getActualSize() = if (isHome) mBannerList.size + 1 else mBannerList.size
fun getActualSize() = mBannerList.size + 1
fun getActualFirstPositionInCenter(): Int {
var index = itemCount / 2

View File

@ -9,7 +9,13 @@ data class GameCollectionListItemData(
var gameCollectionItem: GamesCollectionEntity? = null,
var amwayListItem: List<AmwayCommentEntity>? = null,
var carouselListItem: List<CarouselEntity>? = null,
var hotListTabName: String = "",
var gameStartPosition: Int = 0,
var outerSequence: Int = -1
var outerSequence: Int = -1,
var isHeaderItem: Boolean = false,
var isFilterItem: Boolean = false,
var isGameCollectionItem: Boolean = false,
var collectionId: String = "",
var collectionName: String = ""
) :
LegacyHomeItemData()

View File

@ -16,78 +16,130 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.common.exposure.IExposable
import com.gh.common.util.*
import com.gh.gamecenter.common.utils.ImageUtils.display
import com.gh.common.exposure.*
import com.gh.common.util.*
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.ImageUtils.display
import com.gh.gamecenter.common.view.ScrollEventListener
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.GameCollectionSquareItemBinding
import com.gh.gamecenter.databinding.ItemGameCollectionBannerBinding
import com.gh.gamecenter.databinding.ItemGameCollectionFilterBinding
import com.gh.gamecenter.databinding.ItemGameCollectionHeaderBinding
import com.gh.gamecenter.entity.AmwayCommentEntity
import com.gh.gamecenter.entity.CarouselEntity
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
import com.gh.gamecenter.gamecollection.tag.GameCollectionTagSelectActivity
import com.lightgame.view.NoScrollableViewPager
import java.lang.ref.WeakReference
class GameCollectionSquareAdapter(
context: Context,
private val isHome: Boolean = false,
private val mFragment: GameCollectionSquareFragment,
private val mViewModel: GameCollectionSquareViewModel,
private var mBasicExposureSource: List<ExposureSource>,
private val mOuterSequence: Int = -1
private val mOuterSequence: Int = -1,
private val mRefreshCallback: () -> Unit
) :
ListAdapter<GameCollectionListItemData>(context), IExposable {
private val mPosterWidth = DisplayUtils.getScreenWidth() - 32F.dip2px()
override fun setListData(updateData: MutableList<GameCollectionListItemData>?) {
if (updateData == null) {
mEntityList = ArrayList()
notifyDataSetChanged()
return
}
// 避免首页游戏单广场刷新列表后出现异常跳转位置
if (isHome && mEntityList.size == 2 && updateData.size > mEntityList.size) {
mEntityList = ArrayList(updateData)
notifyItemRangeInserted(2, updateData.size - 1)
return
}
// 避免手动刷新列表时出现异常动画
if (mEntityList != null && mEntityList.size > updateData.size) {
mEntityList = ArrayList(updateData)
notifyDataSetChanged()
return
}
calculateDiff(updateData)
}
fun setAmwayList(amwayList: List<AmwayCommentEntity>) {
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].amwayListItem == null) {
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].amwayListItem.isNullOrEmpty()) {
mEntityList[0].amwayListItem = amwayList
notifyItemChanged(0)
}
}
fun setBannerList(bannerList: List<CarouselEntity>) {
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].carouselListItem == null) {
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].carouselListItem.isNullOrEmpty()) {
mEntityList[0].carouselListItem = bannerList
notifyItemChanged(0)
}
}
override fun areItemsTheSame(oldItem: GameCollectionListItemData?, newItem: GameCollectionListItemData?) =
oldItem == newItem
fun setHotListTabName(tabName: String) {
if (isHome && mEntityList.isNotEmpty() && mEntityList[0].hotListTabName.isEmpty()) {
mEntityList[0].hotListTabName = tabName
notifyItemChanged(0)
}
}
override fun areItemsTheSame(oldItem: GameCollectionListItemData?, newItem: GameCollectionListItemData?): Boolean {
if (oldItem?.isHeaderItem == newItem?.isHeaderItem) return true
if (oldItem?.isFilterItem == newItem?.isFilterItem) return true
if (oldItem?.isGameCollectionItem == newItem?.isGameCollectionItem) return true
return false
}
override fun areContentsTheSame(
oldItem: GameCollectionListItemData?,
newItem: GameCollectionListItemData?
): Boolean {
if (oldItem?.isHeaderItem == newItem?.isHeaderItem) {
return (oldItem?.carouselListItem == newItem?.carouselListItem) && (oldItem?.amwayListItem == newItem?.amwayListItem)
}
if (oldItem?.isFilterItem == newItem?.isFilterItem) return true
if (oldItem?.isGameCollectionItem == newItem?.isGameCollectionItem) {
return oldItem?.gameCollectionItem == newItem?.gameCollectionItem
}
return false
}
override fun areContentsTheSame(oldItem: GameCollectionListItemData?, newItem: GameCollectionListItemData?) =
oldItem == newItem
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) {
ItemViewType.ITEM_FOOTER
if (isHome) {
if (position == 0) return ItemViewType.ITEM_HEADER
if (position == 1) return ITEM_FILTER
if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER
return ItemViewType.ITEM_BODY
} else {
when {
isHome && position == 0 -> ItemViewType.ITEM_HEADER
else -> ItemViewType.ITEM_BODY
}
if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER
return ItemViewType.ITEM_BODY
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.ITEM_HEADER -> GameCollectionBannerItemViewHolder(parent.toBinding())
ItemViewType.ITEM_HEADER -> GameCollectionHeaderItemViewHolder(parent.toBinding())
ITEM_FILTER -> GameCollectionFilterItemViewHolder(parent.toBinding())
ItemViewType.ITEM_BODY -> GameCollectionSquareItemViewHolder(parent.toBinding())
ItemViewType.ITEM_FOOTER -> FooterViewHolder(
mLayoutInflater.inflate(
@ -96,42 +148,52 @@ class GameCollectionSquareAdapter(
false
)
)
else -> GameCollectionSquareItemViewHolder(parent.toBinding())
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is GameCollectionBannerItemViewHolder -> {
is GameCollectionHeaderItemViewHolder -> {
val itemData = mEntityList[position]
holder.bindBanner(itemData, mBasicExposureSource)
holder.bindHeader(itemData, mBasicExposureSource, mViewModel)
}
is GameCollectionFilterItemViewHolder -> holder.bindFilter(mFragment, mViewModel, mRefreshCallback)
is GameCollectionSquareItemViewHolder -> {
val itemData = mEntityList[position]
val filterTagName = mViewModel.selectedTagName
val exposureEventList = arrayListOf<ExposureEvent>()
val exposureSource = listOf(
ExposureSource(
"游戏单",
"${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id} + ${
GameCollectionSquareViewModel.getOrderChineseByName(
mViewModel.view
)
} + $filterTagName"
)
)
itemData.gameCollectionItem?.games?.take(3)?.forEachIndexed { index, game ->
exposureEventList.add(
ExposureEvent.createEventWithSourceConcat(
game.toGameEntity().apply {
isAdData = itemData.gameCollectionItem?.adIconActive ?: false
outerSequence = mOuterSequence;
outerSequence = mOuterSequence
sequence = itemData.gameStartPosition + index + 1
},
mBasicExposureSource,
listOf(
ExposureSource(
"游戏单",
if (isHome) "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id}" else "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id} + $filterTagName"
)
)
exposureSource
)
)
}
itemData.exposureEventList = exposureEventList
itemData.gameCollectionItem?.let {
holder.bindGameCollection(mViewModel, it, itemData, isHome)
holder.bindGameCollection(mViewModel, it, itemData, isHome, ArrayList(mBasicExposureSource).apply {
addAll(exposureSource)
})
}
}
is FooterViewHolder -> {
@ -146,9 +208,10 @@ class GameCollectionSquareAdapter(
}
}
override fun getItemCount() = if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + 1
override fun getItemCount() =
if (mEntityList.isNullOrEmpty()) 0 else if (isHome && mEntityList.size == 2) mEntityList.size else mEntityList.size + 1
class GameCollectionBannerItemViewHolder(val binding: ItemGameCollectionBannerBinding) :
class GameCollectionHeaderItemViewHolder(val binding: ItemGameCollectionHeaderBinding) :
RecyclerView.ViewHolder(binding.root) {
private lateinit var mBannerAdapter: GameCollectionBannerAdapter
private lateinit var mSnapHelper: PagerSnapHelper
@ -156,18 +219,23 @@ class GameCollectionSquareAdapter(
private val mLooperHandle = LooperHandle(this)
private val mSlideLooperKey = 111
fun bindBanner(itemData: GameCollectionListItemData, mBasicExposureSource: List<ExposureSource>) {
fun bindHeader(
itemData: GameCollectionListItemData,
mBasicExposureSource: List<ExposureSource>,
viewModel: GameCollectionSquareViewModel
) {
val context = binding.root.context
val bannerList = itemData.carouselListItem ?: emptyList()
val amwayListItem = itemData.amwayListItem
if (::mBannerAdapter.isInitialized) {
mBannerAdapter.submitList(bannerList, amwayListItem)
binding.tabNameTv.text = itemData.hotListTabName
itemData.exposureEventList = getExposureEventList(bannerList, mBasicExposureSource)
if (mBannerAdapter.mBannerList.size != bannerList.size) {
binding.bannerIndicator.run {
mPageSize = mBannerAdapter.getActualSize()
pageSize = mBannerAdapter.getActualSize()
notifyDataChanged()
}
if (mBannerAdapter.getActualSize() > 1) {
@ -181,14 +249,14 @@ class GameCollectionSquareAdapter(
mBannerLayoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
mBannerAdapter = GameCollectionBannerAdapter(
context,
true,
viewModel,
bannerList,
amwayListItem,
"顶部tab-游戏单广场",
mBasicExposureSource
)
binding.bannerIndicator.run {
mPageSize = mBannerAdapter.getActualSize()
pageSize = mBannerAdapter.getActualSize()
notifyDataChanged()
}
binding.bannerRv.run {
@ -232,6 +300,10 @@ class GameCollectionSquareAdapter(
}
startAutoPlay()
}
binding.tabNameTv.text = itemData.hotListTabName
binding.hotListCv.setOnClickListener {
DirectUtils.directToGameCollectionHotList(context, "首页tab栏")
}
itemData.exposureEventList = getExposureEventList(bannerList, mBasicExposureSource)
}
@ -273,8 +345,8 @@ class GameCollectionSquareAdapter(
mLooperHandle.removeMessages(mSlideLooperKey)
}
class LooperHandle(viewHolder: GameCollectionBannerItemViewHolder) : Handler(Looper.getMainLooper()) {
private val mWeakReference: WeakReference<GameCollectionBannerItemViewHolder> = WeakReference(viewHolder)
class LooperHandle(viewHolder: GameCollectionHeaderItemViewHolder) : Handler(Looper.getMainLooper()) {
private val mWeakReference: WeakReference<GameCollectionHeaderItemViewHolder> = WeakReference(viewHolder)
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
@ -287,17 +359,70 @@ class GameCollectionSquareAdapter(
}
}
class GameCollectionSquareItemViewHolder(val binding: GameCollectionSquareItemBinding) :
class GameCollectionFilterItemViewHolder(val binding: ItemGameCollectionFilterBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindFilter(
fragment: GameCollectionSquareFragment,
viewModel: GameCollectionSquareViewModel,
refreshCallback: () -> Unit
) {
binding.orderSfv.run {
setContainerBackground(R.drawable.button_round_f5f5f5.toDrawable(context))
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(context))
setTextColor(
R.color.text_subtitle.toColor(context),
R.color.text_subtitleDesc.toColor(context)
)
}
binding.orderSfv.post {
// 防止标签文字过长
binding.tagTv.maxWidth =
DisplayUtils.getScreenWidth() - 80F.dip2px() - binding.orderSfv.width
}
val orderPosition = GameCollectionSquareViewModel.getOrderPositionByName(viewModel.view)
if (binding.orderSfv.getItemList().isEmpty()) {
binding.orderSfv.setItemList(listOf("推荐", "热门", "最新"), orderPosition)
} else if (binding.orderSfv.getCurrentPosition() != orderPosition) {
binding.orderSfv.setChecked(orderPosition)
}
binding.orderSfv.setOnCheckedCallback { position ->
viewModel.view = GameCollectionSquareViewModel.getOrderNameByPosition(position)
refreshCallback()
}
binding.tagTv.text = viewModel.selectedTagEntity?.name ?: "全部标签"
binding.tagFilter.background =
if (viewModel.selectedTagEntity != null) R.drawable.bg_game_collection_tag_select.toDrawable() else R.drawable.bg_game_collection_tag_unselect.toDrawable()
binding.tagFilter.setOnClickListener {
NewLogUtils.logEnterGameCollectionTag("首页tab栏")
fragment.startActivityForResult(
GameCollectionTagSelectActivity.getIntent(
fragment.requireContext(),
true,
viewModel.selectedTagEntity
),
GameCollectionSquareFragment.REQUEST_SELECT_TAG
)
}
}
}
inner class GameCollectionSquareItemViewHolder(val binding: GameCollectionSquareItemBinding) :
RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bindGameCollection(
viewModel: GameCollectionSquareViewModel,
gamesCollectionEntity: GamesCollectionEntity,
itemData: GameCollectionListItemData,
isHome: Boolean
isHome: Boolean,
exposureSource: List<ExposureSource>
) {
binding.run {
val context = root.context
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, mPosterWidth)
display(poster, gamesCollectionEntity.cover)
display(userIv, gamesCollectionEntity.user?.icon)
titleTv.text = gamesCollectionEntity.title
@ -418,7 +543,8 @@ class GameCollectionSquareAdapter(
GameCollectionDetailActivity.getIntent(
context,
gamesCollectionEntity.id,
!isHome
isFromSquare = !isHome,
exposureSourceList = ArrayList(exposureSource)
)
)
}
@ -457,13 +583,14 @@ class GameCollectionSquareAdapter(
mIsLoading = true
}
LoadStatus.INIT -> {
if (mEntityList != null) mEntityList.clear()
if (mEntityList != null) mEntityList.removeAll { it.isGameCollectionItem }
mIsNetworkError = false
mIsOver = false
mIsLoading = false
notifyDataSetChanged()
return
}
else -> {
//do nothing
}
@ -471,4 +598,8 @@ class GameCollectionSquareAdapter(
if (itemCount > 0 && status != LoadStatus.LIST_LOADED) notifyItemChanged(itemCount - 1)
}
companion object {
private const val ITEM_FILTER = 103
}
}

View File

@ -2,25 +2,32 @@ package com.gh.gamecenter.gamecollection.square
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.LinearLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieDrawable
import com.ethanhua.skeleton.Skeleton
import com.gh.common.exposure.*
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
@ -34,13 +41,14 @@ import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.ScrollEventListener
import com.gh.gamecenter.common.view.SegmentedFilterView
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.core.utils.ClickUtils
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeElapsedHelper
import com.gh.gamecenter.databinding.FragmentGameCollectionSquareAlBinding
import com.gh.gamecenter.databinding.FragmentGameCollectionSquareBinding
import com.gh.gamecenter.databinding.LayoutGameCollectionFilterGuideBinding
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.TagInfoEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
@ -69,6 +77,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
private lateinit var mBannerLayoutManager: LinearLayoutManager
private var mAdapter: GameCollectionSquareAdapter? = null
private var mGuideContainer: LinearLayout? = null
private val mElapsedHelper by lazy { TimeElapsedHelper() }
private val mLooperHandle = LooperHandle(this)
@ -77,6 +86,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
private var mUseAlternativeLayout = false
private var mIsCollapsed = false
private var mIsLoadDone = false
private var mForumName = ""
private var mGameCollectionTitle = ""
private var mGameCollectionId = ""
@ -100,19 +110,30 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mViewModel.isHome = mUseAlternativeLayout
mListViewModel.load(LoadType.NORMAL)
NewLogUtils.logEnterGameCollectionSquare(mEntrance, mForumName, mGameCollectionTitle, mGameCollectionId)
val collectionId = arguments?.getString(EntranceConsts.KEY_COLLECTION_ID, "") ?: ""
val collectionName = arguments?.getString(EntranceConsts.KEY_COLLECTION_NAME, "") ?: ""
NewLogUtils.logEnterGameCollectionSquare(
mEntrance,
mForumName,
mGameCollectionTitle,
mGameCollectionId,
collectionName,
collectionId
)
}
override fun onFragmentPause() {
super.onFragmentPause()
if (mUseAlternativeLayout) {
val rootView = (parentFragment as? HomeSearchToolWrapperFragment)?.view
rootView?.findViewById<ImageView>(R.id.fab)?.visibility = View.GONE
rootView?.findViewById<ImageView>(R.id.postFab)?.visibility = View.GONE
rootView?.findViewById<FrameLayout>(R.id.refreshFab)?.visibility = View.GONE
mGuideContainer?.visibility = View.GONE
} else {
if (mExposureEventList.isNotEmpty()) ExposureManager.log(mExposureEventList)
}
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
com.gh.common.util.NewFlatLogUtils.logGameCollectSquareStayTime(stayTime)
NewFlatLogUtils.logGameCollectSquareStayTime(stayTime, if (mUseAlternativeLayout) "首页tab栏" else "游戏单广场")
mElapsedHelper.pauseCounting()
if (mElapsedHelper.elapsedTime >= 3) {
@ -138,7 +159,16 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
super.onFragmentResume()
if (mUseAlternativeLayout) {
val rootView = (parentFragment as? HomeSearchToolWrapperFragment)?.view
rootView?.findViewById<ImageView>(R.id.fab)?.visibility = View.VISIBLE
rootView?.findViewById<ImageView>(R.id.postFab)?.visibility = View.VISIBLE
rootView?.findViewById<FrameLayout>(R.id.refreshFab)?.visibility = View.VISIBLE
if (mIsLoadDone) {
mGuideContainer?.goneIf(
!SPUtils.getBoolean(
Constants.SP_SHOW_GAME_COLLECTION_SQUARE_FILTER_GUIDE,
true
)
)
}
}
mElapsedHelper.resetCounting()
mElapsedHelper.resumeCounting()
@ -173,13 +203,25 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == REQUEST_SELECT_TAG) {
val tagInfoEntity = data.getParcelableExtra<TagInfoEntity>(GameCollectionTagSelectFragment.SELECTED_TAG)
val tagCategory = data.getStringExtra(GameCollectionTagSelectFragment.SELECTED_TAG_CATEGORY)
if (tagInfoEntity != null) {
NewLogUtils.logFilterGameCollectionTag(
tagCategory ?: "",
tagInfoEntity.name,
if (mUseAlternativeLayout) "首页tab栏" else "游戏单广场"
)
}
if (tagInfoEntity != mViewModel.selectedTagEntity) {
mDefaultBinding.tagTv.text = tagInfoEntity?.name ?: "全部标签"
mViewModel.selectedTagEntity = tagInfoEntity
mViewModel.selectedTagId = tagInfoEntity?.id ?: ""
mViewModel.selectedTagName = tagInfoEntity?.name ?: "全部标签"
mDefaultBinding.tagFilter.background =
if (tagInfoEntity != null) R.drawable.bg_game_collection_tag_select.toDrawable() else R.drawable.bg_game_collection_tag_unselect.toDrawable()
if (mUseAlternativeLayout) {
mAdapter?.notifyItemChanged(HOME_FILTER_ITEM_POSITION)
} else {
mDefaultBinding.tagFilterContainer.tagTv.text = tagInfoEntity?.name ?: "全部标签"
mDefaultBinding.tagFilterContainer.tagFilter.background =
if (tagInfoEntity != null) R.drawable.bg_game_collection_tag_select.toDrawable() else R.drawable.bg_game_collection_tag_unselect.toDrawable()
}
refresh()
}
}
@ -218,24 +260,22 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
GameCollectionSquareAdapter(
requireContext(),
mUseAlternativeLayout,
this,
mViewModel,
mBasicExposureSource,
outerSequence ?: (-1)
)
) {
refresh()
}
}
return mAdapter!!
}
private fun initDefaultLayout() {
mDefaultBinding.nightMaskView.goneIf(!mIsDarkModeOn)
mDefaultBinding.bannerBackground.background =
if (mIsDarkModeOn) ColorDrawable(R.color.background_white.toColor(requireContext())) else R.drawable.bg_game_collection_square_banner.toDrawable(
requireContext()
)
// toolbar 消费 fitsSystemWindows 避免在 collapsingToolbar 下面出现多出来的 padding
// [https://stackoverflow.com/questions/48137666/viewgroup-inside-collapsingtoolbarlayout-show-extra-bottom-padding-when-set-fits]
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn)
ViewCompat.setOnApplyWindowInsetsListener(mDefaultBinding.appbar) { _, insets ->
(mDefaultBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin =
insets.systemWindowInsetTop
@ -254,7 +294,6 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mDefaultBinding.collapsingToolbar.scrimVisibleHeightTrigger = collapsingTrigger
mDefaultBinding.collapsingToolbar.scrimShownAction = {
mIsCollapsed = it
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && it)
changeToolbarStyle(it)
}
@ -264,7 +303,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
}
mDefaultBinding.appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
mDefaultBinding.appbar.addOnOffsetChangedListener { _, verticalOffset ->
val absOffset = abs(verticalOffset)
val invisibleOffset = DisplayUtils.dip2px(30F)
@ -275,28 +314,22 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
mListRefresh?.isEnabled = absOffset <= 2
})
}
// mReuseNoData?.findViewById<TextView>(R.id.reuseNoneDataTv)?.text = "哎呀,没有找到相关内容~"
mDefaultBinding.orderSfv.post {
mDefaultBinding.tagFilterContainer.orderSfv.post {
// 防止标签文字过长
mDefaultBinding.tagTv.maxWidth =
DisplayUtils.getScreenWidth() - 80F.dip2px() - mDefaultBinding.orderSfv.width
mDefaultBinding.tagFilterContainer.tagTv.maxWidth =
DisplayUtils.getScreenWidth() - 80F.dip2px() - mDefaultBinding.tagFilterContainer.orderSfv.width
}
mDefaultBinding.tagFilterContainer.orderSfv.setItemList(listOf("推荐", "热门", "最新"), 0)
mDefaultBinding.tagFilterContainer.orderSfv.setOnCheckedCallback { position ->
mViewModel.view = GameCollectionSquareViewModel.getOrderNameByPosition(position)
refresh()
}
mDefaultBinding.orderSfv.setItemList(listOf("推荐", "热门", "最新"), 0)
mDefaultBinding.orderSfv.setOnCheckedCallback(object : SegmentedFilterView.OnCheckedCallback {
override fun onItemCheck(position: Int) {
when (position) {
0 -> mViewModel.view = "recommend"
1 -> mViewModel.view = "hot"
2 -> mViewModel.view = "new"
}
refresh()
}
})
mDefaultBinding.fab.setOnClickListener {
mDefaultBinding.postFab.setOnClickListener {
// 创建游戏单
ifLogin(mEntrance) {
showRegulationTestDialogIfNeeded {
@ -305,26 +338,36 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
}
mDefaultBinding.refreshFab.setOnClickListener {
if (!mDefaultBinding.refreshLottie.isAnimating) {
NewFlatLogUtils.logGameCollectionSquareFlush("点击刷新按钮", ++mViewModel.refreshCount)
mDefaultBinding.refreshLottie.playAnimation()
refresh()
}
}
mDefaultBinding.listRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > Constants.FOLLOW_HINT_TRIGGER_HEIGHT) {
setFabStatus(mDefaultBinding.fab, View.GONE)
} else if (dy < -Constants.FOLLOW_HINT_TRIGGER_HEIGHT) {
setFabStatus(mDefaultBinding.fab, View.VISIBLE)
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
setFabStatus(mDefaultBinding.postFab, View.GONE)
setFabStatus(mDefaultBinding.refreshFab, View.GONE)
} else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
setFabStatus(mDefaultBinding.postFab, View.VISIBLE)
setFabStatus(mDefaultBinding.refreshFab, View.VISIBLE)
}
}
})
val bannerAdapter = GameCollectionBannerAdapter(
requireContext(),
false,
mViewModel,
mEntrance = "游戏单广场",
mBasicExposureSource = mBasicExposureSource
)
mSnapHelper = PagerSnapHelper()
mBannerLayoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
mDefaultBinding.bannerRv.run {
mDefaultBinding.headerContainer.bannerRv.run {
adapter = bannerAdapter
layoutManager = mBannerLayoutManager
mSnapHelper.attachToRecyclerView(this)
@ -334,6 +377,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
MotionEvent.ACTION_DOWN -> {
mDefaultBinding.listRefresh.isEnabled = false
}
MotionEvent.ACTION_UP -> {
mDefaultBinding.listRefresh.isEnabled = true
}
@ -348,7 +392,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
setOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
mDefaultBinding.bannerIndicator.onPageScrolled(
mDefaultBinding.headerContainer.bannerIndicator.onPageScrolled(
bannerAdapter.getActualPosition(position),
positionOffset
)
@ -357,37 +401,19 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
})
}
mDefaultBinding.tagFilter.setOnClickListener {
mDefaultBinding.headerContainer.hotListCv.setOnClickListener {
DirectUtils.directToGameCollectionHotList(requireContext(), "游戏单广场")
}
mDefaultBinding.tagFilterContainer.tagFilter.setOnClickListener {
NewLogUtils.logEnterGameCollectionTag("游戏单广场")
startActivityForResult(
GameCollectionTagSelectActivity.getIntent(requireContext(), true, mViewModel.selectedTagEntity),
REQUEST_SELECT_TAG
)
}
mViewModel.mBannerList.observeNonNull(this) {
mDefaultBinding.tagFilterContainer.layoutParams =
(mDefaultBinding.tagFilterContainer.layoutParams as AppBarLayout.LayoutParams).apply {
setMargins(
0,
if (it.isEmpty()) (-16F).dip2px() else 0,
0,
0
)
}
mDefaultBinding.headIv.goneIf(it.isNotEmpty())
mDefaultBinding.bannerContainer.goneIf(it.isEmpty())
mDefaultBinding.titleIv.goneIf(it.isEmpty())
mDefaultBinding.sloganTv.goneIf(it.isEmpty())
mDefaultBinding.statusBar.setBackgroundColor(
if (it.isEmpty()) Color.TRANSPARENT
else if (mIsDarkModeOn) R.color.background_white.toColor(requireContext())
else R.color.game_collection_square.toColor(requireContext())
)
mDefaultBinding.toolbar.setBackgroundColor(
if (it.isEmpty()) Color.TRANSPARENT
else if (mIsDarkModeOn) R.color.background_white.toColor(requireContext())
else R.color.game_collection_square.toColor(requireContext())
)
mViewModel.bannerList.observeNonNull(this) {
if (it.isNotEmpty()) {
bannerAdapter.submitList(it)
mExposureEventList.clear()
@ -405,16 +431,24 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mExposureEventList.add(exposureEvent)
}
if (bannerAdapter.getActualSize() > 1) {
mDefaultBinding.bannerRv.scrollToPosition(bannerAdapter.getActualFirstPositionInCenter())
mDefaultBinding.headerContainer.bannerRv.scrollToPosition(bannerAdapter.getActualFirstPositionInCenter())
}
mDefaultBinding.bannerIndicator.run {
mPageSize = bannerAdapter.getActualSize()
mDefaultBinding.headerContainer.bannerIndicator.run {
pageSize = bannerAdapter.getActualSize()
notifyDataChanged()
}
startAutoPlay()
}
}
mViewModel.amwayCommentList.observeNonNull(this) {
bannerAdapter.submitList(amwayList = it)
}
mViewModel.hotListFirstTab.observeNonNull(this) {
mDefaultBinding.headerContainer.tabNameTv.text = it
}
mListRefresh?.setProgressViewOffset(
false,
0,
@ -427,29 +461,12 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
mDefaultBinding.titleTv.alpha = 1F
mDefaultBinding.titleTv.visibility = View.VISIBLE
mDefaultBinding.titleTv.setTextColor(R.color.text_black.toColor(requireContext()))
mDefaultBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back)
mDefaultBinding.tagFilterContainer.background = null
mDefaultBinding.titleIv.visibility = View.GONE
mDefaultBinding.sloganTv.visibility = View.GONE
mDefaultBinding.statusBar.setBackgroundColor(Color.TRANSPARENT)
mDefaultBinding.toolbar.setBackgroundColor(Color.TRANSPARENT)
} else {
mDefaultBinding.titleTv.visibility = View.GONE
mDefaultBinding.toolbar.navigationIcon = R.drawable.ic_bar_back_light.toDrawable(requireContext())
mDefaultBinding.tagFilterContainer.background =
R.drawable.bg_game_collection_square.toDrawable(requireContext())
mDefaultBinding.titleIv.goneIf(mViewModel.mBannerList.value.isNullOrEmpty())
mDefaultBinding.sloganTv.goneIf(mViewModel.mBannerList.value.isNullOrEmpty())
mDefaultBinding.statusBar.setBackgroundColor(
if (mViewModel.mBannerList.value.isNullOrEmpty()) Color.TRANSPARENT
else if (mIsDarkModeOn) R.color.background_white.toColor(requireContext())
else R.color.game_collection_square.toColor(requireContext())
)
mDefaultBinding.toolbar.setBackgroundColor(
if (mViewModel.mBannerList.value.isNullOrEmpty()) Color.TRANSPARENT
else if (mIsDarkModeOn) R.color.background_white.toColor(requireContext())
else R.color.game_collection_square.toColor(requireContext())
)
mDefaultBinding.titleIv.visibility = View.VISIBLE
mDefaultBinding.sloganTv.visibility = View.VISIBLE
}
}
@ -457,7 +474,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
val snapView = mSnapHelper.findSnapView(mBannerLayoutManager)
if (snapView != null) {
mBannerLayoutManager.smoothScrollToPosition(
mDefaultBinding.bannerRv,
mDefaultBinding.headerContainer.bannerRv,
null,
mBannerLayoutManager.getPosition(snapView) + 1
)
@ -465,7 +482,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
private fun startAutoPlay() {
if ((mDefaultBinding.bannerRv.adapter as GameCollectionBannerAdapter).getActualSize() <= 1) return
if ((mDefaultBinding.headerContainer.bannerRv.adapter as GameCollectionBannerAdapter).getActualSize() <= 1) return
stopAutoPlay()
mLooperHandle.sendEmptyMessageDelayed(mSlideLooperKey, BANNER_LOOP_TIME)
}
@ -476,15 +493,10 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
private fun initAlternativeLayout() {
if (parentFragment is HomeSearchToolWrapperFragment) {
val rootView = (parentFragment as HomeSearchToolWrapperFragment).view
if (rootView is RelativeLayout) {
val fabView = ImageView(context).apply {
id = R.id.fab
layoutParams = RelativeLayout.LayoutParams(60F.dip2px(), 60F.dip2px()).apply {
addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
setMargins(0, 0, 14F.dip2px(), 14F.dip2px())
}
val rootView = (parentFragment as HomeSearchToolWrapperFragment).view?.findViewById<CoordinatorLayout>(R.id.coordinator)
if (rootView != null) {
val postFabView = ImageView(context).apply {
id = R.id.postFab
background = R.drawable.community_edit_icon.toDrawable()
setOnClickListener {
ifLogin(mEntrance) {
@ -500,14 +512,50 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
}
}
rootView.addView(fabView)
val refreshLottieView = LottieAnimationView(requireContext()).apply {
id = R.id.refreshLottie
layoutParams = FrameLayout.LayoutParams(45F.dip2px(), 45F.dip2px()).apply {
gravity = Gravity.CENTER
}
setAnimation("lottie/icon_fab_change.json")
repeatMode = LottieDrawable.RESTART
}
val refreshFabView = FrameLayout(requireContext()).apply {
id = R.id.refreshFab
background = R.drawable.bg_fab_container.toDrawable()
addView(refreshLottieView)
setOnClickListener {
if (!refreshLottieView.isAnimating) {
NewFlatLogUtils.logGameCollectionSquareFlush("点击刷新按钮", ++mViewModel.refreshCount)
refreshLottieView.playAnimation()
refresh()
}
}
}
rootView.addView(postFabView, CoordinatorLayout.LayoutParams(60F.dip2px(), 60F.dip2px()).also {
it.gravity = Gravity.BOTTOM.xor(Gravity.END)
it.setMargins(0, 0, 8F.dip2px(), 32F.dip2px())
})
rootView.addView(refreshFabView, CoordinatorLayout.LayoutParams(60F.dip2px(), 60F.dip2px()).also {
it.gravity = Gravity.BOTTOM.xor(Gravity.END)
it.setMargins(0, 0, 8F.dip2px(), 92F.dip2px())
})
mGuideContainer = LayoutGameCollectionFilterGuideBinding.inflate(layoutInflater).root
rootView.addView(mGuideContainer, CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.MATCH_PARENT).apply {
behavior = AppBarLayout.ScrollingViewBehavior()
setMargins(0, 52F.dip2px(), 0, 0)
})
mAlternativeBinding.listRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > Constants.FOLLOW_HINT_TRIGGER_HEIGHT) {
setFabStatus(fabView, View.GONE)
} else if (dy < -Constants.FOLLOW_HINT_TRIGGER_HEIGHT) {
setFabStatus(fabView, View.VISIBLE)
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
setFabStatus(postFabView, View.GONE)
setFabStatus(refreshFabView, View.GONE)
} else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
setFabStatus(postFabView, View.VISIBLE)
setFabStatus(refreshFabView, View.VISIBLE)
}
}
})
@ -516,13 +564,17 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
// mReuseNoData?.findViewById<TextView>(R.id.reuseNoneDataTv)?.text = "哎呀,没有找到相关内容~"
mViewModel.mAmwayCommentList.observeNonNull(this) {
mViewModel.amwayCommentList.observeNonNull(this) {
mAdapter?.setAmwayList(it)
}
mViewModel.mBannerList.observeNonNull(this) {
mViewModel.bannerList.observeNonNull(this) {
mAdapter?.setBannerList(it)
}
mViewModel.hotListFirstTab.observeNonNull(this) {
mAdapter?.setHotListTabName(it)
}
}
private fun setFabStatus(fab: View, visibility: Int) {
@ -538,23 +590,43 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
override fun onLoadEmpty() {
super.onLoadEmpty()
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
showSkeleton(false)
if (mReuseNoConn != null) mReuseNoConn!!.visibility = View.GONE
if (mReuseNoData != null) mReuseNoData!!.visibility = View.VISIBLE
if (mListLoading != null) mListLoading!!.visibility = View.GONE
if (mDataExceptionView != null) mDataExceptionView!!.visibility = View.GONE
mListRv.isVisible = mUseAlternativeLayout
hideRefreshingLayout()
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.root.visibility = View.VISIBLE
}
override fun onLoadDone() {
super.onLoadDone()
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
mIsLoadDone = true
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.root.visibility = View.VISIBLE
val guideContainer =
if (mUseAlternativeLayout) mGuideContainer else mDefaultBinding.guideContainer
guideContainer?.goneIf(
!SPUtils.getBoolean(
Constants.SP_SHOW_GAME_COLLECTION_SQUARE_FILTER_GUIDE,
true
)
) {
guideContainer.setOnClickListener {
SPUtils.setBoolean(Constants.SP_SHOW_GAME_COLLECTION_SQUARE_FILTER_GUIDE, false)
guideContainer.visibility = View.GONE
}
}
}
override fun onLoadError() {
super.onLoadError()
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.GONE
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.root.visibility = View.GONE
}
override fun onLoadRefresh() {
super.onLoadRefresh()
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
refresh(true)
}
private fun initSkeleton() {
@ -578,14 +650,21 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
}
private fun refresh() {
private fun refresh(showSkeleton: Boolean = false) {
showSkeleton(showSkeleton)
if (mReuseNoConn != null) mReuseNoConn!!.visibility = View.GONE
if (mListLoading != null) mListLoading!!.visibility =
if (mListRefresh == null || !mListRefresh!!.isRefreshing) View.VISIBLE else View.GONE
if (mReuseNoData != null) mReuseNoData!!.visibility = View.GONE
if (mListRv != null) mListRv.visibility = View.GONE
if (mListRv != null && (!mUseAlternativeLayout || showSkeleton)) mListRv.visibility = View.GONE
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.root.visibility = View.VISIBLE
if (mUseAlternativeLayout) {
mAdapter?.run {
entityList?.removeAll { it.isGameCollectionItem }
notifyItemRangeRemoved(2, itemCount)
}
}
mBaseHandler.postDelayed({ mListViewModel.load(LoadType.REFRESH) }, 500)
if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
}
private fun scrollToTop() {
@ -607,6 +686,11 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
}
}
override fun onRefresh() {
NewFlatLogUtils.logGameCollectionSquareFlush("下拉刷新", ++mViewModel.refreshCount)
super.onRefresh()
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mItemDecoration?.let { mListRv?.removeItemDecoration(it) }
@ -618,15 +702,11 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
} else if (::mDefaultBinding.isInitialized) {
initSkeleton()
showSkeleton(mListViewModel.loadStatusLiveData.value == LoadStatus.INIT_LOADING)
mDefaultBinding.nightMaskView.goneIf(!mIsDarkModeOn)
mDefaultBinding.bannerBackground.background =
if (mIsDarkModeOn) ColorDrawable(R.color.background_white.toColor(requireContext())) else R.drawable.bg_game_collection_square_banner.toDrawable(
requireContext()
)
mDefaultBinding.listRefresh.setBackgroundColor(R.color.background_white.toColor(requireContext()))
mDefaultBinding.appbar.setBackgroundColor(R.color.background_white.toColor(requireContext()))
mDefaultBinding.toolbar.navigationIcon = R.drawable.ic_bar_back.toDrawable(requireContext())
mDefaultBinding.collapsingToolbar.setContentScrimColor(R.color.background_white.toColor(requireContext()))
mDefaultBinding.orderSfv.run {
mDefaultBinding.tagFilterContainer.orderSfv.run {
setContainerBackground(R.drawable.button_round_f5f5f5.toDrawable(requireContext()))
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(requireContext()))
setTextColor(
@ -634,7 +714,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
R.color.text_subtitleDesc.toColor(requireContext())
)
}
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && mIsCollapsed)
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn)
changeToolbarStyle(mIsCollapsed)
}
}
@ -642,6 +722,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
companion object {
const val REQUEST_SELECT_TAG = 100
const val BANNER_LOOP_TIME = 5000L
const val HOME_FILTER_ITEM_POSITION = 1
}
class LooperHandle(fragment: GameCollectionSquareFragment) : Handler(Looper.getMainLooper()) {

View File

@ -7,8 +7,9 @@ import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadParams
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
@ -19,24 +20,25 @@ import java.util.*
class GameCollectionSquareViewModel(application: Application) :
ListViewModel<GamesCollectionEntity, GameCollectionListItemData>(application) {
private val mApi = RetrofitManager.getInstance().api
private val mRandomId = UUID.randomUUID().toString()
var entrance: String? = null
var selectedTagEntity: TagInfoEntity? = null
var selectedTagId = ""
var selectedTagName = "全部标签"
var view = "recommend"
var isHome = false
var refreshCount = 0
val mAmwayCommentList = MutableLiveData<List<AmwayCommentEntity>>()
val mBannerList = MutableLiveData<List<CarouselEntity>>()
override fun load(loadType: LoadType?) {
if (loadType == LoadType.REFRESH) mResultLiveData.postValue(arrayListOf())
super.load(loadType)
}
val amwayCommentList = MutableLiveData<List<AmwayCommentEntity>>()
val bannerList = MutableLiveData<List<CarouselEntity>>()
val hotListFirstTab = MutableLiveData<String>()
override fun loadData() {
if (isHome) getAmwayCommentList()
getAmwayCommentList()
getBannerList()
getGameCollectionHotListTab()
super.loadData()
}
@ -45,27 +47,51 @@ class GameCollectionSquareViewModel(application: Application) :
mLoadStatusLiveData.value = LoadStatus.INIT
}
override fun provideDataSingle(page: Int): Single<MutableList<GamesCollectionEntity>> =
if (isHome)
RetrofitManager.getInstance()
.api.getHomeGameCollectionSquareList(UUID.randomUUID().toString(), page, PAGE_SIZE)
else
RetrofitManager.getInstance()
.api.getGameCollectionSquareList(view, selectedTagId, page, PAGE_SIZE)
override fun provideDataSingle(page: Int): Single<MutableList<GamesCollectionEntity>> {
val paramsMap = if (selectedTagId.isNotEmpty()) {
mutableMapOf("tag_id" to selectedTagId)
} else {
mutableMapOf()
}
if (view == "recommend") {
paramsMap["random"] = mRandomId
if (refreshCount == 0 && page == 1) {
paramsMap["refresh"] = "true"
}
}
return RetrofitManager.getInstance()
.api.getGameCollectionSquareList(
view,
page,
PAGE_SIZE,
paramsMap.toMap()
)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
val itemDataList = arrayListOf<GameCollectionListItemData>().apply {
var position = 0
if (isHome) add(
GameCollectionListItemData(
amwayListItem = mAmwayCommentList.value,
carouselListItem = mBannerList.value
if (isHome) {
add(
GameCollectionListItemData(
amwayListItem = amwayCommentList.value,
carouselListItem = bannerList.value,
hotListTabName = hotListFirstTab.value ?: "",
isHeaderItem = true
)
)
)
add(GameCollectionListItemData(isFilterItem = true))
}
for (item in list) {
item.games = RegionSettingHelper.filterSimpleGame(item.games)
add(GameCollectionListItemData(gameCollectionItem = item, gameStartPosition = position))
add(
GameCollectionListItemData(
gameCollectionItem = item,
gameStartPosition = position,
isGameCollectionItem = true
)
)
position += if (item.count?.game!! > 2) 3 else if (item.games?.size == 0) 0 else item.count?.game
?: 0
}
@ -78,33 +104,63 @@ class GameCollectionSquareViewModel(application: Application) :
@SuppressLint("CheckResult")
fun getAmwayCommentList() {
RetrofitManager.getInstance().api
.getAmwayCommentList(1, 10)
mApi.getAmwayCommentList(1, 10)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<List<AmwayCommentEntity>>() {
override fun onSuccess(data: List<AmwayCommentEntity>) {
mAmwayCommentList.postValue(data)
amwayCommentList.postValue(data)
}
})
}
@SuppressLint("CheckResult")
fun getBannerList() {
RetrofitManager.getInstance().api
.gameCollectionSquareBanner
mApi.gameCollectionSquareBanner
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<List<CarouselEntity>>() {
override fun onSuccess(data: List<CarouselEntity>) {
mBannerList.postValue(data)
bannerList.postValue(data)
}
override fun onFailure(exception: Exception) {
mBannerList.postValue(emptyList())
bannerList.postValue(emptyList())
}
})
}
private fun getGameCollectionHotListTab() {
mApi.gameCollectionHotListTab
.compose(observableToMain())
.subscribe(object : Response<List<GameCollectionHotListTab>>() {
override fun onResponse(response: List<GameCollectionHotListTab>?) {
super.onResponse(response)
response?.firstOrNull()?.let {
hotListFirstTab.postValue(it.name)
}
}
})
}
companion object {
const val PAGE_SIZE = 15
fun getOrderNameByPosition(position: Int) = when (position) {
1 -> "hot"
2 -> "new"
else -> "recommend"
}
fun getOrderPositionByName(name: String) = when (name) {
"hot" -> 1
"new" -> 2
else -> 0
}
fun getOrderChineseByName(name: String) = when (name) {
"recommend" -> "推荐"
"hot" -> "热门"
"new" -> "最新"
else -> ""
}
}
}

View File

@ -86,13 +86,12 @@ class GameCollectionTagSelectFragment : ToolbarFragment() {
mSingleChoice,
mMaxSelectCount,
mSelectedTag,
updateSelectedTagView,
{ back() })
updateSelectedTagView
) { back() }
if (!mSelectedTags.isNullOrEmpty()) {
mAdapter.selectedTagEntityList.addAll(mSelectedTags!!)
}
mViewModel = viewModelProvider()
if (mSingleChoice) NewLogUtils.logEnterGameCollectionTag()
mBinding.tagRv.run {
layoutManager = LinearLayoutManager(requireContext())
adapter = mAdapter
@ -114,12 +113,12 @@ class GameCollectionTagSelectFragment : ToolbarFragment() {
}
private fun back() {
if (mAdapter.selectedTagEntity != null) {
NewLogUtils.logFilterGameCollectionTag(mAdapter.selectedTagCategory, mAdapter.selectedTagEntity!!.name)
}
requireActivity().setResult(
Activity.RESULT_OK,
Intent().putExtra(SELECTED_TAG, mAdapter.selectedTagEntity)
Intent().apply {
putExtra(SELECTED_TAG, mAdapter.selectedTagEntity)
putExtra(SELECTED_TAG_CATEGORY, mAdapter.selectedTagCategory)
}
)
requireActivity().finish()
}
@ -135,5 +134,6 @@ class GameCollectionTagSelectFragment : ToolbarFragment() {
companion object {
const val SELECTED_TAG = "selected_tag"
const val SELECTED_TAG_CATEGORY = "selected_tag_category"
}
}

View File

@ -711,6 +711,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
if (gameResource.status == Status.SUCCESS) {
mViewModel.logHistory(gameResource.data!!)
mGameEntity = gameResource.data
showBrowserInstallHintIfNeeded()
controlInstallHint()
// 添加启动弹窗的相关信息
if (mEntrance.contains(EntranceConsts.ENTRANCE_WELCOME) && mEntrance.countOccurrences("+") <= 1) {
@ -1957,7 +1958,8 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
private fun showBrowserInstallHintIfNeeded() {
if (BrowserInstallHelper.shouldShowGameDetailUseBrowserToInstallHint()) {
if (BrowserInstallHelper.shouldShowGameDetailUseBrowserToInstallHint()
&& mGameEntity?.isSplitXApk() != true) {
mDownloadBinding.browserInstallHintContainer.visibility = View.VISIBLE
mDownloadBinding.browserInstallHintContainer.setOnClickListener {
val intent = ShellActivity.getIntent(
@ -2290,12 +2292,12 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mDownloadBinding.ivVmode.enlargeTouchArea()
mDownloadBinding.ivVmode.setOnClickListener { _ ->
val downloadStatus = when (entity.downloadStatus) {
"smooth" -> "畅玩"
Constants.V_GAME, Constants.V_GAME_32 -> "畅玩"
"demo" -> "试玩"
else -> "下载"
}
NewFlatLogUtils.logHaloFunGameDetailJumpClick(downloadStatus, simpleGame.id ?: "")
DirectUtils.directToGameDetail(requireContext(), it.id ?: "", mEntrance)
DirectUtils.directToGameDetail(requireContext(), it.id ?: "", entrance = mEntrance)
}
}
}

View File

@ -141,6 +141,28 @@ class GameDetailViewModel(
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<NewGameDetailEntity>() {
override fun onSuccess(data: NewGameDetailEntity) {
if (data.newNotice != null) {
// 存在new_notice字段时移除detail_tab里面type=notice的项并添加new_notice到detail_tab
var noticePosition = -1
data.detailEntity.forEachIndexed { index, it ->
if (it.type == DetailEntity.Type.NOTICE.value) {
noticePosition = index
}
}
if (noticePosition != -1) {
data.detailEntity.removeAt(noticePosition)
data.detailEntity.add(
noticePosition,
DetailEntity(type = DetailEntity.Type.NOTICE.value, noticeList = data.newNotice)
)
} else {
data.detailEntity.add(
0,
DetailEntity(type = DetailEntity.Type.NOTICE.value, noticeList = data.newNotice)
)
}
}
filterGameTags(data)
replaceWithMirrorInfoIfNeeded(data)
// 4.4以下设备不显示顶部视频
@ -164,7 +186,12 @@ class GameDetailViewModel(
// 初始化礼包按钮状态
for (entity in data.detailEntity) {
if (entity.type == "libao") {
val simpleGame = SimpleGame(gameId, mName = game?.name)
val simpleGame = SimpleGame(
gameId,
mName = game?.name,
mIcon = game?.icon,
mRawIcon = game?.rawIcon
)
if (entity.libao != null) {
loadLiBaoStatus(data, entity.libao!!)
for (libaoEntity in entity.libao!!) {

View File

@ -68,6 +68,7 @@ class DescAdapter(
var descItemList = arrayListOf<DetailEntity>()
private val mGameId = mViewModel.game?.id ?: ""
private val mGameName = mViewModel.game?.name ?: "unknown"
private val mExpandableTextViewMaxLinesSparseIntArray = SparseIntArray()
private val mExpandableTextExpandStatusSparseBooleanArray = SparseBooleanArray()
@ -178,11 +179,11 @@ class DescAdapter(
// 绑定公告
private fun bindNoticeViewHolder(viewHolder: GameDetailNoticeViewHolder, itemData: DetailEntity) {
val noticeList = itemData.noticeList!!
val noticeList = itemData.noticeList ?: return
val list = arrayListOf<String>()
for (newsEntity in noticeList) {
list.add(newsEntity.title)
list.add(newsEntity.title ?: "")
}
viewHolder.binding.run {
@ -202,12 +203,10 @@ class DescAdapter(
gamedetailItemNotice.enableSingleLineText()
gamedetailItemNotice.setOnClickListener {
val index = gamedetailItemNotice.displayedChild
DirectUtils.directToArticle(
mContext,
noticeList[index].id,
StringUtils.buildString(mEntrance, "游戏详情[", mGameName, "]:公告")
)
val linkEntity = noticeList[index]
DirectUtils.directToLinkPage(mContext, linkEntity, StringUtils.buildString(mEntrance, "游戏详情[", mGameName, "]:公告"), "")
MtaHelper.onEvent(MTA_KEY_GAME_NEW, "详情_公告", "${mGameName}+${gamedetailItemNotice.notices[index]}")
NewFlatLogUtils.logGameDetailNoticeClick(mGameId, mGameName, linkEntity.link ?: "", linkEntity.type ?: "", linkEntity.text ?: "")
}
}
}
@ -755,8 +754,8 @@ class DescAdapter(
sequence = index
},
source = listOf(
ExposureSource("游戏详情", mGameName),
ExposureSource("游戏单推荐", entity.id)
ExposureSource("游戏详情", "$mGameName+$mGameId"),
ExposureSource("游戏单", "${entity.title}+${entity.id}")
)
)
exposureEventList.add(event)
@ -765,7 +764,12 @@ class DescAdapter(
layoutManager = LinearLayoutManager(mContext, RecyclerView.HORIZONTAL, false)
if (adapter == null) {
adapter = GameCollectionAdapter(recommendGameList, mEntrance, "游戏详情[${mGameName}]:游戏单推荐")
adapter = GameCollectionAdapter(
recommendGameList,
mEntrance,
"游戏详情[${mGameName}]:游戏单推荐",
listOf(ExposureSource("游戏详情", "$mGameName+$mGameId"))
)
} else {
adapter?.notifyItemRangeChanged(0, itemCount)
}

View File

@ -25,6 +25,7 @@ import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.databinding.ItemGameDetailRatingCommentBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
@ -165,12 +166,18 @@ class DescCommentsAdapter(
isChildLongClick = false
return@setOnClickListener
}
val exposureSource = arrayListOf(
ExposureSource("游戏详情"),
ExposureSource("详情tab"),
ExposureSource("玩家评价"),
).toJson()
val intent = RatingReplyActivity.getIntent(
mContext,
mViewModel.game?.id ?: "",
commentData.id,
mEntrance,
path
context = mContext,
gameId = mViewModel.game?.id ?: "",
commentId = commentData.id,
exposureSource = exposureSource,
entrance = mEntrance,
path = path
)
SyncDataBetweenPageHelper.startActivityForResult(mContext, intent, RATING_REPLY_REQUEST, position)
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击评论", mViewModel.game?.name)

View File

@ -8,11 +8,14 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.GamedetailItemGameCollectionBinding
import com.gh.gamecenter.entity.GameDetailRecommendGameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
class GameCollectionAdapter(
private val mRecommendGameList: ArrayList<GameDetailRecommendGameEntity>,
private val mEntrance: String,
private val mPath: String
private val mPath: String,
private val mBasicExposureSource: List<ExposureSource>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val mDefaultHorizontalPadding by lazy { R.dimen.game_detail_item_horizontal_padding.toPx() }
@ -43,7 +46,17 @@ class GameCollectionAdapter(
}
gameCountTv.text = "+${entity.count.game - games.size}"
root.setOnClickListener {
DirectUtils.directToGameCollectionDetail(it.context, entity.id, mEntrance, mPath)
DirectUtils.directToGameCollectionDetail(
it.context,
entity.id,
mEntrance,
mPath,
ExposureEvent.createEventWithSourceConcat(
null,
mBasicExposureSource,
listOf(ExposureSource("游戏单", "${entity.title}+${entity.id}"))
)
)
}
}
}

View File

@ -118,6 +118,7 @@ class GameLibaoAdapter(
holder.binding.libaoSchedulePb.visibility = View.VISIBLE
holder.binding.remainingTv.visibility = View.VISIBLE
holder.binding.libaoCodeTv.visibility = View.GONE
holder.binding.copyLibaoCodeIv.visibility = View.GONE
initProgressUI(libaoEntity, holder)
} else {
@ -145,6 +146,7 @@ class GameLibaoAdapter(
holder.binding.libaoSchedulePb.visibility = View.VISIBLE
holder.binding.remainingTv.visibility = View.VISIBLE
holder.binding.libaoCodeTv.visibility = View.GONE
holder.binding.copyLibaoCodeIv.visibility = View.GONE
initProgressUI(libaoEntity, holder)
}

View File

@ -12,8 +12,8 @@ import kotlinx.parcelize.Parcelize
@Keep
class DetailEntity(
var type: String = "",
@SerializedName("notice")
var noticeList: ArrayList<NoticeEntity>? = null,
@SerializedName("new_notice")
var noticeList: ArrayList<LinkEntity>? = null,
var des: String? = null,// 介绍文案
var gallery: ArrayList<String>? = null,
@SerializedName("count")
@ -122,17 +122,6 @@ class DetailEntity(
}
}
//公告文章
@Keep
class NoticeEntity(
@SerializedName("_id")
var id: String = "",
var title: String = "",
var type: String = "",
var time: String = "",
var overtime: String = ""
)
@Keep
class CustomColumn(
@SerializedName("_id")

View File

@ -57,7 +57,10 @@ class NewGameDetailEntity(
@SerializedName("show_archive")
var showArchive: Boolean = false, //云存档开关
@SerializedName("archive_tab")
var archiveTab: ArchiveTab = ArchiveTab()
var archiveTab: ArchiveTab = ArchiveTab(),
@SerializedName("new_notice")
var newNotice: ArrayList<LinkEntity>? = null,
) {
fun isShowContentCard(gameEntity: GameEntity?): Boolean {
return contentCard.size > 1 && (gameEntity?.shouldUseMirrorInfo() == false || (gameEntity?.shouldUseMirrorInfo() == true && mirrorData?.contentCardStatus == "on"))

View File

@ -10,14 +10,11 @@ import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.utils.copyTextAndToast
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.ifLogin
import com.gh.gamecenter.common.utils.setTextWithHighlightedTextWrappedInsideWrapper
import com.gh.gamecenter.common.utils.TextHelper
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.ItemMyGameRatingBinding
import com.gh.gamecenter.feature.entity.TagStyleEntity
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
import com.gh.gamecenter.personalhome.rating.MyRating
@ -112,7 +109,7 @@ class MyRatingAdapter(
holder.binding.apply {
gameInfo.setOnClickListener {
MtaHelper.onEvent("我的光环_新", "我的游戏评论", "游戏详情")
DirectUtils.directToGameDetail(mContext, rating.game.id, "我的游戏评论")
DirectUtils.directToGameDetail(mContext, rating.game.id, entrance = "我的游戏评论")
}
commentInfo.setOnClickListener {
if (isChildLongClick) {
@ -121,7 +118,13 @@ class MyRatingAdapter(
}
MtaHelper.onEvent("我的光环_新", "我的游戏评论", "评论详情")
val intent =
RatingReplyActivity.getIntent(mContext, rating.game.id, rating.id, false, "我的游戏评论", "")
RatingReplyActivity.getIntent(
context = mContext,
gameId = rating.game.id,
commentId = rating.id,
showKeyboardIfReplyListIsEmpty = false,
entrance = "我的游戏评论",
path = "")
/* if(!rating.active){
intent = RatingReplyActivity.getIntent(mContext, rating.transformGameEntity(), rating.transformCommentEntity(), "我的游戏评论", "")
}else if(!rating.game.active){

View File

@ -26,6 +26,7 @@ import com.gh.gamecenter.databinding.RatingItemBinding
import com.gh.gamecenter.entity.Rating
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.entity.Star
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
import com.lightgame.utils.Utils
@ -475,11 +476,20 @@ class RatingAdapter(
}
PageSwitchDataHelper.pushCurrentPageData(pageData)
val intent = if (isOpenKeyboard) {
RatingReplyActivity.getOpenKeyboardIntent(mContext, mListViewModel.game, commentData, mEntrance, path)
} else {
RatingReplyActivity.getIntent(mContext, mListViewModel.game.id, commentData.id, mEntrance, path)
}
val exposureSource = arrayListOf(
ExposureSource("游戏详情"),
ExposureSource("评价tab"),
).toJson()
val intent = RatingReplyActivity.getIntent(
context = mContext,
gameId = mListViewModel.game.id,
commentId = commentData.id,
forcedShowKeyboard = isOpenKeyboard,
exposureSource = exposureSource,
entrance = mEntrance,
path = path
)
SyncDataBetweenPageHelper.startActivityForResult(
mContext,
intent,

View File

@ -34,6 +34,7 @@ import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.entity.RatingReplyEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@ -90,7 +91,10 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
override fun provideListAdapter(): RatingReplyAdapter {
if (mAdapter == null) {
mAdapter = RatingReplyAdapter(this, mEntrance, mListViewModel, replyCallback = {
val exposureSourceList: ArrayList<ExposureSource>? =
intent.getStringExtra(EntranceConsts.KEY_EXPOSURE_SOURCE)?.toObject()
mAdapter = RatingReplyAdapter(this, mEntrance, mListViewModel, exposureSourceList, replyCallback = {
if (it != null) {
mInputBinding.answerCommentEt.hint = "回复 @${it.user.name}"
} else {
@ -196,14 +200,9 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
}
}
TextHelper.limitTheLengthOfEditText(
mInputBinding.answerCommentEt,
140,
object : TextHelper.ExceedTextLengthLimitCallback {
override fun onExceed() {
toast("最多140个字")
}
})
TextHelper.limitTheLengthOfEditText(mInputBinding.answerCommentEt, 140) {
toast("最多140个字")
}
if (intent?.getBooleanExtra(EntranceConsts.KEY_OPEN_KEYBOARD, false) == true) {
popInputLayout(true)
@ -413,106 +412,83 @@ class RatingReplyActivity : ListActivity<RatingReplyEntity, RatingReplyViewModel
}
companion object {
@JvmStatic
fun getIntent(
context: Context,
game: GameEntity,
comment: RatingComment,
entrance: String,
path: String
): Intent {
val intent = Intent(context, RatingReplyActivity::class.java)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
intent.putExtra(GameEntity::class.java.simpleName, game)
intent.putExtra(RatingComment::class.java.simpleName, comment)
return intent
}
@JvmStatic
/**
* 获取评论详情的 Intent
* @param showKeyboardIfReplyListIsEmpty 当回复列表为空时弹起软键盘
* @param forcedShowKeyboard 默认弹起软键盘
*/
fun getIntent(
context: Context,
gameId: String,
comment: RatingComment,
showKeyboardIfReplyListIsEmpty: Boolean,
gameEntity: GameEntity? = null,
commentId: String,
comment: RatingComment? = null,
topCommentId: String? = null,
showKeyboardIfReplyListIsEmpty: Boolean = false,
forcedShowKeyboard: Boolean = false,
exposureSource: String? = null,
entrance: String,
path: String
): Intent {
val intent = Intent(context, RatingReplyActivity::class.java)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
intent.putExtra(EntranceConsts.KEY_GAMEID, gameId)
intent.putExtra(RatingComment::class.java.simpleName, comment)
if (gameEntity != null) {
intent.putExtra(GameEntity::class.java.simpleName, gameEntity)
}
intent.putExtra(EntranceConsts.KEY_COMMENTID, commentId)
if (comment != null) {
intent.putExtra(RatingComment::class.java.simpleName, comment)
}
intent.putExtra(EntranceConsts.KEY_SHOW_KEYBOARD_IF_NEEDED, showKeyboardIfReplyListIsEmpty)
intent.putExtra(EntranceConsts.KEY_OPEN_KEYBOARD, forcedShowKeyboard)
if (topCommentId != null) {
intent.putExtra(EntranceConsts.KEY_TOP_COMMENT_ID, topCommentId)
}
intent.putExtra(EntranceConsts.KEY_EXPOSURE_SOURCE, exposureSource)
return intent
}
@JvmStatic
fun getIntent(
context: Context,
gameId: String,
commentId: String,
entrance: String,
path: String
): Intent {
return getIntent(context, gameId, commentId, "", false, entrance, path)
}
@JvmStatic
fun getIntent(
context: Context,
gameId: String,
commentId: String,
showKeyboardIfReplyListIsEmpty: Boolean,
entrance: String,
path: String
): Intent {
return getIntent(context, gameId, commentId, "", showKeyboardIfReplyListIsEmpty, entrance, path)
}
@JvmStatic
fun getSpecifiedCommentIntent(
context: Context,
gameId: String,
commentId: String,
topCommentId: String,
exposureSource: ExposureSource,
entrance: String,
path: String
): Intent {
return getIntent(context, gameId, commentId, topCommentId, false, entrance, path)
return getIntent(
context = context,
gameId = gameId,
commentId = commentId,
topCommentId = topCommentId,
exposureSource = arrayListOf(exposureSource).toJson(),
showKeyboardIfReplyListIsEmpty = false,
entrance = entrance,
path = path
)
}
@JvmStatic
fun getIntent(
fun getSimpleIntent(
context: Context,
gameId: String,
commentId: String,
topCommentId: String,
showKeyboardIfReplyListIsEmpty: Boolean,
commentId: String?,
exposureSource: ExposureSource,
entrance: String,
path: String
): Intent {
val intent = Intent(context, RatingReplyActivity::class.java)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
intent.putExtra(EntranceConsts.KEY_GAMEID, gameId)
intent.putExtra(EntranceConsts.KEY_COMMENTID, commentId)
intent.putExtra(EntranceConsts.KEY_TOP_COMMENT_ID, topCommentId)
intent.putExtra(EntranceConsts.KEY_SHOW_KEYBOARD_IF_NEEDED, showKeyboardIfReplyListIsEmpty)
return intent
}
@JvmStatic
fun getOpenKeyboardIntent(
context: Context,
game: GameEntity,
comment: RatingComment,
entrance: String,
path: String
): Intent {
val intent = Intent(context, RatingReplyActivity::class.java)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
intent.putExtra(GameEntity::class.java.simpleName, game)
intent.putExtra(RatingComment::class.java.simpleName, comment)
intent.putExtra(EntranceConsts.KEY_OPEN_KEYBOARD, true)
return intent
return getIntent(
context = context,
gameId = gameId,
commentId = commentId ?: "unknown",
exposureSource = arrayListOf(exposureSource).toJson(),
entrance = entrance,
path = path
)
}
}

View File

@ -49,6 +49,7 @@ class RatingReplyAdapter(
context: Context,
val entrance: String,
val viewModel: RatingReplyViewModel,
private val mExposureSourceList: ArrayList<ExposureSource>?,
val replyCallback: (RatingReplyEntity?) -> Unit
) : ListAdapter<RatingReplyItem>(context), IExposable {
@ -58,6 +59,10 @@ class RatingReplyAdapter(
private val path = "评论详情"
private var mExposureEvent: ExposureEvent? = null
init {
mExposureSourceList?.add(ExposureSource("评论详情", ""))
}
override fun setListData(updateData: MutableList<RatingReplyItem>?) {
if (mEntityList.size > 0 && mEntityList[mEntityList.size - 1].reply == null
&& updateData != null && updateData.size > 0 && updateData[updateData.size - 1].reply != null
@ -105,22 +110,27 @@ class RatingReplyAdapter(
view = mLayoutInflater.inflate(R.layout.rating_reply_head_item, parent, false)
RatingReplyHeadItemViewHolder(RatingReplyHeadItemBinding.bind(view))
}
ITEM_COMMENT -> {
view = mLayoutInflater.inflate(R.layout.item_article_detail_comment, parent, false)
RatingDetailCommentItemViewHolder(ItemArticleDetailCommentBinding.bind(view))
}
ITEM_SECTION_TITLE -> {
view = mLayoutInflater.inflate(R.layout.piece_article_detail_comment_filter, parent, false)
ListSectionItemViewHolder(PieceArticleDetailCommentFilterBinding.bind(view))
}
ItemViewType.ITEM_BODY -> {
view = mLayoutInflater.inflate(R.layout.item_article_detail_comment, parent, false)
RatingReplyItemViewHolder(ItemArticleDetailCommentBinding.bind(view))
}
ItemViewType.ITEM_FOOTER -> {
view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)
FooterViewHolder(view)
}
else -> {
throw IllegalStateException("item view type not found")
}
@ -135,12 +145,12 @@ class RatingReplyAdapter(
when (holder) {
is RatingReplyHeadItemViewHolder -> {
val game = mEntityList[position].game!!
val exposureSource = if (entrance.contains("安利墙")) {
listOf(ExposureSource("安利墙", ""), ExposureSource("评论详情", ""))
} else {
listOf(ExposureSource("其他", ""), ExposureSource("评论详情", ""))
}
mExposureEvent = ExposureEvent.createEvent(game, exposureSource)
// 构造 exposureSource
val exposureSourceList = mExposureSourceList
?: listOf(ExposureSource("其他", ""), ExposureSource("评论详情", ""))
mExposureEvent = ExposureEvent.createEvent(game, exposureSourceList)
// 记录评论 id
mExposureEvent?.payload?.controlLinkDesc = viewModel.commentId
holder.binding.gameIcon.displayGameIcon(game)
holder.binding.gameName.text = game.name
holder.binding.gameInfo.text = if (!game.getApk()
@ -189,6 +199,7 @@ class RatingReplyAdapter(
)
}
}
is RatingDetailCommentItemViewHolder -> {
val commentData = mEntityList[position].comment!!
holder.setContent(commentData, viewModel, position, entrance, path)
@ -232,6 +243,7 @@ class RatingReplyAdapter(
}
}
}
is RatingReplyItemViewHolder -> {
val replyEntity = mEntityList[position].reply!!
holder.binding.run {
@ -411,6 +423,7 @@ class RatingReplyAdapter(
).copyTextAndToast()
logGameDetailCommentDetailCommentClick("回复右上角-复制")
}
"投诉" -> {
mContext.ifLogin("游戏详情-评分-评论详情- 投诉评论") {
DialogUtils.showReportReasonDialog(
@ -427,6 +440,7 @@ class RatingReplyAdapter(
}
logGameDetailCommentDetailCommentClick("回复右上角-投诉")
}
"删除" -> {
DialogHelper.showDeleteGameCommentDialog(
mContext,
@ -493,6 +507,7 @@ class RatingReplyAdapter(
}
}
}
is ListSectionItemViewHolder -> {
holder.binding.run {
root.setRootBackgroundColor(R.color.background_white)
@ -521,6 +536,7 @@ class RatingReplyAdapter(
viewModel.sortList(RatingReplyViewModel.SORT_POSITIVE)
logGameDetailCommentDetailCommentClick("正序")
}
1 -> {
viewModel.sortList(RatingReplyViewModel.SORT_NEGATION)
logGameDetailCommentDetailCommentClick("倒序")
@ -529,6 +545,7 @@ class RatingReplyAdapter(
}
}
}
is FooterViewHolder -> {
holder.itemView.setBackgroundColor(R.color.background_white.toColor(mContext))
when {
@ -538,16 +555,19 @@ class RatingReplyAdapter(
holder.itemView.isClickable = true
holder.itemView.setOnClickListener { viewModel.load(LoadType.RETRY) }
}
mIsLoading -> {
holder.loading.visibility = View.VISIBLE
holder.hint.setText(R.string.loading)
holder.itemView.isClickable = false
}
mIsOver && mEntityList.size > 2 && mEntityList[2].replyCount != null -> {
holder.loading.visibility = View.GONE
holder.hint.setText(R.string.load_over_hint)
holder.itemView.isClickable = false
}
mIsOver -> {
holder.loading.visibility = View.GONE
holder.hint.text = "这里还没有回复,说点什么吧~"
@ -556,6 +576,7 @@ class RatingReplyAdapter(
replyCallback.invoke(null)
}
}
else -> {
holder.loading.visibility = View.GONE
holder.hint.setText(R.string.loading_more_hint)

View File

@ -20,6 +20,7 @@ import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.entity.AmwayCommentEntity
@ -294,13 +295,15 @@ class HomeFragmentAdapter(
val path = "(首页安利墙)"
when (v.id) {
R.id.rating_block -> {
val exposureSource = arrayListOf(ExposureSource("新首页"), ExposureSource("安利墙")).toJson()
val intent = RatingReplyActivity.getIntent(
mContext,
amway.game.id,
amway.comment.id,
false,
path,
""
context = mContext,
gameId = amway.game.id,
commentId = amway.comment.id,
showKeyboardIfReplyListIsEmpty = false,
exposureSource = exposureSource,
entrance = path,
path = ""
)
mContext.startActivity(intent)
NewLogUtils.logHomeShareWallCardClick(amway.game.name ?: "", amway.game.id, "评论内容")
@ -353,7 +356,7 @@ class HomeFragmentAdapter(
}
}
homeItemData.exposureEventList = exposureList
holder.bindGameCollectionList(gameCollectionItemDataList, "首页内容列表")
holder.bindGameCollectionList(gameCollectionItemDataList, "首页内容列表", mBasicExposureSource)
}
private fun bindRecentVGame(holder: HomeRecentVGameViewHolder, position: Int) {

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