Compare commits

...

106 Commits

Author SHA1 Message Date
7cfa26ff02 Merge branch 'build/build_issue' into 'dev'
build: 将 QQ 小游戏的类添加到移除日志输出白名单,避免无法编译

See merge request halo/android/assistant-android!1292
2023-08-29 11:55:24 +08:00
a7335d21c5 build: 将 QQ 小游戏的类添加到移除日志输出白名单,避免无法编译 2023-08-29 11:54:43 +08:00
0fd84f8b44 Merge branch 'fix/csj-privacy-issue' into 'dev'
fix: 处理穿山甲 SDK 的自动初始化问题,穿山甲 SDK 区分测试和正式 ID

See merge request halo/android/assistant-android!1288
2023-08-28 09:51:41 +08:00
43bcf78dea Merge branch 'fix/GHZS-3317' into 'dev'
fix: 【光环助手】插件通知业务:已通知的消息图片不展示以及批量回复“未回复”用户报错(1) https://jira.shanqu.cc/browse/GHZS-3317

See merge request halo/android/assistant-android!1289
2023-08-28 09:51:33 +08:00
fb44391500 fix: 处理穿山甲 SDK 的自动初始化问题,穿山甲 SDK 区分测试和正式 ID 2023-08-28 09:44:20 +08:00
4c4de337cd fix: 【光环助手】插件通知业务:已通知的消息图片不展示以及批量回复“未回复”用户报错(1) https://jira.shanqu.cc/browse/GHZS-3317 2023-08-28 09:41:45 +08:00
625e448928 Merge branch 'fix/qGame_culprit' into 'dev'
fix: 修复专题详情默认为 QQ 小游戏的问题

See merge request halo/android/assistant-android!1286
2023-08-25 16:04:53 +08:00
2bfefc5082 fix: 修复专题详情默认为 QQ 小游戏的问题 2023-08-25 16:00:17 +08:00
1538d77960 Merge branch 'feature-GHZS-3273' into 'dev'
feat: 【光环助手】同步正式问题—QQ小游戏SDK https://jira.shanqu.cc/browse/GHZS-3273

See merge request halo/android/assistant-android!1284
2023-08-24 17:41:27 +08:00
9f77e70c16 feat: 【光环助手】同步正式问题—QQ小游戏SDK https://jira.shanqu.cc/browse/GHZS-3273 2023-08-24 17:41:27 +08:00
630f78e62d Merge branch 'feature-sentry-318553' into 'dev'
fix: Sentry318553

See merge request halo/android/assistant-android!1279
2023-08-18 16:55:52 +08:00
dc7b103cbc fix: Sentry318553 2023-08-18 16:55:52 +08:00
d30f51123d Merge branch 'feature-GHZS-2966-new' into 'dev'
feat: QQ小游戏SDK接入—客户端 https://jira.shanqu.cc/browse/GHZS-2966

See merge request halo/android/assistant-android!1278
2023-08-18 15:23:19 +08:00
00f625c350 feat: QQ小游戏SDK接入—客户端 https://jira.shanqu.cc/browse/GHZS-2966 2023-08-18 15:23:19 +08:00
95f63bd4f2 Merge branch 'feat/GHZS-3252' into 'dev'
feat: 已安装列表权限-合规整改 https://jira.shanqu.cc/browse/GHZS-3249

See merge request halo/android/assistant-android!1276
2023-08-17 16:53:41 +08:00
07a1b2a63b feat: 已安装列表权限-合规整改 https://jira.shanqu.cc/browse/GHZS-3249 2023-08-17 16:29:29 +08:00
6a36874ef8 Merge branch 'fix/GHZS-3242' into 'dev'
fix: 订阅&推送体系优化-消息中心优化—0816测试-客户端(1) https://jira.shanqu.cc/browse/GHZS-3242

See merge request halo/android/assistant-android!1271
2023-08-16 18:02:13 +08:00
285e0caafe fix: 订阅&推送体系优化-消息中心优化—0816测试-客户端(1) https://jira.shanqu.cc/browse/GHZS-3242 2023-08-16 17:51:09 +08:00
0e0c6c48af Merge branch 'fix/GHZS-3242' into 'dev'
fix: 订阅&推送体系优化-消息中心优化—0816测试-客户端(2) https://jira.shanqu.cc/browse/GHZS-3242

See merge request halo/android/assistant-android!1269
2023-08-16 17:30:07 +08:00
38c02380ad fix: 订阅&推送体系优化-消息中心优化—0816测试-客户端(2) https://jira.shanqu.cc/browse/GHZS-3242 2023-08-16 16:24:16 +08:00
bf5608492d Merge branch 'fix/GHZS-3217' into 'dev'
fix: 搜索结果列表跳转开服表问题 https://jira.shanqu.cc/browse/GHZS-3217

See merge request halo/android/assistant-android!1267
2023-08-16 15:42:55 +08:00
267f03fd42 fix: 搜索结果列表跳转开服表问题 https://jira.shanqu.cc/browse/GHZS-3217 2023-08-16 15:23:53 +08:00
d39a62d4e0 Merge branch 'fix/home_game_library_download_hint' into 'dev'
fix: 修复添加游戏下载时游戏库下载按钮没有提示的问题

See merge request halo/android/assistant-android!1264
2023-08-16 13:44:21 +08:00
5d02c40227 fix: 修复添加游戏下载时游戏库下载按钮没有提示的问题 2023-08-16 11:53:51 +08:00
910d1eb6b7 Merge branch 'fix/GHZS-3218' into 'dev'
fix: 订阅&推送体系优化-消息中心优化—0811优化-客户端(一级页面标题栏&红点提示样式优化) https://jira.shanqu.cc/browse/GHZS-3218

See merge request halo/android/assistant-android!1263
2023-08-16 11:51:18 +08:00
755a2a0633 fix: 订阅&推送体系优化-消息中心优化—0811优化-客户端(一级页面标题栏&红点提示样式优化) https://jira.shanqu.cc/browse/GHZS-3218 2023-08-16 11:28:13 +08:00
1a33e24a85 Merge branch 'fix/GHZS-3218' into 'dev'
fix: 订阅&推送体系优化-消息中心优化—0811优化-客户端(一级页面标题栏&红点提示样式优化) https://jira.shanqu.cc/browse/GHZS-3218

See merge request halo/android/assistant-android!1261
2023-08-15 17:39:26 +08:00
9a9c219082 fix: 订阅&推送体系优化-消息中心优化—0811优化-客户端(一级页面标题栏&红点提示样式优化) https://jira.shanqu.cc/browse/GHZS-3218 2023-08-15 17:36:37 +08:00
3e9c3027f2 Merge branch 'fix/GHZS-3218' into 'dev'
fix: 订阅&推送体系优化-消息中心优化—0811优化-客户端(一级页面标题栏&红点提示样式优化) https://jira.shanqu.cc/browse/GHZS-3218

See merge request halo/android/assistant-android!1260
2023-08-15 15:17:35 +08:00
c895965822 fix: 订阅&推送体系优化-消息中心优化—0811优化-客户端(一级页面标题栏&红点提示样式优化) https://jira.shanqu.cc/browse/GHZS-3218 2023-08-15 15:16:16 +08:00
8dff7f3e69 Merge branch 'fix/multiprocess_init_ad_error' into 'dev'
fix: 修复部分广告 SDK 相关的问题

See merge request halo/android/assistant-android!1251
2023-08-15 15:06:02 +08:00
5abb229fcc fix: 修复因接口返回速度不够快时可能导致首页弹窗无法正常弹出的问题 2023-08-15 15:02:29 +08:00
d0b6d4ae5c Merge branch 'fix/GHZS-3221' into 'dev'
fix: 消息中心优化测试:游戏动态更新,但消息中心入口的红点未作提醒 https://jira.shanqu.cc/browse/GHZS-3221

See merge request halo/android/assistant-android!1258
2023-08-15 09:45:06 +08:00
772a21210d fix: 消息中心优化埋点测试:发现从消息中心到游戏详情下载埋点事件的来源属性为空 https://jira.shanqu.cc/browse/GHZS-3225 2023-08-14 16:46:57 +08:00
b81df5b2ad fix: 修复消息会话列表动图图标圆角裁切不生效的问题 2023-08-14 15:21:22 +08:00
07c44ef6a1 fix: 消息中心优化测试:游戏动态更新,但消息中心入口的红点未作提醒 https://jira.shanqu.cc/browse/GHZS-3221 2023-08-14 15:07:28 +08:00
6aa1a0a00e Merge branch 'fix/GHZS-3223' into 'dev'
fix: 消息中心优化埋点测试:message_inform_message_click的会话类型埋点错误 https://jira.shanqu.cc/browse/GHZS-3223

See merge request halo/android/assistant-android!1257
2023-08-14 13:47:47 +08:00
c6890cee19 fix: 消息中心优化埋点测试:message_inform_message_click的会话类型埋点错误 https://jira.shanqu.cc/browse/GHZS-3223 2023-08-14 13:45:46 +08:00
f83a4035c3 Merge branch 'fix/GHZS-3218' into 'dev'
fix: 订阅&推送体系优化-消息中心优化—0811UI测试(3) https://jira.shanqu.cc/browse/GHZS-3213

See merge request halo/android/assistant-android!1256
2023-08-14 09:56:38 +08:00
5fc03780a9 fix: 订阅&推送体系优化-消息中心优化—0811UI测试(3) https://jira.shanqu.cc/browse/GHZS-3213
fix: 消息中心优化测试:消息中心入口的红点的显示样式异常 https://jira.shanqu.cc/browse/GHZS-3218
2023-08-14 09:55:01 +08:00
ac7828c9f2 Merge branch 'fix/GHZS-3215' into 'dev'
fix: 【光环助手】首页下拉推送相关问题(2) https://jira.shanqu.cc/browse/GHZS-3215

See merge request halo/android/assistant-android!1255
2023-08-11 17:18:12 +08:00
270a02366d fix: 【光环助手】首页下拉推送相关问题(2) https://jira.shanqu.cc/browse/GHZS-3215 2023-08-11 17:14:20 +08:00
25d96aba67 Merge branch 'fix/GHZS-2953' into 'dev'
fix: 消息中心优化测试:消息中心入口的未读与消息列表不一致 https://jira.shanqu.cc/browse/GHZS-3208

See merge request halo/android/assistant-android!1254
2023-08-11 16:17:55 +08:00
f6558e1e13 fix: 订阅&推送体系优化-消息中心优化—0811UI测试 https://jira.shanqu.cc/browse/GHZS-3213 2023-08-11 16:10:51 +08:00
7784cecdbc fix: 消息中心优化测试:测试提问帖邀请消息,发现能收到消息,但会话消息列表没有消息 https://jira.shanqu.cc/browse/GHZS-3205 2023-08-11 15:46:42 +08:00
ad3301e0a8 fix: 订阅&推送体系优化-消息中心优化—0811UI测试 https://jira.shanqu.cc/browse/GHZS-3213 2023-08-11 14:54:05 +08:00
8f2ee5d323 fix: 消息中心优化测试:消息中心入口的未读与消息列表不一致 https://jira.shanqu.cc/browse/GHZS-3208
fix: 消息中心优化测试:会话消息设置免打扰或取消免打扰时,页面没有立即响应 https://jira.shanqu.cc/browse/GHZS-3209
2023-08-11 14:38:51 +08:00
9a999eefb7 Merge branch 'fix/GHZS-2953' into 'dev'
fix: 消息中心优化测试:会话消息列表未做已读规则 https://jira.shanqu.cc/browse/GHZS-3200

See merge request halo/android/assistant-android!1253
2023-08-11 11:16:07 +08:00
cdb274229b fix: 消息中心优化测试:会话消息列表未做已读规则 https://jira.shanqu.cc/browse/GHZS-3200
fix: 消息中心优化测试:消息中心入口的红点提醒,无法被消除 https://jira.shanqu.cc/browse/GHZS-3202
fix: 消息中心优化:消息中心入口的未读提醒,冷启动时没有响应,要切换页面才有 https://jira.shanqu.cc/browse/GHZS-3203
2023-08-11 11:10:59 +08:00
b20a3717e1 Merge branch 'fix/GHZS-3183' into 'dev'
fix: 补充消息中心模块混淆规则

See merge request halo/android/assistant-android!1252
2023-08-10 16:48:49 +08:00
3ef8dea4d2 fix: 补充消息中心模块混淆规则 2023-08-10 16:33:46 +08:00
17ee9752d3 fix: 避免多进程初始化广告 SDK 2023-08-10 11:18:10 +08:00
a5992750ed Merge branch 'fix/update_gid' into 'dev'
fix: 更新 gid 版本,避免闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/313421/?project=22

See merge request halo/android/assistant-android!1249
2023-08-10 09:25:38 +08:00
8b76b72222 fix: 更新 gid 版本,避免闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/313421/?project=22 2023-08-10 09:25:04 +08:00
ad6b7228cf Merge branch 'feat/GHZS-3035' into 'dev'
feat: 推广打包功能相关优化 https://jira.shanqu.cc/browse/GHZS-3035

See merge request halo/android/assistant-android!1247
2023-08-09 14:04:24 +08:00
9a0873cf67 feat: 推广打包功能相关优化 https://jira.shanqu.cc/browse/GHZS-3035 2023-08-09 13:50:34 +08:00
6cf461dbf7 Merge remote-tracking branch 'origin/release' into dev 2023-08-09 09:59:32 +08:00
68252a4375 Merge remote-tracking branch 'origin/release' into dev 2023-08-08 16:21:10 +08:00
9925022660 Merge branch 'feature/GHZS-2992' into 'dev'
feat: 订阅&推送体系优化-消息中心优化—客户端 https://jira.shanqu.cc/browse/GHZS-2992

See merge request halo/android/assistant-android!1243
2023-08-08 14:56:32 +08:00
5972b8b4bf feat: 订阅&推送体系优化-消息中心优化—客户端 https://jira.shanqu.cc/browse/GHZS-2992 2023-08-08 14:03:32 +08:00
f31507ae9f Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/search/SearchGameResultViewModel.kt
#	dependencies.gradle
2023-08-08 10:03:10 +08:00
dec546238e Merge branch 'fix/GHZS-3129' into 'dev'
fix: 修复游戏下载按钮显示问题 https://jira.shanqu.cc/browse/GHZS-3129

See merge request halo/android/assistant-android!1239
2023-08-04 16:51:44 +08:00
5715d36ad1 fix: 修复游戏下载按钮显示问题 https://jira.shanqu.cc/browse/GHZS-3129 2023-08-04 16:40:58 +08:00
c62021ee64 Merge branch 'fix/home_game_collection' into 'dev'
fix: 修复删除下载任务时首页游戏单下载按钮没有更新的问题

See merge request halo/android/assistant-android!1237
2023-08-04 10:29:59 +08:00
7bab11d2a1 fix: 修复删除下载任务时首页游戏单下载按钮没有更新的问题 2023-08-04 10:09:33 +08:00
5bb2451750 Merge branch 'fix/ad_culprit' into 'dev'
fix: 修复开屏广告在部分数据为空时候的显示问题

See merge request halo/android/assistant-android!1236
2023-08-03 17:55:03 +08:00
ef0341ad6d fix: 修复开屏广告在部分数据为空时候的显示问题 2023-08-03 17:50:51 +08:00
f645964bdf Merge branch 'fix/GHZS-3115' into 'dev'
fix: 新增广告位管理功能—0802优化(1,3,5)  https://jira.shanqu.cc/browse/GHZS-3115

See merge request halo/android/assistant-android!1231
2023-08-03 09:27:24 +08:00
e420b261bb fix: 新增广告位管理功能—0802优化(1,3,5) https://jira.shanqu.cc/browse/GHZS-3115 2023-08-03 09:22:48 +08:00
1781f4c665 Merge branch 'fix/cloud_archive_sync_issue' into 'dev'
feat: 补上遗漏的跨光环和畅玩组件间的云存档下载数据同步功能 https://jira.shanqu.cc/browse/GHZS-2886

See merge request halo/android/assistant-android!1230
2023-08-02 16:33:56 +08:00
ee79ed528b feat: 补上遗漏的跨光环和畅玩组件间的云存档下载数据同步功能 https://jira.shanqu.cc/browse/GHZS-2886 2023-08-02 15:47:19 +08:00
fc9137a48d Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2023-08-02 11:21:14 +08:00
2dceaeec3e Merge remote-tracking branch 'origin/dev' into dev-5.30.0
# Conflicts:
#	app/build.gradle
2023-07-31 09:36:08 +08:00
f59bc42539 Merge branch 'fix/GHZS-3051' into 'dev-5.30.0'
fix: 游戏搜索-热门标签 补充相关曝光数据—0728测试(0729测试) https://jira.shanqu.cc/browse/GHZS-3051

See merge request halo/android/assistant-android!1227
2023-07-31 09:28:26 +08:00
5b7c98224c fix: 游戏搜索-热门标签 补充相关曝光数据—0728测试(0729测试) https://jira.shanqu.cc/browse/GHZS-3051 2023-07-31 09:21:45 +08:00
2710c03112 Merge branch 'fix/GHZS-3051' into 'dev-5.30.0'
fix: 游戏搜索-热门标签 补充相关曝光数据—0728测试 https://jira.shanqu.cc/browse/GHZS-3051

See merge request halo/android/assistant-android!1225
2023-07-28 16:33:05 +08:00
3341d55f5a fix: 游戏搜索-热门标签 补充相关曝光数据—0728测试 https://jira.shanqu.cc/browse/GHZS-3051 2023-07-28 16:23:12 +08:00
f81d315800 Merge branch 'feat/GHZS-2989' into 'dev-5.30.0'
feat: 右下悬浮窗新增埋点 https://jira.shanqu.cc/browse/GHZS-2989

See merge request halo/android/assistant-android!1222
2023-07-28 11:55:12 +08:00
33f5badfd9 feat: 右下悬浮窗新增埋点 https://jira.shanqu.cc/browse/GHZS-2989 2023-07-28 11:47:01 +08:00
0407244cca Merge branch 'feat/GHZS-2919' into 'dev-5.30.0'
新增广告位管理功能

See merge request halo/android/assistant-android!1221
2023-07-28 11:30:52 +08:00
64449ec38b feat: 新增广告位管理功能 https://jira.shanqu.cc/browse/GHZS-2919 2023-07-28 10:28:49 +08:00
fb937e8ced feat: 完成穿山甲广告SDK接入 https://jira.shanqu.cc/browse/GHZS-2940 2023-07-28 10:16:52 +08:00
96f9e8aceb Merge remote-tracking branch 'origin/dev' into dev-5.30.0
# Conflicts:
#	app/src/main/java/com/gh/common/xapk/XapkInstaller.kt
#	app/src/main/res/values/strings.xml
#	module_common/src/main/java/com/gh/gamecenter/common/utils/DialogHelper.kt
#	module_common/src/main/java/com/gh/gamecenter/common/utils/MiuiUtils.java
#	module_common/src/main/java/com/gh/gamecenter/common/utils/SystemUtils.kt
2023-07-28 10:11:25 +08:00
be294fbba5 Merge branch 'fix/home_game_tab' into 'dev-5.30.0'
fix: 修复游戏库最后一个Tab选中时Tab被切图遮挡的问题

See merge request halo/android/assistant-android!1220
2023-07-27 15:30:36 +08:00
aabc676f94 fix: 修复游戏库最后一个Tab选中时Tab被切图遮挡的问题 2023-07-27 15:26:26 +08:00
4c867390c2 Merge branch 'feature/GHZS-2972' into 'dev-5.30.0'
feat: 组件化消息中心相关功能 https://jira.shanqu.cc/browse/GHZS-2972

See merge request halo/android/assistant-android!1218
2023-07-24 17:49:02 +08:00
f9c6bb1e56 feat: 组件化消息中心相关功能 https://jira.shanqu.cc/browse/GHZS-2972 2023-07-24 17:49:02 +08:00
33ed2796c8 Merge remote-tracking branch 'origin/dev' into dev-5.30.0 2023-07-24 10:48:52 +08:00
c4fb785e55 Merge branch 'fix/channel_issue' into 'dev-5.30.0'
fix: 修复渠道更换的保存问题

See merge request halo/android/assistant-android!1214
2023-07-21 18:07:38 +08:00
8d5e6c8940 fix: 修复渠道更换的保存问题 2023-07-21 17:51:51 +08:00
f258b71648 Merge branch 'feature-GHZS-2884' into 'dev-5.30.0'
feat: 游戏下载新增跳转第三方落地页—客户端 https://jira.shanqu.cc/browse/GHZS-2884

See merge request halo/android/assistant-android!1210
2023-07-21 09:36:35 +08:00
f3679aa041 feat: 游戏下载新增跳转第三方落地页—客户端 https://jira.shanqu.cc/browse/GHZS-2884 2023-07-21 09:23:51 +08:00
3b02c9df23 Merge branch 'feature/GHZS-2978' into 'dev-5.30.0'
feat: 游戏搜索-热门标签 补充相关曝光数据—客户端 https://jira.shanqu.cc/browse/GHZS-2978

See merge request halo/android/assistant-android!1209
2023-07-20 17:17:36 +08:00
1034254613 feat: 游戏搜索-热门标签 补充相关曝光数据—客户端 https://jira.shanqu.cc/browse/GHZS-2978 2023-07-20 17:14:52 +08:00
bc3e92c4a1 Merge branch 'feature/GHZS-2912' into 'dev-5.30.0'
feat: 游戏库增加顶部tab栏—客户端 https://jira.shanqu.cc/browse/GHZS-2912

See merge request halo/android/assistant-android!1208
2023-07-20 09:47:18 +08:00
c7dabaa37b Merge branch 'dev-5.30.0' into feature/GHZS-2912
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
2023-07-20 09:40:21 +08:00
69866eaf91 Merge remote-tracking branch 'origin/dev' into dev-5.30.0 2023-07-19 19:26:05 +08:00
5a8f1d663d feat: 游戏库增加顶部tab栏—客户端 https://jira.shanqu.cc/browse/GHZS-2912 2023-07-19 14:46:19 +08:00
2be72776ce Merge branch 'feature-GHZS-2901' into 'dev-5.30.0'
feat: MIUI优化关闭提示弹窗—客户端 https://jira.shanqu.cc/browse/GHZS-2901

See merge request halo/android/assistant-android!1201
2023-07-17 09:51:44 +08:00
d92f6ff164 feat: MIUI优化关闭提示弹窗—客户端 https://jira.shanqu.cc/browse/GHZS-2901 2023-07-17 09:46:55 +08:00
9aaeee9b3d Merge remote-tracking branch 'origin/dev' into dev-5.30.0 2023-07-14 10:01:59 +08:00
b4e94eeabb Merge branch 'feature-GHZS-2855' into 'dev-5.30.0'
feat: 优化内部测试包的渠道切换功能 https://jira.shanqu.cc/browse/GHZS-2855

See merge request halo/android/assistant-android!1197
2023-07-12 16:04:48 +08:00
6f86dd7eef feat: 优化内部测试包的渠道切换功能 https://jira.shanqu.cc/browse/GHZS-2855 2023-07-12 15:58:33 +08:00
04d001a055 Merge branch 'feature/GHZS-2806' into 'dev-5.30.0'
feat: 插件管理功能优化-新增插件发布上架通知提醒—客户端 https://jira.shanqu.cc/browse/GHZS-2806

See merge request halo/android/assistant-android!1194
2023-07-11 16:07:15 +08:00
f10b08e152 feat: 插件管理功能优化-新增插件发布上架通知提醒—客户端 https://jira.shanqu.cc/browse/GHZS-2806 2023-07-11 14:33:04 +08:00
56c8885030 chore: 版本更新至 5.30.0 2023-07-05 09:56:12 +08:00
551 changed files with 15330 additions and 3200 deletions

View File

@ -72,6 +72,7 @@ android_build:
only:
- dev
- dev-5.29.0
- dev-5.30.0
# 代码检查
sonarqube_analysis:
@ -103,6 +104,7 @@ sonarqube_analysis:
only:
- dev
- dev-5.29.0
- dev-5.30.0
## 发送简易检测结果报告
send_sonar_report:
@ -121,6 +123,7 @@ send_sonar_report:
only:
- dev
- dev-5.29.0
- dev-5.30.0
oss-upload&send-email:
tags:
@ -152,4 +155,5 @@ oss-upload&send-email:
- /usr/local/bin/python /ci-android-mail.py
only:
- dev
- dev-5.29.0
- dev-5.29.0
- dev-5.30.0

View File

@ -188,6 +188,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${DEV_VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${DEV_QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${DEV_QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "CSJ_APPID", "\"${DEV_CSJ_APPID}\""
}
// publish 发布时候使用的 flavor接口仅包含正式环境
@ -199,6 +200,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
tea {
@ -209,6 +211,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
}
@ -221,6 +224,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
gdt {
@ -231,6 +235,7 @@ android {
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
}
}
@ -338,12 +343,19 @@ dependencies {
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':feature:vpn'))
implementation(project(':feature:pkg'))
implementation(project(':feature:oaid'))
implementation(project(':feature:floating-window'))
implementation(project(':feature:csj_ad'))
// implementation(project(':feature:beizi_startup_ad'))
implementation(project(':feature:xapk-installer'))
implementation(project(':feature:qq_game')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
File propFile = file('sign.properties')

View File

@ -77,7 +77,12 @@
androidx.compose.animation.core,
androidx.constraintlayout.compose,
androidx.compose.ui.test.manifest,
androidx.compose.ui.tooling.preview" />
com.bytedance.sdk.openadsdk,
androidx.compose.ui.tooling.preview,
com.tencent.qqmini,
com.tencent.qqmini.minigame.external,
com.tencent.qqmini.minigame.opensdk,
com.tencent.qqmini.union.ad" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -297,10 +302,6 @@
android:name="com.gh.gamecenter.CollectionActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserInfoEditActivity"
android:screenOrientation="portrait"
@ -314,26 +315,10 @@
android:name="com.gh.gamecenter.qa.answer.edit.AnswerEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.ConcernInfoActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.InfoActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageKeFuActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageInviteActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageVoteActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.questions.invite.QuestionsInviteActivity"
android:screenOrientation="portrait" />
@ -760,6 +745,18 @@
android:name="com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameHomeWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameSubjectActivity"
android:screenOrientation="portrait" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
@ -843,39 +840,6 @@
</intent-filter>
</receiver>
<!-- 梦工厂配置 开始 -->
<!--<meta-data
android:name="MGC_APPID"
android:value="1001276" />
<provider
android:name="com.leto.game.base.provider.LetoFileProvider"
android:authorities="${applicationId}.leto.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/leto_file_path"
tools:replace="android:resource" />
</provider>-->
<!-- 梦工厂配置 结束 -->
<!-- 穿山甲配置 开始 -->
<!--<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />-->
<!-- 穿山甲配置 结束 -->
</application>
</manifest>

View File

@ -0,0 +1,445 @@
package com.gh.ad
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.launcher.ARouter
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.LogUtils
import com.gh.common.util.NewFlatLogUtils.logOpenScreenAdSkip
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IBeiziAdProvider
import com.gh.gamecenter.core.provider.ICsjAdProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils.getToday
import com.gh.gamecenter.entity.AdConfig
import com.gh.gamecenter.entity.StartupAdEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
/**
* 广告实现代理类
*
* 由它来分发功能实现到具体的实现
*
* 以最复杂的开屏广告为例有三种实现1. 自有的广告实现 2. 穿山甲的开屏广告实现 3. Beizi 的开屏广告实现)
*
* 由于两个广告 SDK 有可能在一次启动中都被使用,所以会根据获取到的广告配置 config 来决定是否需要出是很好两个 SDK
*/
object AdDelegateHelper {
private var mCsjAdImpl: ICsjAdProvider? = null
private var mBeiziAdImpl: IBeiziAdProvider? = null
private var mAdConfigList: ArrayList<AdConfig>? = null
private var mSplashAd: AdConfig? = null
private var mDownloadManagerAd: AdConfig? = null
private val mGameSearchAdList: ArrayList<AdConfig> by lazy { arrayListOf() }
private var mVGameLaunchAd: AdConfig? = null
private var mIsCsjRequired: Boolean = false // 是否需要初始化穿山甲 SDK
private var mIsBeiziRequired: Boolean = false // 师傅需要初始化 Beizi SDK
private const val AD_SDK_CSJ = "穿山甲"
private const val AD_SDK_BEIZI = "倍孜"
private const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
private const val KEY_CACHE_CONFIG = "cache_config" // 放在 SP 里的广告缓存(避免接口加载问题)
private val mAdConfigSp: SharedPreferences by lazy {
HaloApp.getInstance().getSharedPreferences("AdConfig", Context.MODE_PRIVATE)
}
/**
* 请求接口获取广告相关配置
*/
@SuppressLint("CheckResult")
fun requestAdConfig(context: Context, isFromRetry: Boolean) {
// mAdConfigList 不为空不需要重试
if (isFromRetry && mAdConfigList != null) {
return
}
RetrofitManager.getInstance()
.newApi
.adConfig
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<List<AdConfig>>() {
override fun onSuccess(data: List<AdConfig>) {
handleAdConfig(context, data)
// 缓存数据到 SP 供接口请求失败用
SPUtils.setString(mAdConfigSp, KEY_CACHE_CONFIG, data.toJson())
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
// 若接口请求失败时,从 SP 里获取上次缓存的数据
val cachedConfig: List<AdConfig>? = SPUtils.getString(mAdConfigSp, KEY_CACHE_CONFIG).toObject()
if (cachedConfig != null) {
handleAdConfig(context, cachedConfig)
}
}
})
}
/**
* 获取搜索页的广告列表
*/
fun getGameSearchAdList(): ArrayList<AdConfig> {
return mGameSearchAdList
}
/**
* 获取下载管理页的广告
*/
fun getDownloadManagerAd(): AdConfig? {
return mDownloadManagerAd
}
/**
* 处理广告配置
*/
fun handleAdConfig(context: Context, configList: List<AdConfig>) {
for (config in configList) {
// 处理返回的数据
when (config.location) {
"halo_launch" -> mSplashAd = config
"download_manager" -> mDownloadManagerAd = config
"game_search" -> config.let { mGameSearchAdList.add(it) }
"helper_launch" -> mVGameLaunchAd = config
}
// 根据返回的值里判断是否含有 Beizi 的广告
if (!mIsBeiziRequired) {
if (config.thirdPartyAd?.sourceName == AD_SDK_BEIZI) {
mIsBeiziRequired = true
}
}
// 根据返回的值里判断是否含有 穿山甲 的广告
if (!mIsCsjRequired) {
if (config.thirdPartyAd?.sourceName == AD_SDK_CSJ) {
mIsCsjRequired = true
}
}
}
// 初始化 Beizi
if (mIsBeiziRequired && mBeiziAdImpl == null) {
mBeiziAdImpl =
ARouter.getInstance().build(RouteConsts.provider.beiziAd).navigation() as? IBeiziAdProvider
mBeiziAdImpl?.initSDK(context)
}
// 初始化穿山甲
if (mIsCsjRequired && mCsjAdImpl == null) {
mCsjAdImpl =
ARouter.getInstance().build(RouteConsts.provider.csjAd).navigation() as? ICsjAdProvider
mCsjAdImpl?.initSDK(context, BuildConfig.CSJ_APPID, HaloApp.getInstance().oaid)
// 监听亮色/暗色模式切换
DarkModeUtils.registerModeChangeListener {
val topActivity = CurrentActivityHolder.getCurrentActivity() ?: return@registerModeChangeListener
updateThemeStatus(context, DarkModeUtils.isDarkModeOn(topActivity))
}
}
}
/**
* 是否需要显示开屏广告
*/
fun shouldShowStartUpAd(): Boolean {
return mSplashAd != null
}
/**
* 更新主题样式
*/
private fun updateThemeStatus(context: Context, isDarkMode: Boolean) {
mCsjAdImpl?.updateThemeStatus(context, isDarkMode)
}
/**
* 请求开屏广告
*/
@JvmStatic
fun requestSplashAd(
activity: Activity,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
if (mSplashAd != null) {
if (mSplashAd!!.displayRule.adSource == AD_TYPE_SDK) {
// 第三方开屏广告回调,失败时根据接口配置选项决定是否显示自有开屏广告
val sdkSplashCallback: (isSuccess: Boolean) -> Unit = { isSuccess ->
if (isSuccess) {
hideCallback.invoke()
} else {
if (mSplashAd?.displayRule?.onFailedAction == "show") {
sdkStartAdContainer.visibility = View.GONE
requestStandardSplashAd(mSplashAd!!.ownerAd, startAdContainer, handler, hideCallback)
} else {
hideCallback.invoke()
}
}
}
// 第三方广告的数据为空,按加载失败处理
if (mSplashAd?.thirdPartyAd == null) {
sdkSplashCallback.invoke(false)
return
}
if (mSplashAd?.thirdPartyAd?.sourceName == AD_SDK_BEIZI) {
sdkStartAdContainer.visibility = View.VISIBLE
requestBeiziSplashAd(sdkStartAdContainer, adsViewGroup, adViewWidthInPx, adViewHeightInPx, sdkSplashCallback)
} else if (mSplashAd?.thirdPartyAd?.sourceName == AD_SDK_CSJ) {
sdkStartAdContainer.visibility = View.VISIBLE
requestCsjSplashAd(
activity,
mSplashAd?.thirdPartyAd?.slotId ?: "unknown",
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
sdkStartAdContainer,
sdkSplashCallback
)
}
} else {
requestStandardSplashAd(mSplashAd!!.ownerAd, startAdContainer, handler, hideCallback)
}
}
}
/**
* 获取穿山甲的开屏广告
*/
private fun requestCsjSplashAd(
activity: Activity,
slotId: String,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mCsjAdImpl == null) {
callback.invoke(false)
} else {
mCsjAdImpl?.requestSplashAd(
activity,
slotId,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
callback,
)
}
}
/**
* 获取 Beizi 的开屏广告
*/
private fun requestBeiziSplashAd(
startAdContainer: View,
adsFl: FrameLayout,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mBeiziAdImpl == null) {
callback.invoke(false)
} else {
mBeiziAdImpl?.requestSplashAd(startAdContainer, adsFl, adViewWidthInPx, adViewHeightInPx, callback)
}
}
/**
* 显示自有的开屏广告
*/
private fun requestStandardSplashAd(
splashAd: StartupAdEntity?,
startAdContainer: ViewGroup,
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
if (splashAd == null) {
hideCallback.invoke()
return
}
if (!TextUtils.isEmpty(splashAd.img)) {
val showedTodayTimestamp = SPUtils.getString(Constants.SP_STARTUP_AD_TIMESTAMP, "") ?: ""
when (splashAd.rule) {
"each" -> showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
"once" -> if (TextUtils.isEmpty(showedTodayTimestamp)
|| !showedTodayTimestamp.contains(splashAd.id)
) {
showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
} else {
hideCallback.invoke()
}
"everyday" -> {
val today = getToday()
if (TextUtils.isEmpty(showedTodayTimestamp)
|| !showedTodayTimestamp.contains(today)
|| !showedTodayTimestamp.contains(splashAd.id)
) {
showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
} else {
hideCallback.invoke()
}
}
else -> hideCallback.invoke()
}
SPUtils.setString(Constants.SP_STARTUP_AD_TIMESTAMP, splashAd.id + getToday())
} else {
hideCallback.invoke()
}
}
private fun showStandardSplashAd(
ad: StartupAdEntity,
startAdContainer: ViewGroup,
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
val jumpBtn: View = startAdContainer.findViewById(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
startAdContainer.visibility = View.VISIBLE
jumpDetailBtn.text = ad.desc
jumpDetailBtn.setDrawableEnd(
AppCompatResources.getDrawable(
startAdContainer.context,
R.drawable.ic_startup_ad_arrow
), null, null
)
ImageUtils.display(adImage, ad.img)
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
jumpBtn.setOnClickListener {
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
}
val sources: MutableList<ExposureSource> = ArrayList()
sources.add(ExposureSource("开屏广告", ad.id))
val event = createEvent(null, sources, null, ExposureType.EXPOSURE)
ExposureManager.log(event)
if (ad.button) {
jumpDetailBtn.setOnClickListener { v: View ->
directToLinkPage(v.context, ad.jump, "(启动广告)", "", event)
v.postDelayed({
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
}, 1000)
}
jumpDetailBtn.visibility = View.VISIBLE
LogUtils.logStartAd("watch_start_ads", ad)
} else {
LogUtils.logStartAd("start_ads", ad)
}
handler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_AD, 1000)
}
/**
* 获取信息流广告
*/
fun requestFlowAd(
fragment: Fragment,
slotId: String,
adContainerView: ViewGroup,
expressViewWidth: Float,
callback: (isSuccess: Boolean) -> Unit,
) {
mCsjAdImpl?.requestFlowAd(fragment, adContainerView, slotId, expressViewWidth, callback)
}
/**
* 获取 Banner 广告
*/
fun requestBannerAd(
fragment: Fragment,
containerView: ViewGroup,
ad: AdConfig.ThirdPartyAd,
expressViewWidthInDp: Float,
callback: (isSuccess: Boolean) -> Unit
) {
val slotId = ad.slotId
val displayRatio: Float = if (ad.displaySize.isEmpty()) {
2F
} else {
val array = ad.displaySize.split("*")
if (array.size == 2) {
array[0].toFloat() / array[1].toFloat()
} else {
2F
}
}
val expressViewHeightInDp = expressViewWidthInDp / displayRatio
mCsjAdImpl?.requestBannerAd(
fragment,
containerView,
slotId,
expressViewWidthInDp,
expressViewHeightInDp,
callback
)
}
/**
* 取消开屏广告
*/
fun cancelSplashAd(context: Context) {
mBeiziAdImpl?.cancelSplashAd(context)
mCsjAdImpl?.cancelSplashAd(context)
}
}

View File

@ -1,18 +1,20 @@
package com.gh.base
import android.graphics.Typeface
import android.os.Bundle
import android.text.TextUtils
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils.getBoolean
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
@ -58,6 +60,7 @@ abstract class DownloadToolbarActivity : ToolBarActivity() {
}
val downloadMenuView = mActionMenuView.menu.findItem(R.id.menu_download).actionView
mDownloadCountHint = downloadMenuView?.findViewById(R.id.menu_download_count_hint)
mDownloadCountHint?.typeface = Typeface.createFromAsset(assets, "fonts/d_din_bold_only_number.ttf")
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
@ -74,19 +77,27 @@ abstract class DownloadToolbarActivity : ToolBarActivity() {
if (mDownloadCountHint == null) return
val count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList)
if (count != null) {
mDownloadCountHint!!.visibility = View.VISIBLE
mDownloadCountHint!!.text = count
val params = mDownloadCountHint!!.layoutParams
if (TextUtils.isEmpty(count)) {
params.width = DisplayUtils.dip2px(6f)
params.height = DisplayUtils.dip2px(6f)
} else {
params.width = DisplayUtils.dip2px(12f)
params.height = DisplayUtils.dip2px(12f)
}
mDownloadCountHint!!.layoutParams = params
mDownloadCountHint?.visibility = View.VISIBLE
mDownloadCountHint?.text = count
val params = mDownloadCountHint?.layoutParams
params?.width = if (count.isEmpty()) 6F.dip2px() else ConstraintLayout.LayoutParams.WRAP_CONTENT
params?.height = if (count.isEmpty()) 6F.dip2px() else 14F.dip2px()
(params as? ViewGroup.MarginLayoutParams)?.setMargins(
0,
if (count.isEmpty()) 0 else (-4F).dip2px(),
if (count.isEmpty()) (-4F).dip2px() else (-8F).dip2px(),
0
)
mDownloadCountHint?.setPadding(
if (count.isEmpty()) 0 else 4F.dip2px(),
0,
if (count.isEmpty()) 0 else 4F.dip2px(),
0
)
mDownloadCountHint?.minWidth = if (count.isEmpty()) 0 else 14F.dip2px()
mDownloadCountHint?.layoutParams = params
} else {
mDownloadCountHint!!.visibility = View.GONE
mDownloadCountHint?.visibility = View.GONE
}
}

View File

@ -68,6 +68,7 @@ class DefaultJsApi(
val entrance: String = "",
private var mFragment: Fragment? = null,
private var mBbsId: String? = "",
private var mOriginUrl: String?= "",
) {
private var mLoginHandler: CompletionHandler<Any>? = null
@ -632,12 +633,19 @@ class DefaultJsApi(
fun logExposure(event: Any) {
val simpleExposureEvent = event.toString().toObject() ?: SimpleExposureEvent()
if (simpleExposureEvent.id.isNotEmpty()) {
val exposureSource = ExposureSource("游戏活动", "${simpleExposureEvent.title}+${simpleExposureEvent.id}")
val sourceKey = if (mOriginUrl?.contains(Constants.URL_QUERY_FROM_FLOATING_WINDOW) == true) {
"落地页"
} else {
"游戏活动"
}
val exposureSource = ExposureSource(sourceKey, "${simpleExposureEvent.title}+${simpleExposureEvent.id}")
mExposureEvent = ExposureEvent.createEvent(
gameEntity = null,
source = arrayListOf(exposureSource),
)
ExposureManager.log(mExposureEvent!!)
ExposureManager.commitSavedExposureEvents(true)
}
}

View File

@ -84,11 +84,6 @@ object FixedRateJobHelper {
VideoRecordUtils.commitVideoRecord()
}
// 获取启动广告 (第一次不需要获取)
if (elapsedTime % STARTUP_AD == 0L && mExecuteCount != 0) {
AdHelper.getSettingAdCache()
}
mExecuteCount++
}
}

View File

@ -0,0 +1,23 @@
package com.gh.common.chain
import android.content.Context
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.feature.entity.GameEntity
class LandPageAddressHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
if (gameEntity.isLandPageAddressDialog()) {
DialogUtils.showLandPageAddressDialog(context, gameEntity) {// 跳转第三方落地页
DirectUtils.directToExternalBrowser(context, gameEntity.landPageAddressDialog!!.link!!)
}
} else {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}
}

View File

@ -7,7 +7,15 @@ import com.gh.gamecenter.feature.entity.GameEntity
class OverseaDownloadHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
DialogUtils.showOverseaDownloadDialog(context, gameEntity) {
if (gameEntity.isOverseaAddressDialog()) {
DialogUtils.showOverseaDownloadDialog(context, gameEntity) {// 跳转海外下载地址弹窗
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
} else {
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {

View File

@ -459,7 +459,6 @@ public class Config {
DarkModeUtils.INSTANCE.updateFollowSystemDarkModeToSp(true);
DarkModeUtils.INSTANCE.initDarkMode();
}
AdHelper.prefetchStartUpAd(mNewApiSettingsEntity);
SPUtils.setString(Constants.SP_NEW_API_SETTINGS, GsonUtils.toJson(data));
}
});

View File

@ -28,6 +28,7 @@ import com.gh.common.chain.CheckDownloadHandler;
import com.gh.common.chain.CheckStoragePermissionHandler;
import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.LandPageAddressHandler;
import com.gh.common.chain.OverseaDownloadHandler;
import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
@ -412,6 +413,7 @@ public class BindingAdapters {
builder.addHandler(new DownloadDialogHelperHandler());
builder.addHandler(new CertificationHandler());
builder.addHandler(new VersionNumberHandler());
builder.addHandler(new LandPageAddressHandler());
builder.addHandler(new OverseaDownloadHandler());
builder.addHandler(new CheckDownloadHandler());

View File

@ -10,6 +10,7 @@ import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.feature.entity.User
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
import com.gh.gamecenter.qa.entity.ArticleDetailEntity

View File

@ -19,6 +19,10 @@ class AppProviderImpl : IAppProvider {
return HaloApp.getInstance().getString(R.string.app_name)
}
override fun getAppVersion(): String {
return BuildConfig.VERSION_NAME
}
override fun getGid(): String {
return HaloApp.getInstance().gid ?: ""
}

View File

@ -1,6 +1,7 @@
package com.gh.common.provider
import android.content.Context
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import com.alibaba.android.arouter.facade.annotation.Route
@ -24,6 +25,14 @@ class BindingAdaptersProviderImpl : IBindingAdaptersProvider {
BindingAdapters.setGameTags(layout, gameEntity)
}
override fun setMessageUnread(view: TextView, unreadCount: Int) {
BindingAdapters.setMessageUnread(view, unreadCount)
}
override fun setGame(view: View, gameEntity: GameEntity) {
BindingAdapters.setGame(view, gameEntity)
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,22 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import android.os.Parcelable
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.CommentDetailActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.ICommentDetailProvider
import com.gh.gamecenter.feature.entity.MessageEntity
@Route(path = RouteConsts.provider.commentDetail, name = "CommentDetailActivity暴露服务")
class CommentDetailProviderImpl : ICommentDetailProvider {
override fun getIntent(context: Context, commentId: String?, message: Parcelable): Intent {
return CommentDetailActivity.getIntent(context, commentId, message as MessageEntity.Article)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,18 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.ICommentManagerProvider
import com.gh.gamecenter.manager.CommentManager
@Route(path = RouteConsts.provider.commentManager, name = "CommentManager暴露服务")
class CommentManagerProviderImpl : ICommentManagerProvider {
override fun addUrl(ids: String) {
CommentManager.getInstance().addUrl(ids)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,23 @@
package com.gh.common.provider
import android.content.Context
import android.widget.TextView
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.CommentUtils
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.ICommentUtilsProvider
@Route(path = RouteConsts.provider.commentUtils, name = "CommentUtils暴露服务")
class CommentUtilsProviderImpl : ICommentUtilsProvider {
override fun setCommentTime(textView: TextView, time: Long) {
CommentUtils.setCommentTime(textView, time)
}
override fun getCommentTime(timestamp: Long): String {
return CommentUtils.getCommentTime(timestamp)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,26 @@
package com.gh.common.provider
import android.content.Context
import android.widget.LinearLayout
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.ConcernContentUtils
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IConcernContentUtilsProvider
@Route(path = RouteConsts.provider.concernContentUtils, name = "ConcernContentUtils暴露服务")
class ConcernContentUtilsProviderImpl : IConcernContentUtilsProvider {
override fun addContentPic(
context: Context,
linearLayout: LinearLayout,
list: List<String>,
entrance: String,
width: Int
) {
ConcernContentUtils.addContentPic(context, linearLayout, list, entrance, width)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,20 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.ConcernActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IConcernProvider
@Route(path = RouteConsts.provider.concernActivity, name = "ConcernActivity暴露服务")
class ConcernProviderImpl : IConcernProvider {
override fun getIntent(context: Context, entrance: String): Intent {
return ConcernActivity.getIntent(context, entrance)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,19 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.constant.Config
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feature.provider.IConfigSettingProvider
@Route(path = RouteConsts.provider.configSetting, name = "Config.getSettings暴露服务")
class ConfigSettingProviderImpl : IConfigSettingProvider {
override fun getSettings(): SettingsEntity? {
return Config.getSettings()
}
override fun init(context: Context?) {
// do nothing
}
}

View File

@ -0,0 +1,22 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.DataCollectionUtils
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.IDataCollectionProvider
@Route(path = RouteConsts.provider.dataCollection, name = "DataCollectionUtils暴露服务")
class DataCollectionProviderImpl : IDataCollectionProvider {
override fun uploadClick(context: Context, vararg args: String) {
DataCollectionUtils.uploadClick(context, *args)
}
override fun uploadConcern(context: Context, vararg args: String) {
DataCollectionUtils.uploadConcern(context, *args)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -69,6 +69,56 @@ class DirectProviderImpl : IDirectProvider {
return DirectUtils.directToQqGroup(context, groupNumber)
}
override fun directToHomeActivity(context: Context, userId: String?, entrance: String?, path: String?) {
DirectUtils.directToHomeActivity(context, userId, entrance, path)
}
override fun directToAnswerDetail(context: Context, id: String, entrance: String?, path: String?) {
DirectUtils.directToAnswerDetail(context, id, entrance, path)
}
override fun directToCommunityArticle(
context: Context,
articleId: String?,
communityId: String?,
entrance: String?,
path: String?
) {
DirectUtils.directToCommunityArticle(context, articleId, communityId, entrance, path)
}
override fun directToVideoDetail(context: Context, videoId: String, entrance: String?, path: String?) {
DirectUtils.directToVideoDetail(context, videoId, entrance, path)
}
override fun directToAmway(context: Context, fixedTopAmwayCommentId: String?, entrance: String?, path: String?) {
DirectUtils.directToAmway(context, fixedTopAmwayCommentId, entrance, path)
}
override fun directToOrderCenter(context: Context) {
DirectUtils.directToOrderCenter(context)
}
override fun directToOrderDetail(context: Context, orderId: String) {
DirectUtils.directToOrderDetail(context, orderId)
}
override fun directToEnergyRecord(context: Context, position: Int) {
DirectUtils.directToEnergyRecord(context, position)
}
override fun directToMyPrizePage(context: Context) {
DirectUtils.directToMyPrizePage(context)
}
override fun directToWinOrderDetail(context: Context, orderId: String, activityId: String) {
DirectUtils.directToWinOrderDetail(context, orderId, activityId)
}
override fun directToQGame(context: Context) {
return DirectUtils.directToQGameHome(context)
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,24 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.IGameCollectionDetailProvider
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
@Route(path = RouteConsts.provider.gameCollectionDetail, name = "GameCollectionDetailActivity暴露服务")
class GameCollectionDetailProviderImpl : IGameCollectionDetailProvider {
override fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean): Intent {
return GameCollectionDetailActivity.getIntent(context, gameCollectionId, isFromSquare)
}
override fun getSpecifiedCommentIntent(context: Context, gameCollectionId: String, topCommentId: String): Intent {
return GameCollectionDetailActivity.getSpecifiedCommentIntent(context, gameCollectionId, topCommentId)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -10,6 +10,15 @@ import com.gh.gamecenter.feature.provider.IGameDetailProvider
@Route(path = RouteConsts.provider.gameDetail, name = "GameDetailActivity暴露服务")
class GameDetailProviderImpl : IGameDetailProvider {
override fun startGameDetailActivity(
context: Context,
gameEntity: GameEntity?,
entrance: String,
traceEvent: ExposureEvent?
) {
GameDetailActivity.startGameDetailActivity(context, gameEntity, entrance, traceEvent)
}
override fun startGameDetailActivity(
context: Context,
gameId: String,
@ -18,6 +27,7 @@ class GameDetailProviderImpl : IGameDetailProvider {
) {
GameDetailActivity.startGameDetailActivity(context, gameId, entrance, traceEvent)
}
override fun startGameDetailActivity(
context: Context,
gameEntity: GameEntity?,
@ -40,6 +50,30 @@ class GameDetailProviderImpl : IGameDetailProvider {
)
}
override fun startGameDetailActivity(
context: Context,
gameId: String,
entrance: String?,
defaultTab: Int,
isSkipGameComment: Boolean,
scrollToLibao: Boolean,
openVideoStreaming: Boolean,
openPlatformWindow: Boolean,
traceEvent: ExposureEvent?
) {
GameDetailActivity.startGameDetailActivity(
context,
gameId,
entrance,
defaultTab,
isSkipGameComment,
scrollToLibao,
openVideoStreaming,
openPlatformWindow,
traceEvent
)
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,18 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.GameTrendsHelper
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IGameTrendsHelperProvider
@Route(path = RouteConsts.provider.gameTrendsHelper, name = "GameTrendsHelper暴露服务")
class GameTrendsHelperProviderImpl : IGameTrendsHelperProvider {
override fun updateReadPostTime() {
GameTrendsHelper.updateReadPostTime()
}
override fun init(context: Context?) {
// do nothing
}
}

View File

@ -0,0 +1,27 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.LibaoUtils
import com.gh.common.util.LibaoUtils.PostLibaoListener
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.ILibaoUtilsProvider
@Route(path = RouteConsts.provider.libaoUtils, name = "LibaoUtils暴露服务")
class LibaoUtilsProviderImpl : ILibaoUtilsProvider {
override fun getLibaoStatus(ids: String, successCallback: ((Any?) -> Unit)?, failureCallback: (() -> Unit)?) {
LibaoUtils.getLibaoStatus(ids, object : PostLibaoListener {
override fun postSucceed(response: Any?) {
successCallback?.invoke(response)
}
override fun postFailed(error: Throwable?) {
failureCallback?.invoke()
}
})
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.entity.SuggestType
@ -62,6 +63,16 @@ class LinkDirectUtilsProviderImpl : ILinkDirectUtilsProvider {
DirectUtils.directToSuggestion(context, type, hiddenHint)
}
override fun directToCommunityColumn(
context: Context,
community: CommunityEntity?,
subjectId: String,
entrance: String?,
path: String?
) {
DirectUtils.directToCommunityColumn(context, community, subjectId, entrance, path)
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,31 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.MessageDetailActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.ConcernEntity
import com.gh.gamecenter.feature.provider.IMessageDetailProvider
@Route(path = RouteConsts.provider.messageDetail, name = "MessageDetailActivity暴露服务")
class MessageDetailProviderImpl : IMessageDetailProvider {
override fun getIntentById(
context: Context,
newsId: String,
commentNum: Int,
openSoftInput: Boolean,
entrance: String
): Intent {
return MessageDetailActivity.getIntentById(context, newsId, commentNum, openSoftInput, entrance)
}
override fun getIntentByEntity(context: Context, concernEntity: ConcernEntity, entrance: String): Intent? {
return MessageDetailActivity.getIntentByEntity(context, concernEntity, entrance)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -1,9 +1,13 @@
package com.gh.common.provider
import android.content.Context
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IMessageUnreadRepositoryProvider
import com.gh.gamecenter.feature.entity.MessageUnreadCount
import com.gh.gamecenter.feature.entity.MessageUnreadEntity
import com.gh.gamecenter.feature.provider.IMessageUnreadRepositoryProvider
import com.gh.gamecenter.message.MessageUnreadRepository
@Route(path = RouteConsts.provider.messageUnreadRepository, name = "MessageUnreadRepository暴露服务")
@ -13,6 +17,22 @@ class MessageUnreadRepositoryProviderImpl : IMessageUnreadRepositoryProvider {
MessageUnreadRepository.loadMessageUnreadData()
}
override fun loadMessageUnreadTotal(isRecordData: Boolean) {
MessageUnreadRepository.loadMessageUnreadTotal(isRecordData)
}
override fun getUnreadLiveData(): MediatorLiveData<MessageUnreadEntity> {
return MessageUnreadRepository.unreadLiveData
}
override fun getZixunConcernLiveData(): MutableLiveData<Boolean> {
return MessageUnreadRepository.zixunConcern
}
override fun getMessageUnreadCountLiveData(): MutableLiveData<MessageUnreadCount?> {
return MessageUnreadRepository.messageUnreadCountLiveData
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,83 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.INewCommentDetailProvider
import com.gh.gamecenter.qa.comment.NewCommentDetailActivity
@Route(path = RouteConsts.provider.newCommentDetail, name = "NewCommentDetailActivity暴露服务")
class NewCommentDetailProviderImpl : INewCommentDetailProvider {
override fun getAnswerCommentIntent(
context: Context,
commentId: String,
questionId: String,
topCommentId: String,
entrance: String,
path: String
): Intent {
return NewCommentDetailActivity.getAnswerCommentIntent(
context,
commentId,
questionId,
topCommentId,
entrance,
path
)
}
override fun getArticleCommentIntent(
context: Context,
commentId: String,
communityId: String,
articleId: String,
topCommentId: String,
entrance: String,
path: String
): Intent {
return NewCommentDetailActivity.getArticleCommentIntent(
context,
commentId,
communityId,
articleId,
topCommentId,
entrance,
path
)
}
override fun getVideoCommentIntent(
context: Context,
commentId: String,
videoId: String,
topCommentId: String,
entrance: String,
path: String
): Intent {
return NewCommentDetailActivity.getVideoCommentIntent(context, commentId, videoId, topCommentId, entrance, path)
}
override fun getGameCollectionCommentIntent(
context: Context,
commentId: String,
gameCollectionId: String,
topCommentId: String,
entrance: String,
path: String
): Intent {
return NewCommentDetailActivity.getGameCollectionCommentIntent(
context,
commentId,
gameCollectionId,
topCommentId,
entrance,
path
)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -33,6 +33,18 @@ class PackageUtilsProviderImpl : IPackageUtilsProvider {
return PackageUtils.getSideLoadedInfo()
}
override fun isSignedByGh(context: Context, packageName: String): Boolean {
return PackageUtils.isSignedByGh(context, packageName)
}
override fun getInstalledTime(context: Context, packageName: String): Long {
return PackageUtils.getInstalledTime(context, packageName)
}
override fun getVersionNameByPackageName(packageName: String): String {
return PackageUtils.getVersionNameByPackageName(packageName) ?: ""
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -3,7 +3,8 @@ package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IPackagesManagerProvider
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.feature.provider.IPackagesManagerProvider
import com.gh.gamecenter.manager.PackagesManager
@Route(path = RouteConsts.provider.packagesManager, name = "PackagesManager暴露服务")
@ -12,6 +13,10 @@ class PackagesManagerProviderImpl: IPackagesManagerProvider {
return PackagesManager.isCanPluggable(gameId, packageName)
}
override fun getFilterSameApkInstalledList(): ArrayList<GameInstall> {
return PackagesManager.getFilterSameApkInstalledList()
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -30,6 +30,10 @@ class RegionSettingHelperProviderImpl : IRegionSettingHelperProvider {
return RegionSettingHelper.getIpInfo()
}
override fun shouldThisGameBeFiltered(gameId: String?): Boolean {
return RegionSettingHelper.shouldThisGameBeFiltered(gameId)
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,19 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.ShareCardPicActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.ConcernEntity
import com.gh.gamecenter.feature.provider.IShareCardPicProvider
@Route(path = RouteConsts.provider.shareCardPicActivity, name = "ShareCardPicActivity暴露服务")
class ShareCardPicProviderImpl : IShareCardPicProvider {
override fun startShareCardPicActivity(context: Context, concernEntity: ConcernEntity, entrance: String) {
ShareCardPicActivity.startShareCardPicActivity(context, concernEntity, entrance)
}
override fun init(context: Context?) {
// do nothing
}
}

View File

@ -0,0 +1,20 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.ShareCardActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.ConcernEntity
import com.gh.gamecenter.feature.provider.IShareCardProvider
@Route(path = RouteConsts.provider.shareCardActivity, name = "ShareCardActivity暴露服务")
class ShareCardProviderImpl : IShareCardProvider {
override fun getIntent(context: Context, concernEntity: ConcernEntity, shareContent: String): Intent {
return ShareCardActivity.getIntent(context, concernEntity, shareContent)
}
override fun init(context: Context?) {
// do nothing
}
}

View File

@ -0,0 +1,20 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.ISimpleAnswerDetailProvider
import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity
@Route(path = RouteConsts.provider.simpleAnswerDetail, name = "SimpleAnswerDetailActivity暴露服务")
class SimpleAnswerDetailProviderImpl : ISimpleAnswerDetailProvider {
override fun getIntent(context: Context, answerId: String, entrance: String, path: String): Intent {
return SimpleAnswerDetailActivity.getIntent(context, answerId, entrance, path)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,24 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.ISubjectProvider
import com.gh.gamecenter.subject.SubjectActivity
@Route(path = RouteConsts.provider.subject, name = "SubjectActivity暴露服务")
class SubjectProviderImpl : ISubjectProvider {
override fun startSubjectActivity(
context: Context,
id: String?,
name: String?,
isOrder: Boolean,
entrance: String?
) {
SubjectActivity.startSubjectActivity(context, id, name, isOrder, null, entrance)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -0,0 +1,22 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IVisitManagerProvider
import com.gh.gamecenter.manager.VisitManager
@Route(path = RouteConsts.provider.visitManager, name = "VisitManager暴露服务")
class VisitManagerProviderImpl : IVisitManagerProvider {
override fun updateOkhttpCache(context: Context, newsId: String) {
VisitManager.updateOkhttpCache(context, newsId)
}
override fun addUrl(ids: String) {
VisitManager.getInstance().addUrl(ids)
}
override fun init(context: Context?) {
// Do nothing
}
}

View File

@ -35,6 +35,16 @@ class WebProviderImpl : IWebProvider {
return WebActivity.getQAIntent(context, url, title, isWebPageHandleBackPressed, qaType)
}
override fun getIntentByNews(
context: Context?,
concernLink: String?,
concernGameName: String,
concernId: String?,
entrance: String?
): Intent {
return WebActivity.getIntentByNews(context, concernLink, concernGameName, concernId, entrance)
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -19,44 +19,11 @@ object AdHelper {
const val LOCATION_SUGGESTION_FUNCTION = "suggestion_function"
const val LOCATION_SIMULATOR_GAME = "simulator_game"
@JvmStatic
fun getStartUpAd(): StartupAdEntity? {
return Config.getNewApiSettingsEntity()?.startAd
}
@JvmStatic
fun getStartUp(): StartupAdEntity? {
return Config.getNewApiSettingsEntity()?.startup
}
@JvmStatic
fun prefetchStartUpAd(settingsEntity: NewApiSettingsEntity) {
if (settingsEntity.startAd != null && !settingsEntity.startAd?.img.isNullOrEmpty()) {
val screenWidth = DisplayUtils.getScreenWidth()
val transformedUrl = ImageUtils.getTransformedUrl(settingsEntity.startAd?.img, screenWidth) ?: return
ImageUtils.prefetchToDiskCache(transformedUrl)
}
}
fun getSettingAdCache() {
RetrofitManager.getInstance().newApi
.getSettingAdCache(HaloApp.getInstance().channel)
.compose(observableToMain())
.subscribe(object : Response<NewApiSettingsEntity>() {
override fun onResponse(response: NewApiSettingsEntity?) {
super.onResponse(response)
val settings = Config.getNewApiSettingsEntity()
if (settings != null) {
settings.startAd = response?.startAd
Config.updateNewApiSettings(settings)
if (response != null) {
prefetchStartUpAd(response)
}
}
}
})
}
fun getAd(location: String): SettingsEntity.AD? {
val adList = Config.getSettings()?.adList ?: return null

View File

@ -13,7 +13,7 @@ import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.ifLogin
import com.gh.gamecenter.common.utils.showAutoOrientation
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.feature.entity.CommentEntity
import com.gh.gamecenter.feature.entity.Permissions
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.comment.OnCommentOptionClickListener

View File

@ -29,7 +29,7 @@ import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.NumberUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.MeEntity;
import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.login.user.UserManager;

View File

@ -71,8 +71,8 @@ import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SpanBuilder;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.databinding.DialogAddressConfirmationBinding;
import com.gh.gamecenter.databinding.DialogBindPhoneBinding;
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
import com.gh.gamecenter.databinding.DialogRelievePhoneBinding;
import com.gh.gamecenter.databinding.DialogReportReasonBinding;
@ -732,40 +732,65 @@ public class DialogUtils {
public static void showOverseaDownloadDialog(Context context, GameEntity gameEntity, @NonNull ConfirmListener listener) {
context = checkDialogContext(context);
if (gameEntity.getOverseasAddressDialog() == null
|| gameEntity.getApk().size() == 0
|| !gameEntity.getOverseasAddressDialog().isEnable()) {
listener.onConfirm();
} else {
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
DialogOverseaConfirmationBinding binding = DialogOverseaConfirmationBinding.inflate(LayoutInflater.from(context), null, false);
DialogAddressConfirmationBinding binding = DialogAddressConfirmationBinding.inflate(LayoutInflater.from(context), null, false);
View contentView = binding.getRoot();
View contentView = binding.getRoot();
binding.gameIcon.displayGameIcon(gameEntity);
binding.gameNameTv.setText(context.getString(R.string.dialog_oversea_hint, gameEntity.getName()));
binding.closeIv.setOnClickListener(v -> dialog.dismiss());
binding.gameIcon.displayGameIcon(gameEntity);
binding.gameNameTv.setText(context.getString(R.string.dialog_oversea_hint, gameEntity.getName()));
binding.closeIv.setOnClickListener(v -> dialog.dismiss());
if ("show&download".equals(gameEntity.getOverseasAddressDialog().getStatus())) {
gameEntity.getApk().get(0).setUrl(gameEntity.getOverseasAddressDialog().getLink());
}
binding.urlTv.setText(gameEntity.getOverseasAddressDialog().getLink());
binding.downloadBtn.setText("下载(" + gameEntity.getApk().get(0).getSize() + "");
binding.downloadBtn.setOnClickListener(v -> {
listener.onConfirm();
dialog.dismiss();
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
if ("show&download".equals(gameEntity.getOverseasAddressDialog().getStatus())) {
gameEntity.getApk().get(0).setUrl(gameEntity.getOverseasAddressDialog().getLink());
}
binding.urlTv.setText(gameEntity.getOverseasAddressDialog().getLink());
binding.downloadBtn.setText("下载(" + gameEntity.getApk().get(0).getSize() + "");
binding.downloadBtn.setOnClickListener(v -> {
listener.onConfirm();
dialog.dismiss();
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
// 跳转第三方落地页下载弹窗
public static void showLandPageAddressDialog(Context context, GameEntity gameEntity, @NonNull ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
DialogAddressConfirmationBinding binding = DialogAddressConfirmationBinding.inflate(LayoutInflater.from(context), null, false);
View contentView = binding.getRoot();
binding.gameIcon.displayGameIcon(gameEntity);
binding.gameNameTv.setText(context.getString(R.string.dialog_land_page_address_hint, gameEntity.getName()));
binding.closeIv.setOnClickListener(v -> dialog.dismiss());
binding.urlTv.setText(gameEntity.getLandPageAddressDialog().getLink());
binding.downloadBtn.setText(context.getString(R.string.dialog_land_page_address_confirm));
binding.downloadBtn.setOnClickListener(v -> {
listener.onConfirm();
dialog.dismiss();
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showGameH5DownloadDialog(Context context, GameEntity gameEntity, RegionSetting.GameH5Download gameH5Download) {
@ -773,7 +798,7 @@ public class DialogUtils {
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
DialogOverseaConfirmationBinding binding = DialogOverseaConfirmationBinding.inflate(LayoutInflater.from(context), null, false);
DialogAddressConfirmationBinding binding = DialogAddressConfirmationBinding.inflate(LayoutInflater.from(context), null, false);
View contentView = binding.getRoot();
@ -1293,11 +1318,13 @@ public class DialogUtils {
return dialog;
}
public static void showReserveSuccess2WechatBindDialog(Context context, ConfirmListener confirmListener, CancelListener cancelListener) {
public static void showReserveOrVoteSuccess2WechatBindDialog(Context context, Boolean isReserve, ConfirmListener confirmListener, CancelListener cancelListener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogWechatReserveSuccessBinding binding = DialogWechatReserveSuccessBinding.inflate(LayoutInflater.from(context));
binding.titleIv.setImageResource(isReserve ? R.drawable.bg_reserve_success : R.drawable.bg_vote_success);
binding.contentTv.setText(isReserve ? "游戏上线时,您将在消息中心收到通知。为了避免错过通知,建议您开启微信公众号提醒": "版本上线时,您将在消息中心收到通知。为了避免错过通知,亦建议您开启微信公众号提醒");
binding.closeBtn.setOnClickListener(v -> {
cancelListener.onCancel();
dialog.dismiss();
@ -1318,13 +1345,13 @@ public class DialogUtils {
}
}
public static void showReserveSuccessDialog(Context context) {
public static void showReserveOrVoteSuccessDialog(Context context, Boolean isReserve) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogAlertDefaultBinding binding = DialogAlertDefaultBinding.inflate(LayoutInflater.from(context));
binding.titleTv.setText("游戏预约成功");
binding.contentTv.setText("游戏上线时,您将在消息中心和微信公众号收到通知,不会错过任何预约的游戏");
binding.titleTv.setText(isReserve ? "游戏预约成功" : "版本投票成功");
binding.contentTv.setText(isReserve ? "游戏上线时,您将在消息中心和微信公众号收到通知,不会错过任何预约的游戏" : "版本上线时,您将在消息中心和微信公众号收到通知,不会错过任何投票的版本");
binding.confirmTv.setText("我知道了");
binding.centerDivider.setVisibility(View.GONE);
binding.cancelTv.setVisibility(View.GONE);

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
@ -9,6 +10,7 @@ import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager.log
import com.gh.common.exposure.ExposureTraceUtils.appendTrace
@ -28,9 +30,9 @@ import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.EntranceConsts.*
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.*
import com.gh.gamecenter.common.entity.Display
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IQGameProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.discovery.DiscoveryActivity
@ -39,10 +41,12 @@ import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBSkip
import com.gh.gamecenter.feature.entity.GameDetailServer
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.LibaoEntity
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.provider.IConcernInfoProvider
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.forum.home.CommunityHomeFragment
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
@ -68,6 +72,9 @@ import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
import com.gh.gamecenter.qgame.QGameHomeWrapperActivity
import com.gh.gamecenter.qgame.QGameSearchActivity
import com.gh.gamecenter.qgame.QGameViewModel
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.servers.GameServerTestActivity
import com.gh.gamecenter.servers.GameServersActivity
@ -91,7 +98,6 @@ import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
import java.net.URLEncoder
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.roundToInt
/**
@ -99,53 +105,6 @@ import kotlin.math.roundToInt
*/
object DirectUtils {
/**
* 跳转到特定页面,根据 [type] 决定跳转页面,[path] 为跳转前的页面名称
*/
@JvmStatic
fun directToSpecificPage(
context: Context,
type: String,
link: String,
text: String? = "",
entrance: String? = null,
path: String? = null
) {
when (type) {
HOST_ARTICLE -> directToArticle(context, id = link, entrance = entrance)
HOST_GAME -> directToGameDetail(context, id = link, entrance = entrance)
HOST_GAME_DOWNLOAD -> directToGameDetail(context, id = link, entrance = entrance, autoDownload = true)
HOST_COLUMN -> directToSubject(context, id = link, subjectName = text, entrance = entrance)
HOST_QUESTION -> directToQuestionDetail(context, id = link, entrance = entrance, path = path)
HOST_ANSWER -> directToAnswerDetail(context, id = link, entrance = entrance, path = path)
HOST_WEB -> directToWebView(context, url = link, entrance = entrance)
HOST_DOWNLOAD -> directToDownloadManagerAndStartDownload(
context,
gameId = link,
packageName = text,
entrance = entrance
)
HOST_UPDATE -> directToDownloadManagerAndStartUpdate(
context,
gameId = link,
packageName = text,
entrance = entrance
)
HOST_LIBAO -> directToGiftDetail(context, giftId = link, entrance = entrance)
HOST_COMMUNITY -> directToCommunity(context, CommunityEntity(link, text!!))
}
}
@JvmStatic
fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String) {
directToLinkPage(context, linkEntity, entrance, path, null)
@ -261,7 +220,7 @@ object DirectUtils {
path
)
"web", "inurl", "web链接" -> {
HOST_WEB, HOST_WEB_INURL, HOST_WEB_AL -> {
when {
linkEntity.link!!.contains("v.douyin") && PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme") -> {
directDouyin(context, "1402577827140941")
@ -413,7 +372,7 @@ object DirectUtils {
"column_test" -> context.startActivity(
GameServerTestActivity.getIntent(
context, linkEntity.link
?: "", linkEntity.text ?: "", entrance
?: "", linkEntity.text ?: "", entrance, exposureEvent
)
)
@ -441,7 +400,7 @@ object DirectUtils {
//"h5_game_center" -> directLetoGameCenter(context)
"game_list" -> directToGameCollectionSquare(context, entrance, "", "", "")
"game_list" -> directToGameCollectionSquare(context, entrance, traceEvent = exposureEvent)
"game_list_detail" -> directToGameCollectionDetail(
context,
@ -466,6 +425,8 @@ object DirectUtils {
)
)
"qq_mini_game_column" -> directToQGameHome(context)
"" -> {
// do nothing
}
@ -755,11 +716,12 @@ object DirectUtils {
id: String,
subjectName: String? = "",
entrance: String? = null,
exposureEvent: ExposureEvent? = null
exposureEvent: ExposureEvent? = null,
isQQMiniGame: Boolean = false,
) {
if (id.isEmpty()) return
val bundle = Bundle()
val subjectData = SubjectData(subjectId = id, subjectName = subjectName, isOrder = false)
val subjectData = SubjectData(subjectId = id, subjectName = subjectName, isOrder = false, isQQMiniGame = isQQMiniGame)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subjectData)
@ -1871,8 +1833,11 @@ object DirectUtils {
* 跳转到游戏动态,请不要随意修改方法名
*/
@JvmStatic
fun directToConcernInfo(context: Context) {
context.startActivity(ConcernInfoActivity.getIntent(context));
fun directToConcernInfo(context: Context, entrance: String) {
context.startActivity(
(ARouter.getInstance().build(RouteConsts.provider.concernInfo)
.navigation() as? IConcernInfoProvider)?.getIntent(context, entrance)
)
}
/**
@ -1886,9 +1851,11 @@ object DirectUtils {
gameCollectionTitle: String = "",
gameCollectionId: String = "",
collectionName: String = "",
collectionId: String = ""
collectionId: String = "",
traceEvent: ExposureEvent? = null
) {
val bundle = Bundle()
val exposureSourceList = traceEvent?.source
bundle.putString(KEY_TO, GameCollectionSquareActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putString(KEY_FORUM_NAME, forumName)
@ -1896,6 +1863,11 @@ object DirectUtils {
bundle.putString(KEY_GAME_COLLECTION_ID, gameCollectionId)
bundle.putString(KEY_COLLECTION_ID, collectionId)
bundle.putString(KEY_COLLECTION_NAME, collectionName)
if (exposureSourceList is ArrayList) {
bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, exposureSourceList)
} else if (exposureSourceList != null) {
bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureSourceList))
}
jumpActivity(context, bundle)
}
@ -2057,4 +2029,66 @@ object DirectUtils {
platform = platform
)
}
@JvmStatic
fun directToQGameHome(context: Context) {
context.startActivity(QGameHomeWrapperActivity.getIntent(context))
}
@JvmStatic
fun directToQGameSearch(
context: Context,
hint: String,
sourceEntrance: String
) {
context.startActivity(QGameSearchActivity.getIntent(context, hint, sourceEntrance))
}
@SuppressLint("CheckResult")
@JvmStatic
fun directToQGameById(
activity: Activity,
qqGameId: String
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
ToastUtils.toast("该游戏仅支持安卓5.0及以上设备")
return
}
CheckLoginUtils.checkLogin(
activity, null, true, "QQ小游戏-秒开"
) {
val userToken = UserManager.getInstance().token
val userId = UserManager.getInstance().userId
val userName = UserManager.getInstance().userInfoEntity?.name ?: "unknown"
val qGameProvider = ARouter
.getInstance()
.build(RouteConsts.provider.qGame)
.navigation() as IQGameProvider<*>
qGameProvider.setLoginInfo(activity, userId, userName, userToken)
qGameProvider.launchGame(activity, qqGameId) { _, _ ->
RetrofitManager
.getInstance()
.newApi
.postQGamePlay(qqGameId, userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
QGameViewModel.notifyQGameSubjectUpdate() // 通知QQ小游戏首页列表刷新
},
{}
) // 秒玩记录上报
}
}
}
@JvmStatic
fun directToMessageCenter(defaultTabIndex: Int) {
ARouter.getInstance().build(RouteConsts.activity.messageWrapperActivity)
.withInt(BaseActivity_TabLayout.PAGE_INDEX, defaultTabIndex)
.navigation()
}
}

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import android.annotation.SuppressLint
import android.content.Context
import android.os.Message
import android.text.TextUtils
@ -7,6 +8,7 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.collection.ArrayMap
import androidx.recyclerview.widget.RecyclerView
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.chain.*
import com.gh.common.constant.Config
import com.gh.common.dialog.DeviceRemindDialog
@ -26,19 +28,24 @@ 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.constant.RouteConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IQGameProvider
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
import com.gh.vspace.VHelper
import com.lightgame.download.DownloadConfig
@ -237,6 +244,24 @@ object DownloadItemUtils {
}
return
}
if (gameEntity.isQQMiniGame()) {
val isQQMiniGameOffShelve = gameEntity.qqMiniGameAppStatus == 1 // QQ小游戏是否下架
if (isQQMiniGameOffShelve) {
downloadBtn.apply {
isClickable = false
text = context.getString(R.string.off_shelve)
buttonStyle = DownloadButton.ButtonStyle.NONE
}
} else {
downloadBtn.apply {
isClickable = true
setBackgroundResource(R.drawable.download_button_normal_style)
setTextColor(R.color.white.toColor(context))
text = context.getString(R.string.quick_play)
}
}
return
}
if (gameEntity.getApk().isEmpty() || gameEntity.downloadOffStatus != null) {
val h5LinkEntity = gameEntity.h5Link
val offStatus = gameEntity.downloadOffStatus
@ -275,11 +300,6 @@ object DownloadItemUtils {
downloadEntity = VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
}
// 还是找不到时,尝试从 gameEntity 里找已绑定的 downloadEntity
if (downloadEntity == null) {
downloadEntity = gameEntity.getEntryMap().getOrDefault(gameEntity.getUniquePlatform(), null)
}
if (downloadEntity != null) {
downloadBtn.apply {
when (downloadEntity.status) {
@ -366,15 +386,7 @@ object DownloadItemUtils {
briefStyle: String?,
isShowRecommendStar: Boolean = false
) {
val entryMap: ArrayMap<String, DownloadEntity> = gameEntity.getEntryMap()
val apkEntity = gameEntity.getApk()[0]
var downloadEntity: DownloadEntity? = null
if (entryMap.isNotEmpty()) {
downloadEntity = entryMap[apkEntity.getPlatform()]
}
if (downloadEntity == null) {
downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
}
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
if (downloadEntity != null) {
if (downloadEntity.isSimulatorGame()) {
if (downloadEntity.status != DownloadStatus.done) {
@ -740,6 +752,15 @@ object DownloadItemUtils {
}
return
}
if (gameEntity.isQQMiniGame()) {
downloadBtn.setOnClickListener {
NewFlatLogUtils.logQGameClick(gameEntity.qqMiniGameAppId, gameEntity.name)
GlobalActivityManager.currentActivity?.let { activity ->
DirectUtils.directToQGameById(activity, gameEntity.qqMiniGameAppId)
}
}
return
}
if (gameEntity.getApk().size == 0 && gameEntity.h5Link != null) {
downloadBtn.setOnClickListener {
allStateClickCallback?.onCallback()
@ -827,6 +848,7 @@ object DownloadItemUtils {
addHandler(DownloadDialogHelperHandler())
addHandler(CertificationHandler())
addHandler(OverseaDownloadHandler())
addHandler(LandPageAddressHandler())
addHandler(CheckDownloadHandler())
}
.setProcessEndCallback {
@ -845,6 +867,7 @@ object DownloadItemUtils {
addHandler(DownloadDialogHelperHandler())
addHandler(CertificationHandler())
addHandler(VersionNumberHandler())
addHandler(LandPageAddressHandler())
addHandler(OverseaDownloadHandler())
addHandler(CheckDownloadHandler())
}
@ -862,6 +885,7 @@ object DownloadItemUtils {
addHandler(DownloadDialogHelperHandler())
addHandler(CertificationHandler())
addHandler(VersionNumberHandler())
addHandler(LandPageAddressHandler())
addHandler(OverseaDownloadHandler())
addHandler(CheckStoragePermissionHandler())
addHandler(ValidateVSpaceHandler())
@ -943,16 +967,24 @@ object DownloadItemUtils {
VHelper.updateOrReDownload(gameEntity)
return
}
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk) {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name
) { isSubscribe: Boolean ->
update(context, gameEntity, entrance, location, isSubscribe, traceEvent)
ChainBuilder()
.apply {
addHandler(LandPageAddressHandler())
}.setProcessEndCallback {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk) {
DialogUtils.checkDownload(
context,
apk.size,
gameEntity.id,
gameEntity.name
) { isSubscribe: Boolean ->
update(context, gameEntity, entrance, location, isSubscribe, traceEvent)
}
}
}
}
.buildHandlerChain()
?.handleRequest(context, gameEntity)
} else {
var downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)

View File

@ -0,0 +1,18 @@
package com.gh.common.util
import com.gh.gamecenter.db.GameTrendsDao
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.message.MessageUnreadRepository
import com.halo.assistant.HaloApp
object GameTrendsHelper {
private val mGameTrendsDao = GameTrendsDao(HaloApp.getInstance().application)
fun updateReadPostTime() {
mGameTrendsDao.findGameTrendsInfo(UserManager.getInstance().userId)?.let { trendsInfo ->
trendsInfo.readPostTime = System.currentTimeMillis()
mGameTrendsDao.add(trendsInfo)
MessageUnreadRepository.loadMessageUnreadTotal(true)
}
}
}

View File

@ -22,8 +22,8 @@ import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.LibaoEntity;
import com.gh.gamecenter.feature.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.MeEntity;
import com.gh.gamecenter.common.entity.NotificationUgc;
import com.gh.gamecenter.feature.entity.UserDataLibaoEntity;
@ -46,7 +46,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;

View File

@ -986,7 +986,7 @@ public class LogUtils {
LoghubUtils.log(object, LOG_STORE_EVENT, false);
}
public static void logHomeTopTabClick(String tabName, String linkType, String linkTitle, String linkId, int sequence) {
public static void logHomeTopTabClick(String tabName, String linkType, String linkTitle, String linkId, int sequence, String entrance) {
JSONObject object = new JSONObject();
try {
object.put(KEY_EVENT, "top_tab_click");
@ -995,6 +995,7 @@ public class LogUtils {
object.put("link_id", linkId);
object.put("link_text", linkTitle);
object.put("sequence", sequence);
object.put("entrance", entrance);
object.put(KEY_META, getMetaObject());
object.put(KEY_TIMESTAMP, System.currentTimeMillis() / 1000);
} catch (JSONException e) {

View File

@ -2340,4 +2340,74 @@ object NewFlatLogUtils {
}
log(json)
}
// 游戏详情-求加速点击事件
fun logGameDetailClickForAccelerate(gameId: String, gameName: String) {
val json = json {
KEY_EVENT to "game_detail_click_for_accelerate"
"game_name" to gameName
"game_id" to gameId
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏详情-求版本投票事件
fun logGameDetailClickForVersionVote(gameId: String, gameName: String, button: String) {
val json = json {
KEY_EVENT to "game_detail_click_for_version_vote"
"game_name" to gameName
"game_id" to gameId
"button" to button
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏详情-求版本取消投票事件
fun logGameDetailCancelForVersionVote(gameId: String, gameName: String, button: String) {
val json = json {
KEY_EVENT to "game_detail_cancel_for_version_vote"
"game_name" to gameName
"game_id" to gameId
"button" to button
parseAndPutMeta().invoke(this)
}
log(json)
}
// 消息中心-插件版本提醒弹窗点击事件
@JvmStatic
fun logMessageInformClickPluginVersion(gameId: String, gameName: String) {
val json = json {
KEY_EVENT to "message_inform_click_plugin_version"
"game_name" to gameName
"game_id" to gameId
parseAndPutMeta().invoke(this)
}
log(json)
}
// 游戏动态关注列表取消关注事件 / 游戏动态关注列表查看详情事件
@JvmStatic
fun logGameActivityConcern(event: String, gameId: String, gameName: String?) {
val json = json {
KEY_EVENT to event
KEY_GAME_ID to gameId
KEY_GAME_NAME to gameName
parseAndPutMeta().invoke(this)
}
log(json)
}
@JvmStatic
fun logQGameClick(qqGameId: String, qqGameName: String?) {
val json = json {
KEY_EVENT to "qq_game_click"
"qq_game_id" to qqGameId
"qq_game_name" to qqGameName ?: ""
parseAndPutMeta().invoke(this)
}
log(json)
}
}

View File

@ -2,7 +2,7 @@ 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.GameInstall
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.packagehelper.PackageRepository

View File

@ -7,12 +7,14 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.content.pm.Signature;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@ -29,6 +31,7 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.PackageFlavorHelper;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.core.utils.MD5Utils;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.feature.entity.ApkEntity;
@ -74,6 +77,9 @@ public class PackageUtils {
private static final String TAG = "PackageUtils";
// 设备是否支持禁用获取已安装应用列表。-1 代表支持情况未知0 代表不支持, 1 代表支持
private static int mIsSupportGetInstalledListPermission = -1;
public static String getInstallPackageInfoSourceDir(String packageName) {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
@ -137,6 +143,9 @@ public class PackageUtils {
updateEntity.setSignature(apkEntity.getSignature());
updateEntity.setCategory(gameEntity.getCategory());
updateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName()));
if (gameEntity.isLandPageAddressDialog()) {
updateEntity.setLandPageAddressDialog(gameEntity.getLandPageAddressDialog());
}
updateList.add(updateEntity);
}
}
@ -211,6 +220,9 @@ public class PackageUtils {
updateEntity.setSignature(apkEntity.getSignature());
updateEntity.setCategory(gameEntity.getCategory());
updateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName()));
if (gameEntity.isLandPageAddressDialog()) {
updateEntity.setLandPageAddressDialog(gameEntity.getLandPageAddressDialog());
}
updateList.add(updateEntity);
}
}
@ -960,18 +972,78 @@ public class PackageUtils {
return new ArrayList<>(mInstalledPackageList);
}
Utils.log(TAG, "调用系统 API 获取新的已安装应用列表");
// 是否需要调用系统 API 获取新的已安装应用列表
boolean shouldGetNewInstalledPackagedList = false;
// 当前设备是否支持限制获取已安装应用列表的功能
if (isSupportGetInstalledAppsPermission(context)) {
Utils.log(TAG, "当前设备支持限制获取已安装应用列表的功能");
// 当前设备是否支持禁用了获取已安装应用列表
if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
Utils.log(TAG, "当前设备没有限制获取已安装应用列表的功能");
shouldGetNewInstalledPackagedList = true;
} else {
Utils.log(TAG, "当前设备已限制获取已安装应用列表的功能");
}
} else {
Utils.log(TAG, "当前设备不支持限制获取已安装应用列表的功能");
shouldGetNewInstalledPackagedList = true;
}
if (shouldGetNewInstalledPackagedList) {
mLastInstalledPackageListTime = System.currentTimeMillis();
mInstalledPackageList = getInstalledPackagesInternal(context, flags);
}
if (mInstalledPackageList == null) {
mInstalledPackageList = new ArrayList<>();
}
mLastInstalledPackageListTime = System.currentTimeMillis();
mInstalledPackageList = getInstalledPackagesInternal(context, flags);
return mInstalledPackageList;
}
public static boolean isSupportGetInstalledAppsPermission(Context context) {
// 若存在缓存,直接返回缓存结果。为 0 代表不支持,为 1 代表支持
if (mIsSupportGetInstalledListPermission != -1) {
return mIsSupportGetInstalledListPermission != 0;
}
try {
// 根据官方提供的方法来判定是否支持限制获取已安装应用列表
int flag = Settings.Secure.getInt(context.getContentResolver(), "oem_installed_apps_runtime_permission_enable", 0);
if (flag == 1) {
mIsSupportGetInstalledListPermission = 1;
return true;
}
// 部分未升级的手机没有上面配置项,有定义下面危险权限也认为是支持设备软件列表管控
PackageManager packageManager = context.getPackageManager();
PermissionInfo permissionInfo = packageManager.getPermissionInfo("com.android.permission.GET_INSTALLED_APPS", 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS) {
mIsSupportGetInstalledListPermission = 1;
return true;
} else {
mIsSupportGetInstalledListPermission = 0;
return false;
}
} else {
mIsSupportGetInstalledListPermission = 0;
return false;
}
} catch (NameNotFoundException e) {
mIsSupportGetInstalledListPermission = 0;
return false;
}
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-tÏo-get-a-list-of-applications-installed/30062632#30062632
*/
private static List<PackageInfo> getInstalledPackagesInternal(Context context, int flags) {
Utils.log(TAG, "调用系统 API 获取已安装应用列表");
final PackageManager pm = context.getPackageManager();
try {
return pm.getInstalledPackages(flags);

View File

@ -7,7 +7,7 @@ import android.text.TextUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import com.walkud.rom.checker.RomIdentifier;

View File

@ -95,21 +95,19 @@ object ReservationHelper {
NewLogUtils.logReserveGameSuccess(wechatConfig)
if (bind && follow && notice) {
NewLogUtils.logReserveWechatSuccessPopShow()
DialogUtils.showReserveSuccessDialog(context)
DialogUtils.showReserveOrVoteSuccessDialog(context, true)
} else {
NewLogUtils.logReserveWechatRemindPopShow(wechatConfig)
SensorsBridge.trackEvent("AppointmenWechatRemindDialogShow")
DialogUtils.showReserveSuccess2WechatBindDialog(context, object : ConfirmListener {
override fun onConfirm() {
NewLogUtils.logReserveWechatRemindPopClick(wechatConfig, "开启微信提醒")
SensorsBridge.trackEvent("AppointmenWechatRemindDialogClick")
context.startActivity(WebActivity.getBindWechatIntent(context))
SensorsBridge.trackEvent(
"AppointmenWechatRemindConfigPageShow",
"source_entrance",
"设置微信提醒弹窗"
)
}
DialogUtils.showReserveOrVoteSuccess2WechatBindDialog(context, true, {
NewLogUtils.logReserveWechatRemindPopClick(wechatConfig, "开启微信提醒")
SensorsBridge.trackEvent("AppointmenWechatRemindDialogClick")
context.startActivity(WebActivity.getBindWechatIntent(context))
SensorsBridge.trackEvent(
"AppointmenWechatRemindConfigPageShow",
"source_entrance",
"设置微信提醒弹窗"
)
}, object : CancelListener {
override fun onCancel() {
NewLogUtils.logReserveWechatRemindPopClick(wechatConfig, "关闭弹窗")

View File

@ -270,7 +270,11 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
pendingSessionInfo.updateStatus(XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
} else if (sessionInfo.progress <= 0.8F) {
AppExecutor.ioExecutor.execute {
installer.abandonSession(sessionInfo.sessionId)
try {
installer.abandonSession(sessionInfo.sessionId)
} catch (_: Exception) {
// 有概率抛SecurityException这里只要直接catch不做处理即可
}
}
pendingSessionInfo.updateStatus(XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
}

View File

@ -2,7 +2,7 @@ package com.gh.download
import android.annotation.SuppressLint
import android.text.TextUtils
import com.gh.common.util.ConcernUtils
import com.gh.gamecenter.feature.utils.ConcernUtils
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageUtils

View File

@ -10,7 +10,7 @@ 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.common.entity.LinkEntity;
import com.gh.gamecenter.entity.MessageEntity;
import com.gh.gamecenter.feature.entity.MessageEntity;
import com.gh.gamecenter.qa.comment.CommentActivity;
import com.gh.gamecenter.qa.comment.NewCommentConversationFragment;
import com.halo.assistant.fragment.comment.CommentDetailFragment;

View File

@ -1,32 +0,0 @@
package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.info.ConcernFragment;
/**
* Created by khy on 10/04/18.
*/
public class ConcernInfoActivity extends ToolBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
public static Intent getIntent(Context context) {
return getTargetIntent(context, ConcernInfoActivity.class, ConcernFragment.class);
}
@Override
protected void onDarkModeChanged() {
super.onDarkModeChanged();
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
}

View File

@ -34,6 +34,7 @@ import androidx.transition.*
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import com.alibaba.android.arouter.facade.annotation.Route
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipeline
@ -41,6 +42,7 @@ import com.facebook.imagepipeline.request.ImageRequest
import com.gh.common.constant.Config
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
@ -71,6 +73,7 @@ import kotlin.math.roundToInt
* @author 黄壮华
*
*/
@Route(path = RouteConsts.activity.imageViewerActivity)
class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
private var mScale = 0F
@ -150,8 +153,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
mUrlList = ArrayList()
mUrlList?.add(base64Image)
} else {
mUrlList = it.getStringArrayList(KEY_URL_LIST) ?: arrayListOf()
mInitialPosition = it.getInt(KEY_CURRENT, 0)
mUrlList = it.getStringArrayList(EntranceConsts.KEY_URL_LIST) ?: arrayListOf()
mInitialPosition = it.getInt(EntranceConsts.KEY_CURRENT, 0)
}
mShowSaveBtn = it.getBoolean(KEY_SHOW_SAVE)
mUseEnterAndExitAnimation = it.getBoolean(KEY_USE_ENTER_AND_EXIT_ANIMATION)
@ -930,8 +933,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
var base64Image: String = ""
private const val KEY_BASE64 = "base64"
private const val KEY_URL_LIST = "urls"
private const val KEY_CURRENT = "current"
private const val KEY_SHOW_SAVE = "showSave"
private const val KEY_USE_ENTER_AND_EXIT_ANIMATION = "use_enter_and_exit_animation"
private const val KEY_IS_FROM_IMAGE_CONTAINER_VIEW = "is_from_image_container_view"
@ -995,8 +996,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
isFromICV: Boolean = false
): Intent {
val intent = Intent(context, ImageViewerActivity::class.java)
intent.putExtra(KEY_URL_LIST, list)
intent.putExtra(KEY_CURRENT, position)
intent.putExtra(EntranceConsts.KEY_URL_LIST, list)
intent.putExtra(EntranceConsts.KEY_CURRENT, position)
intent.putExtra(KEY_SHOW_SAVE, isShowSaveBtn)
intent.putExtra(AnswerEntity::class.java.name, answerEntity)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)

View File

@ -18,9 +18,11 @@ import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.ethanhua.skeleton.Skeleton;
import com.ethanhua.skeleton.ViewSkeletonScreen;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.feature.utils.ApkActiveUtils;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DetailDownloadUtils;
@ -38,8 +40,8 @@ import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.view.VerticalItemDecoration;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.LibaoEntity;
import com.gh.gamecenter.feature.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.MeEntity;
import com.gh.gamecenter.feature.entity.UserDataLibaoEntity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
@ -70,6 +72,7 @@ import retrofit2.HttpException;
/**
* Created by khy on 2016/12/13.
*/
@Route(path = RouteConsts.activity.libaoDetailActivity)
public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailAdapter.OnCodeScrollListener,
OnRequestCallBackListener {

View File

@ -21,7 +21,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
@ -33,6 +32,7 @@ import android.text.Html;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
@ -43,9 +43,8 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import com.alibaba.android.arouter.launcher.ARouter;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.DefaultUrlHandler;
import com.gh.ad.AdDelegateHelper;
import com.gh.common.constant.Config;
import com.gh.common.exposure.ExposureManager;
import com.gh.common.filter.RegionSettingHelper;
@ -77,7 +76,6 @@ import com.gh.gamecenter.common.base.fragment.ToolbarFragment;
import com.gh.gamecenter.common.constant.CommonConsts;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.entity.NotificationUgc;
import com.gh.gamecenter.common.entity.SuggestType;
@ -92,7 +90,6 @@ import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.gamecenter.common.utils.NotificationHelper;
import com.gh.gamecenter.common.utils.ShareUtils;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.provider.IStartUpAdProvider;
import com.gh.gamecenter.core.utils.ClassUtils;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.GsonUtils;
@ -102,8 +99,6 @@ import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.core.utils.TimeUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.download.DownloadFragment;
import com.gh.gamecenter.entity.InnerMetaInfoEntity;
import com.gh.gamecenter.entity.StartupAdEntity;
import com.gh.gamecenter.eventbus.EBSkip;
import com.gh.gamecenter.feature.entity.GameEntity;
@ -141,22 +136,16 @@ import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -174,7 +163,7 @@ public class MainActivity extends BaseActivity {
public static final String SWITCH_TO_COMMUNITY = "switch_to_community";
public static final String SWITCH_TO_VIDEO = "switch_to_video";
public static final String SHOW_AD = "show_ad";
private static final int COUNTDOWN_AD = 100;
public static final int COUNTDOWN_AD = 100;
private static final int COUNTDOWN_MAX_COUNT = 3;
private int countdownCount = 0;
@ -190,13 +179,11 @@ public class MainActivity extends BaseActivity {
public static boolean isNewFirstLaunch;
private final Handler handler = new Handler();
public boolean showAd = false; // 是否显示广告
private IStartUpAdProvider mStartUpAdProvider;
private boolean mShouldShowAd = false; // 是否显示广告
@Override
protected void onCreate(Bundle savedInstanceState) {
showAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null;
mShouldShowAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null;
HaloApp.getInstance().isAlreadyUpAndRunning = true;
@ -230,7 +217,6 @@ public class MainActivity extends BaseActivity {
}
}
}, 2000L);
getPluginUpdate();
sp.edit().putBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), false).apply();
// 记录曾安装过的版本 + 渠道
@ -284,8 +270,6 @@ public class MainActivity extends BaseActivity {
}
}
// checkTinkerPath(); // 看情况是否需要显示补丁弹窗
// 必须放在这里,否则会导致获取 baseActivity 不是本应用包名
DownloadManager.getInstance().initDownloadService();
@ -302,17 +286,16 @@ public class MainActivity extends BaseActivity {
doSkip();
}
// debug 模式下的快速跳转页面
if (BuildConfig.DEBUG) {
handler.postDelayed(() -> {
EntranceUtils.jumpShortcut(this);
}, 500);
handler.postDelayed(() -> EntranceUtils.jumpShortcut(this), 500);
}
if (showAd) {
observeStartUp();
if (mShouldShowAd) {
showAd();
} else {
hideStartUp();
hideStartUpAd();
hideTextAd();
hideSplashAd();
}
// 默认配置为空时重试
@ -475,7 +458,7 @@ public class MainActivity extends BaseActivity {
protected void onDestroy() {
super.onDestroy();
if (mStartUpAdProvider != null) mStartUpAdProvider.cancelStartUpAd(this);
AdDelegateHelper.INSTANCE.cancelSplashAd(this);
handler.removeCallbacksAndMessages(null);
releaseExoSourceCache();
@ -499,87 +482,58 @@ public class MainActivity extends BaseActivity {
}
}
private void observeStartUp() {
if (!showAd) {
hideStartUp();
hideStartUpAd();
/**
* 显示广告 (包括文本广告和开屏广告)
*/
private void showAd() {
if (!mShouldShowAd) {
hideTextAd();
hideSplashAd();
return;
}
final StartupAdEntity startUp = AdHelper.getStartUp();
if (startUp != null) {
showStartUp(startUp);
final StartupAdEntity textAd = AdHelper.getStartUp();
if (textAd != null) {
showTextAd(textAd);
AppExecutor.getUiExecutor().executeWithDelay(() -> {
hideStartUp();
initStartUpAd();
hideTextAd();
showSplashAd();
}, 2000);
} else {
initStartUpAd();
showSplashAd();
}
}
private void initStartUpAd() {
mStartUpAdProvider = (IStartUpAdProvider) ARouter.getInstance().build(RouteConsts.provider.adSdk).navigation();
if (mStartUpAdProvider != null && mStartUpAdProvider.shouldEnableSDK(HaloApp.getInstance().getChannel())) {
initSDKStartUpAd();
} else {
observeStartUpAd();
}
}
/**
* 显示开屏广告
*/
private void showSplashAd() {
if (AdDelegateHelper.INSTANCE.shouldShowStartUpAd()) {
ViewGroup startAdContainer = findViewById(R.id.startAdContainer);
ViewGroup sdkStartAdContainer = findViewById(R.id.sdkStartAdContainer);
FrameLayout adsFl = findViewById(R.id.adsFl);
private void observeStartUpAd() {
final StartupAdEntity startUpAd = AdHelper.getStartUpAd();
int screenWidthInPx = DisplayUtils.getScreenWidth(this);
int screenHeightInPx = DisplayUtils.getScreenHeight(this) + DisplayUtils.getStatusBarHeight(this.getResources());
float screenWidthInDp = DisplayUtils.px2dip(this, screenWidthInPx);
float screenHeightInDp = DisplayUtils.px2dip(this, screenHeightInPx);
if (startUpAd != null && !TextUtils.isEmpty(startUpAd.getImg())) {
// 根据接口返回的广告时间,判断该图片广告是否还有必要显示
boolean isAdValid = false;
if (startUpAd.getTime() != null) {
long currentTimeInSecond = System.currentTimeMillis() / 1000;
if (currentTimeInSecond > startUpAd.getTime().getStart()
&& currentTimeInSecond < startUpAd.getTime().getEnd()) {
isAdValid = true;
}
} else {
// 接口没有返回开始和结束时间时,默认有效
isAdValid = true;
}
// 图片广告无效,跳过
if (!isAdValid) {
hideStartUpAd();
return;
}
final String showedTodayTimestamp = SPUtils.getString(Constants.SP_STARTUP_AD_TIMESTAMP, "");
final String rule = startUpAd.getRule();
switch (rule) {
case "each":
showStartUpAd(startUpAd);
break;
case "once":
if (TextUtils.isEmpty(showedTodayTimestamp)
|| !showedTodayTimestamp.contains(startUpAd.getId())) {
showStartUpAd(startUpAd);
} else {
hideStartUpAd();
AdDelegateHelper.requestSplashAd(
this,
screenWidthInPx,
screenHeightInPx,
screenWidthInDp,
screenHeightInDp,
startAdContainer,
sdkStartAdContainer,
adsFl,
(BaseHandler) mBaseHandler,
() -> {
hideSplashAd();
return null;
}
break;
case "everyday":
final String today = TimeUtils.getToday();
if (TextUtils.isEmpty(showedTodayTimestamp)
|| !showedTodayTimestamp.contains(today)
|| !showedTodayTimestamp.contains(startUpAd.getId())) {
showStartUpAd(startUpAd);
} else {
hideStartUpAd();
}
break;
default:
hideStartUpAd();
break;
}
SPUtils.setString(Constants.SP_STARTUP_AD_TIMESTAMP, startUpAd.getId() + TimeUtils.getToday());
);
} else {
hideStartUpAd();
hideSplashAd();
}
}
@ -591,14 +545,17 @@ public class MainActivity extends BaseActivity {
TextView jumpBtn = findViewById(R.id.jumpBtn);
jumpBtn.setText(String.format(Locale.CHINA, "跳过 %d", COUNTDOWN_MAX_COUNT - countdownCount));
if (COUNTDOWN_MAX_COUNT < countdownCount) {
hideStartUpAd();
hideSplashAd();
} else {
mBaseHandler.sendEmptyMessageDelayed(COUNTDOWN_AD, 1000);
}
}
}
private void hideStartUp() {
/**
* 隐藏开屏文案
*/
private void hideTextAd() {
View maskContainer = findViewById(R.id.maskContainer);
if (maskContainer != null) {
maskContainer.setVisibility(View.GONE);
@ -606,8 +563,11 @@ public class MainActivity extends BaseActivity {
}
}
private void hideStartUpAd() {
showAd = false;
/**
* 隐藏开屏广告
*/
private void hideSplashAd() {
mShouldShowAd = false;
getIntent().putExtra(SHOW_AD, false);
View startAdContainer = findViewById(R.id.startAdContainer);
if (startAdContainer != null) {
@ -618,7 +578,7 @@ public class MainActivity extends BaseActivity {
if (startSdkAdContainer != null) {
startSdkAdContainer.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(startSdkAdContainer);
if (mStartUpAdProvider != null) mStartUpAdProvider.cancelStartUpAd(this);
AdDelegateHelper.INSTANCE.cancelSplashAd(this);
}
checkDialog();
}
@ -634,62 +594,10 @@ public class MainActivity extends BaseActivity {
});
}
private void showStartUpAd(StartupAdEntity ad) {
View startAdContainer = findViewById(R.id.startAdContainer);
View jumpBtn = findViewById(R.id.jumpBtn);
TextView jumpDetailBtn = findViewById(R.id.jumpDetailBtn);
SimpleDraweeView adImage = findViewById(R.id.adImage);
startAdContainer.setVisibility(View.VISIBLE);
jumpDetailBtn.setText(ad.getDesc());
ExtensionsKt.setDrawableEnd(jumpDetailBtn, AppCompatResources.getDrawable(this, R.drawable.ic_startup_ad_arrow), null, null);
ImageUtils.display(adImage, ad.getImg());
startAdContainer.setOnClickListener(v -> {
// do nothing 只是为了点击拦截事件,避免传递到下面的页面
});
jumpBtn.setOnClickListener(v -> {
mBaseHandler.removeMessages(COUNTDOWN_AD);
hideStartUpAd();
LinkEntity linkEntity = ad.getJump();
NewFlatLogUtils.logOpenScreenAdSkip(
ad.getId(),
linkEntity.getText() != null ? linkEntity.getText() : "",
linkEntity.getType() != null ? linkEntity.getType() : "",
linkEntity.getLink() != null ? linkEntity.getLink() : ""
);
});
List<ExposureSource> sources = new ArrayList<>();
sources.add(new ExposureSource("开屏广告", ad.getId()));
final ExposureEvent event = ExposureEvent.createEvent(null, sources, null, ExposureType.EXPOSURE);
ExposureManager.INSTANCE.log(event);
if (ad.getButton()) {
jumpDetailBtn.setOnClickListener(v -> {
DirectUtils.directToLinkPage(this, ad.getJump(), "(启动广告)", "", event);
v.postDelayed(() -> {
mBaseHandler.removeMessages(COUNTDOWN_AD);
hideStartUpAd();
}, 1000);
});
jumpDetailBtn.setVisibility(View.VISIBLE);
LogUtils.logStartAd("watch_start_ads", ad);
} else {
LogUtils.logStartAd("start_ads", ad);
}
mBaseHandler.sendEmptyMessageDelayed(COUNTDOWN_AD, 1000);
}
private void initSDKStartUpAd() {
View startAdContainer = findViewById(R.id.sdkStartAdContainer);
startAdContainer.setVisibility(View.VISIBLE);
FrameLayout adsFl = findViewById(R.id.adsFl);
if (mStartUpAdProvider != null) {
mStartUpAdProvider.initStartUpAd(startAdContainer, adsFl, showAd, () -> {
hideStartUpAd();
return null;
});
}
}
private void showStartUp(StartupAdEntity ad) {
/**
* 显示文本广告
*/
private void showTextAd(StartupAdEntity ad) {
TextView adContentTv = findViewById(R.id.adContentTv);
View containerView = findViewById(R.id.maskContainer);
containerView.setVisibility(View.VISIBLE);
@ -697,7 +605,7 @@ public class MainActivity extends BaseActivity {
containerView.setElevation(500F);
}
containerView.setOnClickListener(v -> {
// do nothing 只是为了点击拦截事件,避免传递到下面的页面
// 拦截点击事件,避免传递到下面的页面
});
adContentTv.setText(ad.getDesc());
adContentTv.setVisibility(View.VISIBLE);
@ -747,7 +655,6 @@ public class MainActivity extends BaseActivity {
} else {
Intent skipIntent = new Intent(MainActivity.this, clazz);
skipIntent.putExtras(bundle);
// startActivity(skipIntent);
AvoidOnResultManager.Companion.getInstance(this)
.startForResult(skipIntent, (resultCode, data) -> {
Bundle nextToBundle = getIntent().getBundleExtra(KEY_NEXT_TO);
@ -869,7 +776,7 @@ public class MainActivity extends BaseActivity {
@Override
public Boolean invoke(Integer code) {
if (code == 404001) {
if (showAd) {
if (mShouldShowAd) {
AppExecutor.getUiExecutor().executeWithDelay(() -> {
toast("抱歉,暂未找到相关内容");
}, 1000);
@ -980,7 +887,7 @@ public class MainActivity extends BaseActivity {
@Override
protected int getLayoutId() {
if (showAd) {
if (mShouldShowAd) {
return R.layout.activity_main;
} else {
return R.layout.layout_wrapper_activity;
@ -1003,71 +910,6 @@ public class MainActivity extends BaseActivity {
}
}
// 获取META-INF中的plugin_update 文件判断是否从游戏插件中下载的app是则获取游戏id启动游戏更新下载该游戏
private void getPluginUpdate() {
AppExecutor.getIoExecutor().execute(() -> {
ApplicationInfo appinfo = getApplicationInfo();
String sourceDir = appinfo.sourceDir;
ZipFile zipfile = null;
try {
zipfile = new ZipFile(sourceDir);
Enumeration<?> entries = zipfile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = ((ZipEntry) entries.nextElement());
String entryName = entry.getName();
if (entryName.contains("gh_assist")) {
String packageName = entryName.substring(entryName.lastIndexOf("_") + 1);
startActivity(DownloadManagerActivity.getDownloadMangerIntent(MainActivity.this,
packageName, DownloadFragment.INDEX_UPDATE, "(游戏插件)"));
break;
} else if (entryName.contains("halo_skip.json")) {
InputStream in = zipfile.getInputStream(entry);
if (in != null) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
InnerMetaInfoEntity info = GsonUtils.getGson().fromJson(reader, InnerMetaInfoEntity.class);
if (info != null) {
if (EntranceConsts.HOST_COMMUNITY.equals(info.getType())) {
runOnUiThread(() -> mMainWrapperFragment.setCurrentItem(MainWrapperFragment.INDEX_BBS));
} else {
DirectUtils.directToSpecificPage(this,
info.getType(),
info.getLink(),
info.getText(),
EntranceConsts.KEY_PLUGIN,
"特定包启动跳转");
}
}
}
} else if (entryName.contains("halo_skip.dat")) {
InputStream in = zipfile.getInputStream(entry);
if (in != null) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String content = "";
for (String line; (line = reader.readLine()) != null; content += line) ;
if (!TextUtils.isEmpty(content)) {
DefaultUrlHandler.interceptUrl(this, content, "(特定包启动跳转)");
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (zipfile != null) {
try {
zipfile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
// 连接上网络事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBNetworkState busNetworkState) {

View File

@ -9,8 +9,8 @@ import android.view.ViewGroup;
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.entity.CommentEntity;
import com.gh.gamecenter.entity.ConcernEntity;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.ConcernEntity;
import com.gh.gamecenter.message.MessageDetailFragment;
import com.halo.assistant.HaloApp;

View File

@ -1,37 +0,0 @@
package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.message.MessageNormalFragment;
/**
* Created by khy on 10/04/18.
*/
public class MessageInviteActivity extends ToolBarActivity {
public static Intent getIntent(Context context, String messageType, String outerInfo, String entrance) {
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_MESSAGE_TYPE, messageType);
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_OUTER_INFO, outerInfo);
return getTargetIntent(context, MessageInviteActivity.class, MessageNormalFragment.class, bundle);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
@Override
protected void onDarkModeChanged() {
super.onDarkModeChanged();
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
}

View File

@ -1,40 +0,0 @@
package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.message.KeFuFragment;
/**
* Created by khy on 10/04/18.
*/
public class MessageKeFuActivity extends ToolBarActivity {
@Override
protected Intent provideNormalIntent() {
return getTargetIntent(this, MessageKeFuActivity.class, KeFuFragment.class);
}
public static Intent getIntent(Context context, String entrance) {
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
return getTargetIntent(context, MessageKeFuActivity.class, KeFuFragment.class, bundle);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
@Override
protected void onDarkModeChanged() {
super.onDarkModeChanged();
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
}

View File

@ -1,37 +0,0 @@
package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.message.MessageNormalFragment;
/**
* Created by khy on 10/04/18.
*/
public class MessageVoteActivity extends ToolBarActivity {
public static Intent getIntent(Context context, String messageType, String outerInfo, String entrance) {
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_MESSAGE_TYPE, messageType);
bundle.putString(EntranceConsts.KEY_OUTER_INFO, outerInfo);
return getTargetIntent(context, MessageVoteActivity.class, MessageNormalFragment.class, bundle);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
@Override
protected void onDarkModeChanged() {
super.onDarkModeChanged();
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
}
}

View File

@ -25,6 +25,7 @@ import androidx.core.content.ContextCompat;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.ethanhua.skeleton.Skeleton;
import com.ethanhua.skeleton.ViewSkeletonScreen;
import com.gh.base.DownloadToolbarActivity;
@ -40,6 +41,7 @@ import com.gh.gamecenter.adapter.viewholder.DetailViewHolder;
import com.gh.gamecenter.common.callback.OnRequestCallBackListener;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.eventbus.EBNetworkState;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.retrofit.Response;
@ -51,9 +53,9 @@ import com.gh.gamecenter.core.utils.ClickUtils;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.entity.NewsDetailEntity;
import com.gh.gamecenter.eventbus.EBConcernChanged;
import com.gh.gamecenter.eventbus.EBAddComment;
import com.gh.gamecenter.eventbus.EBDeleteComment;
import com.gh.gamecenter.feature.eventbus.EBConcernChanged;
import com.gh.gamecenter.feature.eventbus.EBAddComment;
import com.gh.gamecenter.feature.eventbus.EBDeleteComment;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.feature.entity.GameEntity;
@ -83,6 +85,7 @@ import retrofit2.HttpException;
*
* @author 黄壮华
*/
@Route(path = RouteConsts.activity.newsDetailActivity)
public class NewsDetailActivity extends DownloadToolbarActivity implements OnClickListener, OnRequestCallBackListener {
RecyclerView mDetailRv;

View File

@ -18,12 +18,12 @@ import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.util.MessageShareUtils;
import com.gh.common.util.QRCodeUtils;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.common.util.MessageShareUtils;
import com.gh.common.util.QRCodeUtils;
import com.gh.gamecenter.entity.ConcernEntity;
import com.gh.gamecenter.feature.entity.ConcernEntity;
import java.io.File;

View File

@ -32,7 +32,7 @@ import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.common.util.MessageShareUtils;
import com.gh.common.util.QRCodeUtils;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.entity.ConcernEntity;
import com.gh.gamecenter.feature.entity.ConcernEntity;
import com.gh.gamecenter.common.retrofit.ObservableUtil;
import java.io.File;

View File

@ -16,6 +16,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECT
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INVOKE_ONLY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_LIBAO;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GROUP;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_QUN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QUESTION;
@ -49,19 +50,25 @@ import android.util.Base64;
import androidx.annotation.Nullable;
import com.alibaba.android.arouter.launcher.ARouter;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.DownloadItemUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.entity.CommunityEntity;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.entity.SimpleGameEntity;
import com.gh.gamecenter.core.provider.IQGameProvider;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.VideoLinkEntity;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
import com.gh.vspace.shortcut.OnCreateShortcutResult;
@ -72,6 +79,14 @@ import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Utils;
import com.muugi.shortcut.core.Executor;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.function.Function;
import kotlin.Unit;
import kotlin.jvm.functions.Function2;
/**
* Created by LGT on 2016/11/16.
* 链接跳转用
@ -123,7 +138,7 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER, null);
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER, null, false);
break;
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
@ -403,7 +418,15 @@ 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, "", "", "", "", "", null);
break;
case HOST_QQ_GAME:
String extJson = uri.getQueryParameter("ext");
try {
JSONObject extJsonObject = new JSONObject(extJson);
String qqGameId = extJsonObject.optString("aid");
DirectUtils.directToQGameById(this, qqGameId);
} catch (JSONException ignored) {}
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页

View File

@ -19,6 +19,7 @@ import androidx.viewpager.widget.ViewPager
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.g00fy2.versioncompare.Version
import com.gh.ad.AdDelegateHelper
import com.gh.common.dialog.NewPrivacyPolicyDialogFragment
import com.gh.common.util.*
import com.gh.common.util.GameSubstituteRepositoryHelper.updateGameSubstituteRepository
@ -33,7 +34,6 @@ import com.gh.gamecenter.common.tracker.TrackerLogger
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IPackageUtilsProvider
import com.gh.gamecenter.core.provider.IStartUpAdProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.PrivacyPolicyEntity
@ -64,9 +64,6 @@ class SplashScreenActivity : BaseActivity() {
private var mStartMainActivityDirectly = false // 是否不需要用户点击立即体验就直接跳转首页
private var mViewModel: SplashScreenViewModel? = null
private var mShouldPrefetchData = true
private val mStartUpAdProvider by lazy {
ARouter.getInstance().build(RouteConsts.provider.adSdk).navigation() as? IStartUpAdProvider
}
private val mPermissions = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
@ -122,18 +119,13 @@ class SplashScreenActivity : BaseActivity() {
"这个弹窗只会在右上角有环境标签的测试包出现\n进入应用以后还可以到关于我们页面长按应用图标重新选择",
"正式环境",
"测试环境",
object : EmptyCallback {
override fun onCallback() {
SPUtils.setBoolean(Constants.SP_IS_DEV_ENV, false)
showPrivacyDialog(guideLayout)
}
{
SPUtils.setBoolean(Constants.SP_IS_DEV_ENV, false)
showPrivacyDialog(guideLayout)
},
object : EmptyCallback {
override fun onCallback() {
SPUtils.setBoolean(Constants.SP_IS_DEV_ENV, true)
showPrivacyDialog(guideLayout)
}
{
SPUtils.setBoolean(Constants.SP_IS_DEV_ENV, true)
showPrivacyDialog(guideLayout)
},
false,
"",
@ -285,7 +277,6 @@ class SplashScreenActivity : BaseActivity() {
overridePendingTransition(0, 0)
startActivity(intent)
doFlavorInit()
initStartUpAdSDK()
logAppLaunch()
finish()
}
@ -298,14 +289,6 @@ class SplashScreenActivity : BaseActivity() {
}
}
private fun initStartUpAdSDK() {
mStartUpAdProvider?.run {
if (shouldEnableSDK(HaloApp.getInstance().channel)) {
initSDK(applicationContext)
}
}
}
private fun getGitLogString(): String {
if (com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0L) {
val stringBuilder = StringBuilder()

View File

@ -13,7 +13,7 @@ import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.EnvHelper
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.entity.ConcernEntity
import com.gh.gamecenter.feature.entity.ConcernEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.common.entity.ToolBoxEntity
import com.halo.assistant.fragment.WebFragment
@ -197,11 +197,23 @@ open class WebActivity : ToolBarActivity() {
context: Context?,
concernEntity: ConcernEntity,
entrance: String?
): Intent {
return getIntentByNews(context, concernEntity.link, concernEntity.getGameName(), concernEntity.id, entrance)
}
// 获取游戏动态详情页
@JvmStatic
fun getIntentByNews(
context: Context?,
concernLink: String?,
concernGameName: String,
concernId: String?,
entrance: String?
): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_URL, concernEntity.link)
bundle.putString(EntranceConsts.KEY_GAMENAME, concernEntity.getGameName())
bundle.putString(EntranceConsts.KEY_NEWSID, concernEntity.id)
bundle.putString(EntranceConsts.KEY_URL, concernLink)
bundle.putString(EntranceConsts.KEY_GAMENAME, concernGameName)
bundle.putString(EntranceConsts.KEY_NEWSID, concernId)
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
return getTargetIntent(
context,

View File

@ -20,9 +20,9 @@ import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.gamecenter.common.utils.TextHelper;
import com.gh.gamecenter.common.viewholder.FooterViewHolder;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.entity.ArticleCommentParent;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.eventbus.EBDeleteComment;
import com.gh.gamecenter.feature.entity.ArticleCommentParent;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.feature.eventbus.EBDeleteComment;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.adapter.BaseRecyclerAdapter;
import com.lightgame.utils.Utils;

View File

@ -39,8 +39,8 @@ import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.databinding.LibaodetailItemContentBinding;
import com.gh.gamecenter.databinding.LibaodetailItemTopBinding;
import com.gh.gamecenter.entity.LibaoDetailEntity;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.LibaoEntity;
import com.gh.gamecenter.feature.entity.LibaoStatusEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.MeEntity;
import com.gh.gamecenter.feature.entity.UserDataLibaoEntity;

View File

@ -36,13 +36,13 @@ import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.adapter.viewholder.CommentHeadViewHolder;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.common.viewholder.FooterViewHolder;
import com.gh.gamecenter.adapter.viewholder.NewsDigestViewHolder;
import com.gh.gamecenter.feature.databinding.NewsDigestItemBinding;
import com.gh.gamecenter.feature.viewholder.NewsDigestViewHolder;
import com.gh.gamecenter.databinding.CommentHeadItemBinding;
import com.gh.gamecenter.databinding.NewsDigestItemBinding;
import com.gh.gamecenter.entity.ArticleCommentParent;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.entity.ConcernEntity;
import com.gh.gamecenter.eventbus.EBDeleteComment;
import com.gh.gamecenter.feature.entity.ArticleCommentParent;
import com.gh.gamecenter.feature.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.ConcernEntity;
import com.gh.gamecenter.feature.eventbus.EBDeleteComment;
import com.gh.gamecenter.manager.VisitManager;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.common.retrofit.OkHttpCache;

View File

@ -1,6 +1,6 @@
package com.gh.gamecenter.adapter;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.feature.entity.CommentEntity;
public interface OnCommentCallBackListener {
void onCommentCallback(CommentEntity entity);

View File

@ -20,6 +20,7 @@ import com.gh.common.chain.CheckDownloadHandler;
import com.gh.common.chain.CheckStoragePermissionHandler;
import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.LandPageAddressHandler;
import com.gh.common.chain.OverseaDownloadHandler;
import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
@ -237,6 +238,7 @@ public class DetailViewHolder {
builder.addHandler(new DownloadDialogHelperHandler());
builder.addHandler(new CertificationHandler());
builder.addHandler(new VersionNumberHandler());
builder.addHandler(new LandPageAddressHandler());
builder.addHandler(new OverseaDownloadHandler());
builder.addHandler(new CheckDownloadHandler());

View File

@ -3,7 +3,7 @@ package com.gh.gamecenter.adapter.viewholder;
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder;
import com.gh.gamecenter.common.callback.OnListClickListener;
import com.gh.gamecenter.databinding.LibaoItemBinding;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.feature.entity.LibaoEntity;
/**
* Created by khy on 2016/12/12.

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.baselist.ListViewModel
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.utils.toRequestBody
@ -15,6 +16,7 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.vspace.VArchiveHelper
import com.gh.vspace.db.VArchiveEntity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.Observable
@ -29,8 +31,7 @@ class CloudArchiveManagerViewModel(
private val mType: MyArchiveFragment.Type = MyArchiveFragment.Type.MY_ARCHIVE,
val gameId: String,
val configUrl: String
) :
ListViewModel<ArchiveEntity, ArchiveEntity>(application) {
) : ListViewModel<ArchiveEntity, ArchiveEntity>(application) {
companion object {
private const val SORT_TYPE_CREATE = "time.create:-1"
@ -47,50 +48,98 @@ class CloudArchiveManagerViewModel(
init {
getGameDigest()
if (mType == MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE) {
syncDownloadedArchives()
}
if (configUrl.isNotEmpty()) getArchiveConfigString(configUrl)
}
/**
* 同步已下载但还没同步到接口端的存档数据
*/
@SuppressLint("CheckResult")
fun syncDownloadedArchives() {
val unSyncedDownloadedArchivesIdSet = hashSetOf<String>()
val unSyncedDownloadedArchivesList = arrayListOf<VArchiveEntity>()
VArchiveHelper.getVArchiveEntityList().forEach {
if (it.isLocal == 0) {
unSyncedDownloadedArchivesIdSet.add(it.id)
unSyncedDownloadedArchivesList.add(it)
}
}
mNewApi.syncGameArchives(gameId, unSyncedDownloadedArchivesIdSet.toRequestBody())
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
unSyncedDownloadedArchivesList.forEach {
it.isLocal = 1
}
if (unSyncedDownloadedArchivesList.isNotEmpty()) {
VArchiveHelper.updateArchives(unSyncedDownloadedArchivesList)
}
}
})
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
list.forEach { it.gameId = gameId }
mResultLiveData.postValue(list)
if (mType == MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE) {
// 优先使用本地数据(未成功同步的数据),相同 ID 的网络数据屏蔽掉,加载到的网络数据补充到列表后面
val localIdSet = hashSetOf<String>()
val downloadList = VArchiveHelper.getVArchiveEntityList()
val archiveEntityList = arrayListOf<ArchiveEntity>()
for (vArchiveEntity in downloadList) {
if (vArchiveEntity.gameId == gameId
&& vArchiveEntity.type == 1
&& vArchiveEntity.isLocal == 0
) {
localIdSet.add(vArchiveEntity.id)
archiveEntityList.add(
ArchiveEntity(
id = vArchiveEntity.id,
name = vArchiveEntity.name,
gameId = vArchiveEntity.gameId,
desc = vArchiveEntity.descContent,
url = vArchiveEntity.url,
configUrl = vArchiveEntity.configUrl,
md5 = vArchiveEntity.md5,
time = ArchiveEntity.Time(create = vArchiveEntity.time),
gameVersion = vArchiveEntity.gameVersion
)
)
}
}
list.forEach {
if (!localIdSet.contains(it.id)) {
archiveEntityList.add(it)
}
}
if (archiveEntityList.isNotEmpty()) {
// 若数据不够用
mLoadStatusLiveData.postValue(LoadStatus.LIST_LOADED)
}
mResultLiveData.postValue(archiveEntityList)
} else {
mResultLiveData.postValue(list)
}
}
}
override fun provideDataObservable(page: Int): Observable<List<ArchiveEntity>>? = when (mType) {
MyArchiveFragment.Type.MY_ARCHIVE -> {
mNewApi.getMyArchives(gameId, page, SORT_TYPE_CREATE)
}
MyArchiveFragment.Type.MY_ARCHIVE -> mNewApi.getMyArchives(gameId, page, SORT_TYPE_CREATE)
MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE -> null
MyArchiveFragment.Type.MY_SHARE_ARCHIVE -> mNewApi.getMyShareArchives(gameId, page, SORT_TYPE_SHARE_AND_CREATE)
}
override fun provideDataSingle(page: Int): Single<MutableList<ArchiveEntity>>? {
return if (mType == MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE) {
Single.create { emitter ->
val downloadList = VArchiveHelper.vArchiveDao.getAll()
val archiveEntityList = arrayListOf<ArchiveEntity>()
if (downloadList != null) {
for (vArchiveEntity in downloadList) {
if (vArchiveEntity.gameId == gameId && vArchiveEntity.type == 1) {
archiveEntityList.add(
ArchiveEntity(
id = vArchiveEntity.id,
name = vArchiveEntity.name,
gameId = vArchiveEntity.gameId,
desc = vArchiveEntity.descContent,
url = vArchiveEntity.url,
configUrl = vArchiveEntity.configUrl,
md5 = vArchiveEntity.md5,
time = ArchiveEntity.Time(create = vArchiveEntity.time),
gameVersion = vArchiveEntity.gameVersion
)
)
}
}
}
emitter.onSuccess(archiveEntityList)
}
mNewApi.getArchivesDownloadHistories(gameId, page, 20)
} else {
null
}
@ -196,6 +245,9 @@ class CloudArchiveManagerViewModel(
})
}
/**
* 删除我的存档
*/
@SuppressLint("CheckResult")
fun deleteArchive(archiveEntity: ArchiveEntity) {
mNewApi.deleteMyArchive(gameId, archiveEntity.id)
@ -214,6 +266,27 @@ class CloudArchiveManagerViewModel(
})
}
/**
* 删除我下过的存档
*/
@SuppressLint("CheckResult")
fun deleteSyncedArchive(archiveEntity: ArchiveEntity) {
mNewApi.deleteSyncedGameArchive(gameId, archiveEntity.id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
load(LoadType.REFRESH)
Utils.toast(getApplication(), "删除成功")
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
Utils.toast(getApplication(), "删除失败")
}
})
}
// 通过url获取config字符串内容
private fun getArchiveConfigString(url: String) {

View File

@ -120,6 +120,11 @@ open class MyArchiveFragment : ListFragment<ArchiveEntity, CloudArchiveManagerVi
open fun onEventMainThread(reuse: EBReuse) {
if (reuse.type == Constants.LOGIN_TAG) {
onLoadRefresh()
// 从未登录变成登录状态时,同步本地已下载的数据
if (mType == Type.MY_DOWNLOAD_ARCHIVE) {
mViewModel.syncDownloadedArchives()
}
}
}

View File

@ -86,6 +86,7 @@ class MyArchiveOptionDialogFragment(
deleteLocalArchive(entity.md5)
EventBus.getDefault().post(EBReuse("RefreshArchive"))
}
mViewModel.deleteSyncedArchive(entity)
}
MyArchiveFragment.Type.MY_SHARE_ARCHIVE -> {
mViewModel.cancelShareArchive(entity)

View File

@ -9,7 +9,7 @@ import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.common.baselist.ListViewModel;
import com.gh.gamecenter.common.baselist.LoadType;
import com.gh.gamecenter.feature.entity.NewsEntity;
import com.gh.gamecenter.entity.ViewsEntity;
import com.gh.gamecenter.feature.entity.ViewsEntity;
import com.gh.gamecenter.info.NewsViewsRepository;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.retrofit.RetrofitManager;

View File

@ -10,7 +10,7 @@ import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.entity.PersonalHistoryEntity
import com.gh.gamecenter.entity.User
import com.gh.gamecenter.feature.entity.User
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp

View File

@ -9,15 +9,19 @@ import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.gh.ad.AdDelegateHelper
import com.gh.common.util.HomePluggableHelper
import com.gh.common.util.PackageInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseFragment_TabLayout
import com.gh.gamecenter.common.databinding.FragmentDownloadBinding
import com.gh.gamecenter.common.eventbus.EBMiPush
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.visibleIf
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.TabItemDownloadNumberBinding
import com.gh.gamecenter.entity.HomePluggableFilterEntity
import com.gh.gamecenter.feature.entity.PluginLocation
@ -42,12 +46,17 @@ class DownloadFragment : BaseFragment_TabLayout() {
private var mPermanentInactivePluggableApkList: List<HomePluggableFilterEntity>? = null
private val mBinding by lazy { FragmentDownloadBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mPermanentInactivePluggableApkList = HomePluggableHelper.getPermanentInactivePluggablePackage()
}
override fun getLayoutId() = 0
override fun getInflatedLayout() = mBinding.root
override fun initFragmentList(fragments: MutableList<Fragment>) {
fragments.add(GameDownloadFragment())
fragments.add(UpdatableGameFragment())
@ -94,6 +103,18 @@ class DownloadFragment : BaseFragment_TabLayout() {
mDownloadManager.markDownloadedTaskAsRead()
}
val ad = AdDelegateHelper.getDownloadManagerAd()?.thirdPartyAd
if (ad != null) {
AdDelegateHelper.requestBannerAd(
this,
mBinding.adContainer,
ad,
DisplayUtils.getScreenWidthInDp(requireActivity())
) { isSuccess ->
mBinding.maskView.goneIf(!isSuccess)
}
}
val pathOfPackageToInstall = activity?.intent?.getStringExtra(KEY_PATH_OF_PACKAGE_TO_INSTALL)
if (!TextUtils.isEmpty(pathOfPackageToInstall)) {
PackageInstaller.install(requireContext(), false, pathOfPackageToInstall)
@ -179,6 +200,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
mDownloadNumberTv.setBackgroundColor(Color.TRANSPARENT)
mDownloadNumberTv.text = downloadingCount.toString()
}
mDownloadManager.isContainsUnreadDownloadedTask -> {
layoutParams.width = 6F.dip2px()
layoutParams.height = 6F.dip2px()
@ -186,6 +208,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
mDownloadNumberTv.setBackgroundResource(R.drawable.oval_hint_red_bg)
mDownloadNumberTv.text = ""
}
else -> mDownloadNumberTv.visibility = View.GONE
}
mDownloadNumberTv.layoutParams = layoutParams

View File

@ -14,7 +14,7 @@ import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper.getGameId
import com.gh.gamecenter.feature.entity.ApkEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.GameInstall
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers

View File

@ -23,7 +23,7 @@ import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.databinding.FragmentMyGameBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.GameInstall
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.fragment.MainWrapperFragment

View File

@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.setPadding
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
@ -66,7 +67,7 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
override fun getItemViewType(position: Int): Int {
val item = mItemList!![position]
return when {
item.header != null || item.ignoredUpdateHeader != null -> TYPE_HEADER
item.header != null || item.ignoredUpdateHeader != null || item.landPageAddressDialogHeader != null -> TYPE_HEADER
item.normalUpdate != null || item.ignoredUpdate != null -> TYPE_NORMAL_GAME
item.normalUpdateWithArrow != null -> TYPE_NORMAL_GAME_WITH_ARROW
item.otherVersionUpdateHint != null -> TYPE_OTHER_VERSION_GAME_HINT
@ -89,6 +90,7 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
height = 8F.dip2px()
}
}
else -> BlankDividerViewHolder(parent.toBinding())
}
}
@ -105,19 +107,45 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
holder.binding.updateAllBtn.text = itemData.miscUpdateText
holder.binding.updateAllBtn.setOnClickListener {
if (itemData.miscUpdateText == "全部更新") {
if (mViewModel.hasLandPageAddressDialog()) {
DialogHelper.showDialog(
it.context,
title = it.context.getString(R.string.update_all_has_land_page_address_dialog_title),
content = it.context.getString(R.string.update_all_has_land_page_address_dialog_content),
confirmText = it.context.getString(R.string.update_all_has_land_page_address_dialog_confirm),
cancelText = ""
)
}
mViewModel.updateAllMatchedVersionValidUpdate()
}
}
holder.binding.infoTv.text = itemData.header ?: itemData.ignoredUpdateHeader
holder.binding.infoTv.text =
itemData.header ?: itemData.ignoredUpdateHeader ?: itemData.landPageAddressDialogHeader
if (itemData.header != null) {
holder.binding.infoTv.setTextColor(R.color.text_title.toColor(mContext))
(holder.binding.infoTv.layoutParams as ConstraintLayout.LayoutParams).apply {
bottomToBottom = ConstraintLayout.LayoutParams.UNSET
}
holder.binding.root.setOnClickListener(null)
holder.binding.root.setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 0)
holder.binding.infoTv.removeDrawable()
} else if (itemData.landPageAddressDialogHeader != null) {
holder.binding.infoTv.setTextColor(R.color.theme_yellow.toColor(mContext))
(holder.binding.infoTv.layoutParams as ConstraintLayout.LayoutParams).apply {
bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID
}
holder.binding.root.setOnClickListener(null)
holder.binding.root.setPadding(16F.dip2px(), 0, 16F.dip2px(), 0)
holder.binding.root.setBackgroundColor(R.color.home_realname_error.toColor(mContext))
} else {
holder.binding.infoTv.setTextColor(R.color.text_subtitleDesc.toColor(mContext))
(holder.binding.infoTv.layoutParams as ConstraintLayout.LayoutParams).apply {
bottomToBottom = ConstraintLayout.LayoutParams.UNSET
}
holder.binding.root.setOnClickListener {
mViewModel.toggleIgnoredUpdateVisibility()
}
holder.binding.root.setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 0)
holder.binding.infoTv.setDrawableEnd(
if (mViewModel.isIgnoredUpdateExpanded()) {
R.drawable.ic_arrow_up_grey.toDrawable()
@ -128,6 +156,7 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
}
}
}
is BlankDividerViewHolder -> {
if (itemData.divider == UpdatableGameViewModel.GREY) {
holder.binding.container.setBackgroundColor(R.color.background.toColor(holder.binding.root.context))
@ -137,6 +166,7 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
holder.binding.container.setBackgroundColor(R.color.background_white.toColor(holder.binding.root.context))
}
}
is UpdatableGameViewHolder -> {
val update: GameUpdateEntity = (itemData.normalUpdate
?: itemData.normalUpdateWithArrow
@ -188,6 +218,7 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
generateExposureEvent(update)
}
is UpdatableOtherVersionGameHintViewHolder -> {
holder.binding.root.setOnClickListener {
mViewModel.toggleOtherVersionVisibility(itemData.miscPackageName)
@ -310,10 +341,12 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
if (update.isPluggable) DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN else DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
updateBtn.progress = (downloadEntity.percent * 10).toInt()
}
DownloadStatus.waiting -> {
updateBtn.setText(R.string.waiting)
updateBtn.buttonStyle = DownloadButton.ButtonStyle.WAITING
}
DownloadStatus.timeout,
DownloadStatus.neterror,
DownloadStatus.subscribe,
@ -322,11 +355,13 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
updateBtn.setText(R.string.resume)
updateBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
}
DownloadStatus.done -> {
updateBtn.setText(R.string.install)
updateBtn.buttonStyle =
if (update.isPluggable) DownloadButton.ButtonStyle.INSTALL_PLUGIN else DownloadButton.ButtonStyle.INSTALL_NORMAL
}
else -> {
// do nothing
}
@ -340,6 +375,13 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
if ("更新" == str || str.contains("")) {
// 这里用 CurrentActivity 不用 view.context 的原因是
// view.context 在 5.0 以下设备会使用 TintContextWrapper 包一层导致类型转换异常
if ("更新" == str && update.isLandPageAddressDialog()) {// 第三方落地页跳转直接展示跳转弹窗
DialogUtils.showLandPageAddressDialog(it.context, update.transformGameEntity()) {// 跳转第三方落地页
DirectUtils.directToExternalBrowser(it.context, update.landPageAddressDialog!!.link!!)
}
return@setOnClickListener
}
(CurrentActivityHolder.getCurrentActivity() as? FragmentActivity)?.checkStoragePermissionBeforeAction {
DialogUtils.checkDownload(
updateBtn.context,

View File

@ -36,6 +36,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import java.util.*
import kotlin.collections.ArrayList
class UpdatableGameViewModel(
application: Application,
@ -50,6 +51,8 @@ class UpdatableGameViewModel(
private var mUpdatableListLiveData = MutableLiveData<ArrayList<UpdatableDataItem>>()
private var mHasLandPageAddressDialog = false // 是否存在由第三方提供的游戏下载
private val mSuppressUpdateDao by lazy { SuppressUpdateDao() }
private val mIgnoredUpdateDao by lazy { IgnoredUpdateDao() }
private val mDownloadedGameIdAndPackageNameDao by lazy { DownloadedGameIdAndPackageNameDao() }
@ -77,7 +80,8 @@ class UpdatableGameViewModel(
// 筛选仅下载管理出现的插件化更新
if (update.isShowPlugin(PluginLocation.only_index)
&& update.downloadStatus != Constants.V_GAME
&& update.downloadStatus != Constants.V_GAME_32) {
&& update.downloadStatus != Constants.V_GAME_32
) {
val platform =
PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform)
if (!platform.isNullOrEmpty() && "官方版" != platform) {
@ -273,6 +277,7 @@ class UpdatableGameViewModel(
val validPackageUpdateList: ArrayList<PackageUpdate> = arrayListOf() // 按钮为更新的我的游戏列表
val invalidPackageUpdateList: ArrayList<PackageUpdate> = arrayListOf() // 按钮为启动的我的游戏列表
val ignoredPackageUpdateList: ArrayList<PackageUpdate> = arrayListOf() // 被隐藏的我的游戏列表
val landPageAddressUpdateList: ArrayList<PackageUpdate> = arrayListOf() // 跳转第三方落地页的游戏列表
val ignoredUpdateList = mIgnoredUpdateDao.getAll()
@ -296,17 +301,26 @@ class UpdatableGameViewModel(
ignoredUpdateList?.contains(matchedPackageName + matchedVersionName) == true -> {
ignoredPackageUpdateList.add(packageUpdate)
}
packageUpdate.matchedVersionUpdate.version == currentlyUpdatableVersion
&& !PackagesManager.isCanUpdate(installedGhId, matchedPackageName)
&& !isUpdatePluggableRelated(packageUpdate.matchedVersionUpdate) -> {
&& !isUpdatePluggableRelated(packageUpdate.matchedVersionUpdate)
&& !packageUpdate.matchedVersionUpdate.isLandPageAddressDialog() -> {
invalidPackageUpdateList.add(packageUpdate)
}
packageUpdate.matchedVersionUpdate.isLandPageAddressDialog() -> {// 第三方落地页跳转
landPageAddressUpdateList.add(packageUpdate)
}
else -> {
validPackageUpdateList.add(packageUpdate)
}
}
}
mHasLandPageAddressDialog = landPageAddressUpdateList.isNotEmpty()
// 构建装饰好的页面列表
// 正常的我的版本
if (validPackageUpdateList.isNotEmpty()) {
@ -406,6 +420,34 @@ class UpdatableGameViewModel(
}
}
// 游戏下载资源由第三方提供
if (landPageAddressUpdateList.isNotEmpty()) {
if (updatableDataItemList.size != 0) {
updatableDataItemList.add(UpdatableDataItem(divider = WHITE))
}
updatableDataItemList.add(UpdatableDataItem(landPageAddressDialogHeader = "以下游戏下载资源由第三方提供"))
for (packageUpdate in landPageAddressUpdateList) {
if (packageUpdate.mismatchedVersionUpdateList.isNotEmpty()) {
updatableDataItemList.add(UpdatableDataItem(normalUpdateWithArrow = packageUpdate.matchedVersionUpdate))
updatableDataItemList.add(
UpdatableDataItem(
otherVersionUpdateHint = mOtherVersionExpandedMap[packageUpdate.matchedVersionUpdate.packageName] == true,
miscPackageName = packageUpdate.matchedVersionUpdate.packageName,
miscVersion = packageUpdate.matchedVersionUpdate.currentVersion ?: ""
)
)
if (mOtherVersionExpandedMap[packageUpdate.matchedVersionUpdate.packageName] == true) {
for (update in packageUpdate.mismatchedVersionUpdateList) {
updatableDataItemList.add(UpdatableDataItem(otherVersionUpdate = update))
}
updatableDataItemList.add(UpdatableDataItem(divider = BLUE))
}
} else {
updatableDataItemList.add(UpdatableDataItem(normalUpdate = packageUpdate.matchedVersionUpdate))
}
}
}
return updatableDataItemList
}
@ -558,6 +600,11 @@ class UpdatableGameViewModel(
}
}
/**
* 是否存在第三方提供下载的游戏
*/
fun hasLandPageAddressDialog(): Boolean = mHasLandPageAddressDialog
/**
* 更新列表状态
*/
@ -686,6 +733,7 @@ class UpdatableGameViewModel(
var divider: String? = null,
var header: String? = null,
var ignoredUpdateHeader: String? = null,
var landPageAddressDialogHeader: String? = null,
var normalUpdate: GameUpdateEntity? = null,
var normalUpdateWithArrow: GameUpdateEntity? = null,
var ignoredUpdate: GameUpdateEntity? = null,

View File

@ -0,0 +1,35 @@
package com.gh.gamecenter.entity
import com.google.gson.annotations.SerializedName
class AdConfig(
val name: String,
val location: String, // 广告插入位置。光环启动halo_launch 下载管理download_manager 游戏搜索game_search 助手启动helper_launch
val type: String, // 广告位类型。开屏广告launch 信息流广告native banner 广告banner 插屏广告interstitial
val position: Int, // 定位,不存在的时候返回:-1
@SerializedName("display_rules")
val displayRule: DisplayRule,
@SerializedName("third_party_ads")
val thirdPartyAd: ThirdPartyAd? = null,
@SerializedName("owner_ads")
val ownerAd: StartupAdEntity? = null,
) {
class DisplayRule(
@SerializedName("ad_source")
val adSource: String, // 广告位获取广告源。第三方广告third_party_ads 自有广告owner_ads
@SerializedName("on_failed")
val onFailedAction: String, // 第三方广告获取失败时。显示自有广告show 隐藏广告位hide
)
class ThirdPartyAd(
@SerializedName("source_name")
val sourceName: String, // 广告源名。穿山甲、倍孜
@SerializedName("ad_size")
val displaySize: String,
@SerializedName("code_name")
val slotName: String,
@SerializedName("code_id")
val slotId: String
)
}

View File

@ -47,7 +47,8 @@ data class GameUpdateEntity(
var signature: String? = "",
var category: String? = "",
var md5: String? = "",
var downloadStatus: String? = ""
var downloadStatus: String? = "",
var landPageAddressDialog: GameEntity.AddressDialog? = null // 第三方跳转落地页跳转链接
) {
val categoryChinese: String
get() = when (category) {
@ -74,6 +75,13 @@ data class GameUpdateEntity(
return false
}
/**
* 是否为第三方落地页跳转游戏
*/
fun isLandPageAddressDialog(): Boolean {
return landPageAddressDialog?.let { it.status == "on" } ?: false
}
fun transformGameEntity(): GameEntity {
val gameEntity = GameEntity()
gameEntity.id = id
@ -90,6 +98,7 @@ data class GameUpdateEntity(
gameEntity.pluginDesc = pluginDesc
gameEntity.pluggableCollection = pluggableCollection
gameEntity.category = category
gameEntity.landPageAddressDialog = landPageAddressDialog
val apkEntity = ApkEntity()
apkEntity.url = url

View File

@ -6,9 +6,7 @@ import androidx.room.Ignore
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
import com.gh.gamecenter.R
import com.gh.gamecenter.feature.entity.MeEntity
import com.gh.gamecenter.feature.entity.SimpleGame
import com.gh.gamecenter.feature.entity.Count
import com.gh.gamecenter.feature.entity.*
import com.gh.gamecenter.feature.entity.TimeEntity
import com.gh.gamecenter.room.converter.*
import com.google.gson.annotations.SerializedName

View File

@ -5,6 +5,7 @@ import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
import com.gh.gamecenter.feature.entity.User
import com.gh.gamecenter.room.converter.UserConverter
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

View File

@ -8,8 +8,6 @@ class NewApiSettingsEntity(
@SerializedName("night_mode")
var nightMode: NightMode? = null,
var simulator: SimulatorEntity? = null,
@SerializedName("start_ad")
var startAd: StartupAdEntity? = null,//开屏图片广告
var startup: StartupAdEntity? = null,//启动文案广告
@SerializedName("user_interested_game")
var userInterestedGame: Boolean = false, //偏好设置状态开关

View File

@ -4,7 +4,8 @@ import com.gh.gamecenter.common.entity.LinkEntity
import com.google.gson.annotations.SerializedName
class StartupAdEntity(
@SerializedName("_id")
// 接口返回了个狗屎 code_id 过来,只能用 alternate 来 map 一下了
@SerializedName(value = "_id", alternate = ["code_id"])
val id: String,
val desc: String,
val button: Boolean,

View File

@ -16,6 +16,7 @@ class SubjectData(
var tagType: String? = "", // 游戏Item 标签类型
var briefStyle: String = "",
var showSuffix: Boolean = true,
var isQQMiniGame: Boolean = false,
var requireUpdateSetting: Boolean = false, // 多专题页面需要专题页面自行获取专题配置
var isAdData: Boolean = false,

View File

@ -96,7 +96,10 @@ data class SubjectEntity(
var position: Int = -1,
// 本地字段,用来标记在外部页面中的序号,仅用于曝光记录,具体细节可见 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087
var outerSequence: Int = -1
var outerSequence: Int = -1,
@SerializedName("is_qq_column")
var isQQColumn: Boolean = false
) : Parcelable {
@IgnoredOnParcel

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter.entity
import com.gh.gamecenter.common.entity.ToolBoxEntity
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.LibaoEntity
import com.google.gson.annotations.SerializedName
class UnifiedUserTrendEntity(

View File

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

View File

@ -46,7 +46,7 @@ class WelfaresAdapter(
"游戏动态" -> {
NewLogUtils.logForumPageEvent("click_forum_game_general")
CheckLoginUtils.checkLogin(mContext, "社区-论坛:游戏动态") {
DirectUtils.directToConcernInfo(mContext)
DirectUtils.directToConcernInfo(mContext, "社区-论坛:游戏动态")
}
}

View File

@ -0,0 +1,171 @@
package com.gh.gamecenter.fragment
import android.graphics.Typeface
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SentryHelper
import com.gh.gamecenter.databinding.FragmentHomeGameWrapperBinding
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.packagehelper.PackageViewModel
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlin.math.roundToInt
class HomeGameWrapperFragment : HomeTabWrapperFragment() {
private var mViewModel: HomeGameWrapperViewModel? = null
private var mPackageViewModel: PackageViewModel? = null
private var mBinding: FragmentHomeGameWrapperBinding? = null
override fun getRealLayoutId(): Int = R.layout.fragment_home_game_wrapper
override fun getInflatedLayout(): View =
FragmentHomeGameWrapperBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
mViewModel?.forumTabPairs?.forEach { pair ->
if (pair.first == position) {
DirectUtils.directForumDetail(requireContext(), pair.second, "游戏库")
mViewPager?.post { mViewPager?.currentItem = position - 1 }
}
}
}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
tabEntityList: ArrayList<SubjectRecommendEntity>
) {
mCurrentTabSelectedColor = mTabSelectedColor
mCurrentTabDefaultColor = mTabDefaultColor
// 这里的 selectedPosition 指的是应该被高亮显示的 position
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 {
positionOffset
}
updateTabStyle(selectedPosition, positionOffsetOnRealSelectedPosition)
}
override fun initRealView() {
super.initRealView()
mBinding?.run {
searchIv.setOnClickListener {
startActivity(SearchActivity.getIntent(requireContext(), false, "", "游戏库", "游戏库"))
}
downloadContainer.setOnClickListener {
DataCollectionUtils.uploadClick(activity, "下载图标", "主页")
startActivity(DownloadManagerActivity.getDownloadMangerIntent(requireContext(), "游戏库"))
}
mBinding?.menuDownloadCountHint?.typeface =
Typeface.createFromAsset(requireContext().assets, "fonts/d_din_bold_only_number.ttf")
}
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
val factory = HomeGameWrapperViewModel.Factory(arguments?.getParcelable(EntranceConsts.KEY_BLOCK_DATA))
mViewModel = viewModelProvider(factory)
mPackageViewModel = viewModelProvider(PackageViewModel.Factory())
mViewModel?.tabs?.observe(viewLifecycleOwner) {
if (mDefaultSelectedTab == -1) {
mDefaultSelectedTab = mViewModel?.defaultTabPosition ?: 0
}
mHomeTabPosition = mViewModel?.getHomeTabPosition() ?: 0
initViewPager(it, "游戏库")
mBinding?.toolbarContainer?.visibility = View.VISIBLE
mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.GONE
mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE
}
mViewModel?.error?.observe(viewLifecycleOwner) {
mBinding?.toolbarContainer?.visibility = View.GONE
mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.VISIBLE
mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE
mBinding?.noConnectionContainer?.reuseNoConnection?.setOnClickListener {
mViewModel?.getHomeGameTab()
mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.GONE
mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.VISIBLE
}
}
mPackageViewModel?.filterSameUpdateLiveData?.observe(this) {
setDownloadHint(it)
}
}
private fun setDownloadHint(updateList: List<GameUpdateEntity>) {
val count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList)
val params = mBinding?.menuDownloadCountHint?.layoutParams
params?.width = if (count.isNullOrEmpty()) 6F.dip2px() else ConstraintLayout.LayoutParams.WRAP_CONTENT
params?.height = if (count.isNullOrEmpty()) 6F.dip2px() else 14F.dip2px()
(params as ViewGroup.MarginLayoutParams).setMargins(
0,
if (count.isNullOrEmpty()) 0 else (-4F).dip2px(),
if (count.isNullOrEmpty()) (-4F).dip2px() else (-8F).dip2px(),
0
)
mBinding?.menuDownloadCountHint?.setPadding(
if (count.isNullOrEmpty()) 0 else 4F.dip2px(),
0,
if (count.isNullOrEmpty()) 0 else 4F.dip2px(),
0
)
mBinding?.menuDownloadCountHint?.minWidth = if (count.isNullOrEmpty()) 0 else 14F.dip2px()
mBinding?.menuDownloadCountHint?.layoutParams = params
mBinding?.menuDownloadCountHint?.goneIf(count == null)
mBinding?.menuDownloadCountHint?.text = count.toString()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus?) {
mPackageViewModel?.filterSameUpdateLiveData?.value?.let { setDownloadHint(it) }
}
override fun getLastTabRightMargin(): Int = 26F.dip2px()
override fun logTabSelected(tabEntity: SubjectRecommendEntity, position: Int) {
LogUtils.logHomeTopTabClick(tabEntity.name, tabEntity.type, tabEntity.text, tabEntity.link, position, "游戏库")
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
if (isSupportVisible) DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn)
mCurrentTabSelectedColor = mTabSelectedColor
mCurrentTabDefaultColor = mTabDefaultColor
updateTabStyle(mLastSelectedPosition, 0F)
}
}

View File

@ -0,0 +1,87 @@
package com.gh.gamecenter.fragment
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.pkg.PkgHelper
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
class HomeGameWrapperViewModel(application: Application, val blockData: SubjectRecommendEntity?) :
AndroidViewModel(application) {
private val mApi = RetrofitManager.getInstance().newApi
val tabs = MutableLiveData<ArrayList<SubjectRecommendEntity>>()
val error = MutableLiveData<Exception>()
var defaultTabPosition = 0
var forumTabPairs: ArrayList<Pair<Int, String>> = arrayListOf()
private var mHomeTab: SubjectRecommendEntity? = null
private var mHomeTabPosition: Int = -1
init {
getHomeGameTab()
}
fun getHomeTabEntity() = mHomeTab
fun getHomeTabPosition() = mHomeTabPosition
@SuppressLint("CheckResult")
fun getHomeGameTab() {
mApi.getBlockTab(blockData?.link)
.compose(singleToMain())
.subscribe(object : BiResponse<List<SubjectRecommendEntity>>() {
override fun onSuccess(data: List<SubjectRecommendEntity>) {
data.forEachIndexed { index, tab ->
if (tab.type == "block") {
mHomeTab = tab
mHomeTabPosition = index
}
if (tab.default) {
defaultTabPosition = index
}
if (tab.type == "bbs") {
forumTabPairs.add(Pair(index, tab.link ?: ""))
}
}
// 根据特殊打包配置,调整默认选中的 tab
PkgHelper.getPkgConfig(isFromGameTopTab = true)?.let { pkgLinkEntity ->
if (pkgLinkEntity.shouldStayAtMainActivity) {
for ((index, tab) in data.withIndex()) {
if (pkgLinkEntity.type == tab.type
&& (pkgLinkEntity.link == tab.link || tab.link == null)) {
defaultTabPosition = index
break
}
}
// 无论是否找到默认选中的 tab都把这个配置标记为已读避免下次启动这个配置仍生效
PkgHelper.markConfigUsed()
}
}
tabs.postValue(ArrayList(data))
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
error.postValue(exception)
}
})
}
class Factory(val blockData: SubjectRecommendEntity?) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return HomeGameWrapperViewModel(HaloApp.getInstance().application, blockData) as T
}
}
}

View File

@ -1,16 +1,10 @@
package com.gh.gamecenter.fragment
import android.graphics.Color
import android.graphics.Typeface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.core.graphics.ColorUtils
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils
import com.gh.common.util.DownloadItemUtils
@ -21,42 +15,27 @@ import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.amway.AmwayFragment
import com.gh.gamecenter.catalog.CatalogFragment
import com.gh.gamecenter.category.CategoryDirectoryFragment
import com.gh.gamecenter.category2.CategoryV2Fragment
import com.gh.gamecenter.common.base.adapter.FragmentAdapter
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.TabIndicatorView
import com.gh.gamecenter.common.view.WrapContentDraweeView
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.FragmentMainHomeWrapperBinding
import com.gh.gamecenter.databinding.TabItemMainBinding
import com.gh.gamecenter.discovery.DiscoveryFragment
import com.gh.gamecenter.entity.HomePush
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.exposure.time.TimeUtil
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.gh.gamecenter.game.GameFragment
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailFragment
import com.gh.gamecenter.game.commoncollection.detail.CommonCollectionDetailFragment
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareFragment
import com.gh.gamecenter.home.HomeFragment
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.servers.GameServersPublishFragment
import com.gh.gamecenter.servers.GameServersTestFragment
import com.gh.gamecenter.servers.gametest2.GameServerTestV2Fragment
import com.gh.gamecenter.subject.SubjectFragment
import com.google.android.material.appbar.AppBarLayout
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.WebFragment
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.scwang.smartrefresh.layout.api.RefreshHeader
@ -70,27 +49,16 @@ import org.greenrobot.eventbus.ThreadMode
import kotlin.math.abs
import kotlin.math.roundToInt
class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
class HomeSearchToolWrapperFragment : HomeTabWrapperFragment() {
private var mBinding: FragmentMainHomeWrapperBinding? = null
private var mTabBindingList = arrayListOf<TabItemMainBinding>()
private var mTabImageStyleList = arrayListOf<Int>()
private var mTabSelectedColor: Int = 0
private var mTabDefaultColor: Int = 0
private var mCurrentAppBarColor: Int = 0
private var mIsDisplayingLightContent = false
private var mDefaultSelectedTab = -1
private var mLastSelectedPosition = 0
private var mViewModel: HomeSearchToolWrapperViewModel? = null
private var mFragmentList = ArrayList<Fragment>()
private var mHomeTabPosition = -1
private var mOffsetCritical = 0.7F
private var mShowTwoLevel = false
@ -119,13 +87,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedInstanceState?.let { mDefaultSelectedTab = it.getInt(LAST_SELECTED_POSITION) }
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
mViewModel = viewModelProviderFromParent()
mElapsedHelper = TimeElapsedHelper()
mSearchToolbarFragment =
@ -151,7 +114,7 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
mDefaultSelectedTab = mViewModel?.defaultTabPosition ?: 0
}
mHomeTabPosition = mViewModel?.getHomeTabPosition() ?: 0
initViewPager(it)
initViewPager(it, "首页")
// 当 tab 只有一个的时候隐藏顶部 tab 栏,停用 nestedScroll
if (it.size == 1) {
@ -349,18 +312,12 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
})
twoLevelHeader.setOnTwoLevelListener {
mHomePush?.run {
if (game != null) {
game.sequence = mTwoLevelOpenCount
mExposureEvent = ExposureEvent.createEventWithSourceConcat(
game,
basicSource = listOf(ExposureSource("新首页", "")),
source = listOf(ExposureSource("下拉推送", id))
)
ExposureManager.log(mExposureEvent!!)
}
mExposureEvent?.timeInMillisecond = System.currentTimeMillis()
mExposureEvent?.time = TimeUtil.currentTime()
mExposureEvent?.payload?.sequence = mTwoLevelOpenCount
mExposureEvent?.let {
ExposureManager.log(it)
}
mElapsedHelper.resetCounting()
mElapsedHelper.resumeCounting()
playHomePushVideo()
@ -427,9 +384,9 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
) else R.drawable.ic_commodity_selected.toDrawable(
requireContext()
)
if (mTabSelectedColor != tabSelectedColor || mTabDefaultColor != tabDefaultColor) {
mTabSelectedColor = tabSelectedColor
mTabDefaultColor = tabDefaultColor
if (mCurrentTabSelectedColor != tabSelectedColor || mCurrentTabDefaultColor != tabDefaultColor) {
mCurrentTabSelectedColor = tabSelectedColor
mCurrentTabDefaultColor = tabDefaultColor
updateTabStyle(mLastSelectedPosition, 0F)
indicatorView.updateIndicatorDrawable(indicatorDrawable)
}
@ -482,6 +439,15 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
private fun setHomePush() {
mHomePush?.run {
if (game != null) {
game.sequence = 1
mExposureEvent = ExposureEvent.createEventWithSourceConcat(
game,
basicSource = listOf(ExposureSource("新首页", "")),
source = listOf(ExposureSource("下拉推送", id))
)
}
mBinding?.run {
if (game != null) {
gameNameTv.text = game.name
@ -528,7 +494,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
fun popUpHomePushIfNeeded() {
mBinding?.run {
if (mFragmentList.safelyGetInRelease(viewPager.currentItem) !is HomeFragment) return
if (mFragmentList.isEmpty()
|| mFragmentList.safelyGetInRelease(viewPager.currentItem) !is HomeFragment) return
mHomePush?.run {
val homePushSet = HashSet(SPUtils.getStringSet(Constants.SP_HOME_PUSH_POP_UP_SET))
if (popSwitch == "on" && !homePushSet.contains(id)) {
@ -642,48 +609,18 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
updateHomePushDownloadBtn()
}
override fun onSaveInstanceState(outState: Bundle) {
mBinding?.viewPager?.let { outState.putInt(LAST_SELECTED_POSITION, it.currentItem) }
super.onSaveInstanceState(outState)
}
override fun getInflatedLayout() =
FragmentMainHomeWrapperBinding.inflate(layoutInflater).apply { mBinding = this }.root
private fun initViewPager(tabEntityList: ArrayList<SubjectRecommendEntity>) {
val fragmentList = generateFragments(tabEntityList).apply { mFragmentList = this }
val tabTitleList = arrayListOf<String>()
tabEntityList.forEach { tabTitleList.add(it.name ?: "") }
mBinding?.run {
viewPager.offscreenPageLimit = fragmentList.size
viewPager.doOnScroll(
onPageSelected = { position ->
refreshLayout.setEnableRefresh(getFragment(position) is HomeFragment && mHomePush != null)
if (mShowTwoLevel) finishTwoLevel("跳转收起")
notifyChildFragmentLifecycle(position)
mViewModel?.forumTabPairs?.forEach { pair ->
if (pair.first == position) {
DirectUtils.directForumDetail(requireContext(), pair.second, "首页")
viewPager.post { viewPager.currentItem = position - 1 }
}
}
tabEntityList.safelyGetInRelease(position)?.let { logTabSelected(it, position) }
},
onPageScrolled = { position, positionOffset, _ ->
onPageScrolled(position, positionOffset, tabEntityList)
}
)
setRestoredCurItem(viewPager)
viewPager.adapter = FragmentAdapter(childFragmentManager, fragmentList, tabTitleList)
tabLayout.setupWithViewPager(mBinding?.viewPager)
indicatorView.setupWithTabLayout(mBinding?.tabLayout)
indicatorView.setupWithViewPager(mBinding?.viewPager)
indicatorView.setIndicatorWidth(18)
initTabView(tabEntityList)
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
mBinding?.refreshLayout?.setEnableRefresh(getFragment(position) is HomeFragment && mHomePush != null)
if (mShowTwoLevel) finishTwoLevel("跳转收起")
mViewModel?.forumTabPairs?.forEach { pair ->
if (pair.first == position) {
DirectUtils.directForumDetail(requireContext(), pair.second, "首页")
mViewPager?.post { mViewPager?.currentItem = position - 1 }
}
}
}
@ -695,34 +632,29 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
}
private fun onPageScrolled(position: Int, positionOffset: Float, tabEntityList: ArrayList<SubjectRecommendEntity>) {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
tabEntityList: ArrayList<SubjectRecommendEntity>
) {
val nextPosition = position + 1
// TODO 避免高频调用 toColor 方法
val backgroundColor = R.color.background.toColor(requireContext())
val backgroundWhiteColor = R.color.background_white.toColor(requireContext())
val amwayPrimaryColor = R.color.amway_primary_color.toColor(requireContext())
val tabDefaultColor = TAB_DEFAULT_COLOR.toColor(requireContext())
val tabSelectedColor = TAB_SELECTED_COLOR.toColor(requireContext())
val tabDefaultLightColor = TAB_DEFAULT_COLOR_LIGHT.toColor(requireContext())
val tabEntity = tabEntityList.safelyGetInRelease(position)
// 处理当前 tab 和下一个 tab
if (nextPosition != mTabBindingList.size) {
val nextTabEntity = tabEntityList.safelyGetInRelease(nextPosition)
var currentAppBarColor = tabEntity?.primaryColor ?: backgroundWhiteColor
var nextAppBarColor = nextTabEntity?.primaryColor ?: backgroundWhiteColor
var currentAppBarColor = tabEntity?.primaryColor ?: mBackgroundWhiteColor
var nextAppBarColor = nextTabEntity?.primaryColor ?: mBackgroundWhiteColor
if (currentAppBarColor == Color.WHITE) currentAppBarColor = backgroundWhiteColor
if (nextAppBarColor == Color.WHITE) nextAppBarColor = backgroundWhiteColor
if (currentAppBarColor == Color.WHITE) currentAppBarColor = mBackgroundWhiteColor
if (nextAppBarColor == Color.WHITE) nextAppBarColor = mBackgroundWhiteColor
if (getFragment(position) is AmwayFragment) {
currentAppBarColor = if (mIsDarkModeOn) backgroundColor else amwayPrimaryColor
currentAppBarColor = if (mIsDarkModeOn) mBackgroundColor else mAmwayPrimaryColor
tabEntity?.currentSelectColor = currentAppBarColor
}
if (getFragment(nextPosition) is AmwayFragment) {
nextAppBarColor = if (mIsDarkModeOn) backgroundColor else amwayPrimaryColor
nextAppBarColor = if (mIsDarkModeOn) mBackgroundColor else mAmwayPrimaryColor
}
val proximatelySelectedTabEntity = if (positionOffset < 0.5) tabEntity else nextTabEntity
@ -739,9 +671,9 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
mIsDisplayingLightContent = proximatelySelectedTabEntity?.useLightStyle ?: false
if (!mShowTwoLevel) {
mTabSelectedColor =
if (mIsDisplayingLightContent) tabDefaultLightColor else tabSelectedColor
mTabDefaultColor = if (mIsDisplayingLightContent) tabDefaultLightColor else tabDefaultColor
mCurrentTabSelectedColor =
if (mIsDisplayingLightContent) mTabDefaultLightColor else mTabSelectedColor
mCurrentTabDefaultColor = if (mIsDisplayingLightContent) mTabDefaultLightColor else mTabDefaultColor
}
if (isContentStyleChanged) {
@ -752,19 +684,19 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
mCurrentAppBarColor = appBarColorInBetween
updateAppBarStyle(appBarColorInBetween, mIsDisplayingLightContent)
} else {
var currentAppBarColor = tabEntity?.primaryColor ?: backgroundWhiteColor
var currentAppBarColor = tabEntity?.primaryColor ?: mBackgroundWhiteColor
if (mIsDarkModeOn && currentAppBarColor == Color.WHITE) {
currentAppBarColor = backgroundWhiteColor
currentAppBarColor = mBackgroundWhiteColor
}
if (getFragment(position) is AmwayFragment) {
currentAppBarColor = if (mIsDarkModeOn) backgroundColor else amwayPrimaryColor
currentAppBarColor = if (mIsDarkModeOn) mBackgroundColor else mAmwayPrimaryColor
tabEntity?.currentSelectColor = currentAppBarColor
}
mIsDisplayingLightContent = tabEntity?.useLightStyle == true
if (!mShowTwoLevel) {
mTabSelectedColor =
if (mIsDisplayingLightContent) tabDefaultLightColor else tabSelectedColor
mTabDefaultColor = if (mIsDisplayingLightContent) tabDefaultLightColor else tabDefaultColor
mCurrentTabSelectedColor =
if (mIsDisplayingLightContent) mTabDefaultLightColor else mTabSelectedColor
mCurrentTabDefaultColor = if (mIsDisplayingLightContent) mTabDefaultLightColor else mTabDefaultColor
}
updateAppBarStyle(currentAppBarColor, mIsDisplayingLightContent)
@ -789,170 +721,21 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
updateTabStyle(selectedPosition, positionOffsetOnRealSelectedPosition)
}
/**
* 更新 tab 的样式
* @param selectedPosition 选中的 tab
* @param positionOffset 与选中 tab 的位置偏移,为负时在选中的 tab 左边,为正时在选中 tab 的右边
*/
private fun updateTabStyle(selectedPosition: Int, positionOffset: Float) {
if (mTabBindingList.isEmpty()) return
val prePosition = selectedPosition - 1
val nextPosition = selectedPosition + 1
// positionOffset 小于零,表示 indicator 当前位置处于选中的 tab 的左边
val indicatorOnLeft = positionOffset < 0F
val selectedTabBinding = mTabBindingList.safelyGetInRelease(selectedPosition) ?: return
val selectedTabImageStyle = mTabImageStyleList.safelyGetInRelease(selectedPosition) ?: return
// 前一个 tab、当前选中的 tab、后一个 tab 的显示比例
val preScaleRatio = 1 + abs(positionOffset) / 4
val selectedScaleRatio = 1 + (1 - abs(positionOffset)) / 4
val nextScaleRatio = 1 + positionOffset / 4
// 处理前一个 tab
if (prePosition != -1) {
mTabBindingList[prePosition].run {
if (indicatorOnLeft) {
when (mTabImageStyleList[prePosition]) {
TAB_IMAGE_ALWAYS_ON -> {
titleIv.scaleX = preScaleRatio
titleIv.scaleY = preScaleRatio
}
TAB_IMAGE_HIDE_ON_SELECTED -> {
titleIv.scaleX = preScaleRatio
titleIv.scaleY = preScaleRatio
titleIv.visibility = View.VISIBLE
titleTv.visibility = View.GONE
invisibleTitleTv.visibility = View.GONE
}
else -> {
titleIv.visibility = View.GONE
titleTv.visibility = View.VISIBLE
invisibleTitleTv.visibility = View.INVISIBLE
}
}
titleTv.textSize = (DEFAULT_TAB_TEXT_SIZE * preScaleRatio).roundTo(1)
titleTv.setTextColor(ColorUtils.blendARGB(mTabDefaultColor, mTabSelectedColor, abs(positionOffset)))
} else {
titleTv.setTextColor(mTabDefaultColor)
}
}
}
// 更新当前选中的 tab
selectedTabBinding.run {
// 更新当前选中的 tab 的图片显示状态
when (selectedTabImageStyle) {
TAB_IMAGE_ALWAYS_ON -> {
val scaleRatio = (1 + (1 - abs(positionOffset)) * 0.25).toFloat()
titleIv.scaleX = scaleRatio
titleIv.scaleY = scaleRatio
}
else -> {
titleIv.visibility = View.GONE
titleTv.visibility = View.VISIBLE
invisibleTitleTv.visibility = View.INVISIBLE
mBinding?.indicatorView?.visibility = View.VISIBLE
}
}
// 选中常驻型的图片时隐藏 indicatorView
mBinding?.indicatorView?.goneIf(selectedTabImageStyle == TAB_IMAGE_ALWAYS_ON)
titleTv.textSize = (DEFAULT_TAB_TEXT_SIZE * selectedScaleRatio).roundTo(1)
titleTv.setTextColor(ColorUtils.blendARGB(mTabDefaultColor, mTabSelectedColor, 1 - abs(positionOffset)))
}
// 处理后一个 tab
if (nextPosition < mTabBindingList.size) {
mTabBindingList[nextPosition].run {
if (!indicatorOnLeft) {
when (mTabImageStyleList[nextPosition]) {
TAB_IMAGE_ALWAYS_ON -> {
titleIv.scaleX = nextScaleRatio
titleIv.scaleY = nextScaleRatio
}
TAB_IMAGE_HIDE_ON_SELECTED -> {
titleIv.scaleX = nextScaleRatio
titleIv.scaleY = nextScaleRatio
titleIv.visibility = View.VISIBLE
titleTv.visibility = View.GONE
invisibleTitleTv.visibility = View.GONE
}
else -> {
titleIv.visibility = View.GONE
titleTv.visibility = View.VISIBLE
invisibleTitleTv.visibility = View.INVISIBLE
}
}
titleTv.textSize = (DEFAULT_TAB_TEXT_SIZE * nextScaleRatio).roundTo(1)
titleTv.setTextColor(ColorUtils.blendARGB(mTabDefaultColor, mTabSelectedColor, positionOffset))
} else {
titleTv.setTextColor(mTabDefaultColor)
}
}
}
// 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续)
for ((index, binding) in mTabBindingList.withIndex()) {
if (index != prePosition && index != selectedPosition && index != nextPosition) {
if (binding.titleTv.textSize != DEFAULT_TAB_TEXT_SIZE) {
binding.titleTv.textSize = DEFAULT_TAB_TEXT_SIZE
binding.titleTv.setTextColor(mTabDefaultColor)
}
if (binding.titleIv.scaleX != 1F) {
binding.titleIv.scaleX = 1F
binding.titleIv.scaleY = 1F
}
}
if (index == selectedPosition) {
if (positionOffset == 0F) {
binding.titleTv.setTextColor(mTabSelectedColor)
}
binding.titleTv.setTypeface(binding.titleTv.typeface, Typeface.BOLD)
} else {
if (positionOffset == 0F) {
binding.titleTv.setTextColor(mTabDefaultColor)
}
binding.titleTv.setTypeface(null, Typeface.NORMAL)
}
}
}
fun onScrollChanged(totalHeight: Int, offset: Int) {
val currentTab = getCurrentTabEntity()
val backgroundWhiteColor = R.color.background_white.toColor(requireContext())
val backgroundColor = R.color.background.toColor(requireContext())
val amwayPrimaryColor = R.color.amway_primary_color.toColor(requireContext())
val tabDefaultLightColor = TAB_DEFAULT_COLOR_LIGHT.toColor(requireContext())
val tabSelectedColor = TAB_SELECTED_COLOR.toColor(requireContext())
val tabDefaultColor = TAB_DEFAULT_COLOR.toColor(requireContext())
currentTab?.offsetRatio = offset / totalHeight.toFloat()
if ((currentTab?.isTopViewShow == true && offset >= totalHeight)
|| currentTab?.isSlideEmpty == true
) {
currentTab.isTopViewShow = false
currentTab.primaryColor = backgroundWhiteColor
currentTab.primaryColor = mBackgroundWhiteColor
currentTab.useLightStyle = false
mIsDisplayingLightContent = false
updateAppBarColorWhenScrollChanged(backgroundWhiteColor)
updateAppBarColorWhenScrollChanged(mBackgroundWhiteColor)
refreshStatusBarStyle()
if (!mShowTwoLevel) {
mTabSelectedColor = TAB_SELECTED_COLOR.toColor(requireContext())
mTabDefaultColor = TAB_DEFAULT_COLOR.toColor(requireContext())
mCurrentTabSelectedColor = TAB_SELECTED_COLOR.toColor(requireContext())
mCurrentTabDefaultColor = TAB_DEFAULT_COLOR.toColor(requireContext())
mBinding?.indicatorView?.updateIndicatorDrawable(R.drawable.ic_commodity_selected.toDrawable())
updateTabStyle(mLastSelectedPosition, 0F)
}
@ -961,10 +744,10 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
val offsetMeetsCriticalPoint = (currentTab?.offsetRatio ?: 0F) < mOffsetCritical
currentTab?.isTopViewShow = true
if (getFragment(mBinding?.viewPager?.currentItem ?: 0) is AmwayFragment) {
currentSelectColor = if (mIsDarkModeOn) backgroundColor else amwayPrimaryColor
currentSelectColor = if (mIsDarkModeOn) mBackgroundColor else mAmwayPrimaryColor
}
val colorInBetween =
ColorUtils.blendARGB(currentSelectColor, backgroundWhiteColor, currentTab?.offsetRatio ?: 0F)
ColorUtils.blendARGB(currentSelectColor, mBackgroundWhiteColor, currentTab?.offsetRatio ?: 0F)
updateAppBarColorWhenScrollChanged(colorInBetween)
currentTab?.primaryColor = colorInBetween
currentTab?.useLightStyle = offsetMeetsCriticalPoint
@ -975,8 +758,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
refreshStatusBarStyle()
if (!mShowTwoLevel) {
mTabSelectedColor = if (offsetMeetsCriticalPoint) tabDefaultLightColor else tabSelectedColor
mTabDefaultColor = if (offsetMeetsCriticalPoint) tabDefaultLightColor else tabDefaultColor
mCurrentTabSelectedColor = if (offsetMeetsCriticalPoint) mTabDefaultLightColor else mTabSelectedColor
mCurrentTabDefaultColor = if (offsetMeetsCriticalPoint) mTabDefaultLightColor else mTabDefaultColor
mBinding?.indicatorView?.updateIndicatorDrawable(
if (offsetMeetsCriticalPoint) {
R.drawable.ic_home_tab_indicator_white.toDrawable()
@ -1031,144 +814,6 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
} else null
}
private fun notifyChildFragmentLifecycle(currentSelectedPosition: Int) {
tryWithDefaultCatch {
// 补充 Viewpager Fragment 的生命周期, 先调用旧选中 fragment 的 onPause 再当前的 onResume
// 避免部分被内嵌的 Fragment 不能正常运作
if (mFragmentList.size > mLastSelectedPosition) {
val fragment: Fragment = mFragmentList[mLastSelectedPosition]
if (!fragment.isAdded) return
fragment.onPause()
val childFragmentManager = fragment.childFragmentManager
val fragments = childFragmentManager.fragments
for (childFragment in fragments) {
childFragment.onPause()
}
}
if (mFragmentList.size > currentSelectedPosition) {
val fragment: Fragment = mFragmentList[currentSelectedPosition]
if (!fragment.isAdded) return
fragment.onResume()
val childFragmentManager = fragment.childFragmentManager
val fragments = childFragmentManager.fragments
for (childFragment in fragments) {
childFragment.onResume()
}
}
mLastSelectedPosition = currentSelectedPosition
}
}
private fun generateFragments(tabEntityList: ArrayList<SubjectRecommendEntity>): ArrayList<Fragment> {
val fragmentList = arrayListOf<Fragment>()
for ((index, tabEntity) in tabEntityList.withIndex()) {
val fragment = when (tabEntity.type) {
"home" -> HomeFragment().with(Bundle())
"top_game_comment" -> AmwayFragment().with(Bundle())
"block" -> GameFragment().with(Bundle().apply {
putParcelable(EntranceConsts.KEY_BLOCK_DATA, tabEntity)
})
"server" -> GameServersPublishFragment().with(Bundle())
"game_list" -> GameCollectionSquareFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, "顶部tab")
putInt(EntranceConsts.KEY_TAB_INDEX, index)
putString(EntranceConsts.KEY_NAME, tabEntity.name)
})
"column_test" -> GameServersTestFragment().with(Bundle().apply {
putString(GameServersTestFragment.TEST_COLUMN_ID, tabEntity.link)
})
"category" -> CategoryDirectoryFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_CATEGORY_ID, tabEntity.link)
putString(EntranceConsts.KEY_CATEGORY_TITLE, tabEntity.text)
})
"catalog" -> CatalogFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_CATALOG_ID, tabEntity.link)
putString(EntranceConsts.KEY_CATALOG_TITLE, tabEntity.text)
})
"category_v2" -> CategoryV2Fragment().with(Bundle().apply {
putString(EntranceConsts.KEY_CATEGORY_ID, tabEntity.link)
putString(EntranceConsts.KEY_CATEGORY_TITLE, tabEntity.text)
})
"ranking", "column_collection" -> ColumnCollectionDetailFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, "首页")
putString(EntranceConsts.KEY_COLLECTION_ID, tabEntity.link)
putInt(EntranceConsts.KEY_POSITION, 0)
putString(EntranceConsts.KEY_COLUMNNAME, tabEntity.text)
putBoolean(EntranceConsts.KEY_IS_COLUMN_COLLECTION, true)
putInt(EntranceConsts.KEY_TAB_INDEX, index)
putParcelableArrayList(
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST,
arrayListOf(ExposureSource("顶部tab", tabEntity.name ?: ""))
)
})
"column" -> SubjectFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, "首页")
putParcelable(
EntranceConsts.KEY_SUBJECT_DATA,
SubjectData(tabEntity.link, tabEntity.text, false)
)
})
"web" -> WebFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_URL, tabEntity.link)
putString(EntranceConsts.KEY_ENTRANCE, "首页tab")
putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, false)
putBoolean(WebFragment.KEY_ENABLE_HORIZONTAL_SCROLL_DISPATCH, true)
if (tabEntity.link?.contains("leave_web_page_handle_back_pressed=true") == true) {
putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_BACK_PRESSED, true)
}
})
"common_collection" -> CommonCollectionDetailFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, "首页顶部Tab栏")
putString(EntranceConsts.KEY_COLLECTION_ID, tabEntity.link)
putString(EntranceConsts.KEY_COLUMNNAME, tabEntity.text)
putInt(EntranceConsts.KEY_TAB_INDEX, index)
putParcelableArrayList(
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST,
arrayListOf(ExposureSource("顶部tab", tabEntity.name ?: ""))
)
})
"explore_column" -> DiscoveryFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, "首页")
putInt(EntranceConsts.KEY_POSITION, index)
})
"column_test_v2" -> GameServerTestV2Fragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, "首页")
putInt(EntranceConsts.KEY_POSITION, index)
putParcelable(
EntranceConsts.KEY_EXPOSURE_SOURCE,
ExposureSource("顶部tab", tabEntity.name ?: "")
)
})
"bbs" -> Fragment()
else -> Fragment()
}
fragment.arguments?.putInt(EntranceConsts.KEY_TAB_COUNT, tabEntityList.size)
fragment.arguments?.putBoolean(EntranceConsts.KEY_IS_HOME, true)
if (fragment.arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE) == null) {
fragment.arguments?.putParcelable(
EntranceConsts.KEY_EXPOSURE_SOURCE,
ExposureSource("首页顶部Tab栏", tabEntity.name ?: "")
)
}
fragmentList.add(fragment)
}
return fragmentList
}
/**
* 更新 AppBar 的控件 style
*/
@ -1181,34 +826,11 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
mSearchToolbarFragment.updateStyle(mIsDarkModeOn || useLightStyle)
}
/**
* 生成 TabView
*/
private fun generateTabView(title: String): TabItemMainBinding {
val binding = TabItemMainBinding.inflate(LayoutInflater.from(requireContext()))
binding.titleTv.run {
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
setTextColor(mTabDefaultColor)
}
binding.invisibleTitleTv.run {
text = title
textSize = DEFAULT_TAB_TEXT_SIZE
}
return binding
}
override fun onBackPressed(): Boolean {
if (mShowTwoLevel) {
finishTwoLevel("主动收起")
return true
}
mBinding?.viewPager?.run {
val currentFragment = mFragmentList.safelyGetInRelease(currentItem)
if (currentFragment is WebFragment) {
return currentFragment.onBackPressed()
}
}
return super.onBackPressed()
}
@ -1256,70 +878,11 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
}
/**
* 初始化每个需要显示的 TabView
*/
private fun initTabView(tabEntityList: ArrayList<SubjectRecommendEntity>) {
for (i in 0 until tabEntityList.size) {
val tabView = mBinding?.tabLayout?.getTabAt(i) ?: continue
val tabEntity = tabEntityList[i]
val tabTitle = if (tabView.text != null) tabView.text.toString() else ""
val tabViewBinding = generateTabView(tabTitle)
val tabImageStyle = if (tabEntity.img.isNullOrEmpty()) {
TAB_IMAGE_EMPTY
} else if (tabEntity.showImgOnSelected == true) {
TAB_IMAGE_ALWAYS_ON
} else {
TAB_IMAGE_HIDE_ON_SELECTED
}
mTabBindingList.add(tabViewBinding)
mTabImageStyleList.add(tabImageStyle)
if (!tabEntity.img.isNullOrEmpty()) {
tabViewBinding.titleTv.visibility = View.GONE
tabViewBinding.invisibleTitleTv.visibility = View.GONE
tabViewBinding.titleIv.setFixedHeight(16)
// 部分设备加载图片时会获取到错误的最小宽度,这里为它做个 64DP 的保底尺寸
tabViewBinding.titleIv.setTag(ImageUtils.TAG_TARGET_WIDTH, 64F.dip2px())
tabViewBinding.titleIv.display(tabEntity.img)
tabViewBinding.titleIv.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
postRunnable {
mBinding?.run {
// 图片 layout 完成后,更新 tabBar 和 indicatorView 的位置,避免偏移
tabLayout.setScrollPosition(viewPager.currentItem, 0F, false)
indicatorView.generatePath(viewPager.currentItem, 0F)
}
}
}
})
} else {
tabViewBinding.titleTv.visibility = View.VISIBLE
tabViewBinding.invisibleTitleTv.visibility = View.INVISIBLE
}
tabView.customView = tabViewBinding.root
tabView.view.setPadding(0, 0, 0, 0)
tabView.view.setOnClickListener {
if (mShowTwoLevel) {
mBinding?.twoLevelHeader?.setFloorDuration(100)
mBinding?.refreshLayout?.setFloorDuration(100)
finishTwoLevel("跳转收起")
}
}
// 第一个和最后一个分别设置额外的外边距
if (i == 0) {
tabView.view.updateLayoutParams {
this as LinearLayout.LayoutParams
setMargins(10F.dip2px(), 0, 0, 0)
}
} else if (i == tabEntityList.size - 1) {
tabView.view.updateLayoutParams {
this as LinearLayout.LayoutParams
setMargins(0, 0, 10F.dip2px(), 0)
}
}
override fun onTabViewClick() {
if (mShowTwoLevel) {
mBinding?.twoLevelHeader?.setFloorDuration(100)
mBinding?.refreshLayout?.setFloorDuration(100)
finishTwoLevel("跳转收起")
}
}
@ -1331,35 +894,11 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDisplayingLightContent && !mIsDarkModeOn)
}
/**
* 设置 ViewPager 默认的选中项
*/
private fun setRestoredCurItem(viewPager: ViewPager) {
// 设置默认 position 避免 position 为 0 的 fragment 被先加载显示再跳转至具体页面
tryCatchInRelease {
val field = ViewPager::class.java.getDeclaredField("mRestoredCurItem")
field.isAccessible = true
field.set(viewPager, mDefaultSelectedTab)
mLastSelectedPosition = mDefaultSelectedTab
}
}
/**
* 安全地从根据 position 获取 fragment
*/
private fun getFragment(position: Int): Fragment? {
return if (position < mFragmentList.size) {
mFragmentList.safelyGetInRelease(position)
} else {
null
}
}
/**
* 记录 tab 被选中的日志
*/
private fun logTabSelected(tabEntity: SubjectRecommendEntity, position: Int) {
LogUtils.logHomeTopTabClick(tabEntity.name, tabEntity.type, tabEntity.text, tabEntity.link, position)
override fun logTabSelected(tabEntity: SubjectRecommendEntity, position: Int) {
LogUtils.logHomeTopTabClick(tabEntity.name, tabEntity.type, tabEntity.text, tabEntity.link, position, "首页")
SensorsBridge.trackEvent("HomeTopTabSelect",
json {
@ -1384,24 +923,11 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
companion object {
const val LAST_SELECTED_POSITION = "last_selected_position"
var TAB_SELECTED_COLOR: Int = R.color.text_title
var TAB_DEFAULT_COLOR: Int = R.color.text_subtitle
var TAB_DEFAULT_COLOR_LIGHT: Int = R.color.search_text_color_light
var DEFAULT_TAB_TEXT_SIZE = 16F
const val HOME_PUSH_VIDEO_PLAY_DELAY = 100L
const val AUTO_FINISH_TWO_LEVEL_DELAY = 5000L
const val FINISH_TWO_LEVEL_DELAY = 1000L
const val AUTO_OPEN_TWO_LEVEL_DURATION = 1000L
const val PULL_TAB_TEXT_STYLE_UPDATE_PERCENT = 0.5F
const val TAB_IMAGE_EMPTY = 0
const val TAB_IMAGE_HIDE_ON_SELECTED = 1
const val TAB_IMAGE_ALWAYS_ON = 2
}
}

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