Compare commits

..

126 Commits

Author SHA1 Message Date
33a5e2061f chore: 版本更新至 5.25.2 2023-05-24 16:56:34 +08:00
b62b1f399c Merge branch 'hotfix/v5.25.1-851/ad_error' into 'release'
fix: 修复开屏广告无响应的问题

See merge request halo/android/assistant-android!1049
2023-05-24 16:49:05 +08:00
c4449db90a fix: 修复开屏广告无响应的问题 2023-05-24 16:13:55 +08:00
6edd9f2204 Merge branch 'hotfix/v5.25.1-851/database_crash' into 'release'
fix: 修复数据库变更导致的畅玩数据转化闪退

See merge request halo/android/assistant-android!1048
2023-05-24 14:09:17 +08:00
8508b9ece2 fix: 修复数据库变更导致的畅玩数据转化闪退 2023-05-24 11:52:26 +08:00
20d5ef7a6e Merge branch 'hotfix/v5.25.1-851/GHZS-2518' into 'release'
fix: 【光环助手】右侧卡片曝光数据问题 https://jira.shanqu.cc/browse/GHZS-2518

See merge request halo/android/assistant-android!1047
2023-05-24 10:47:59 +08:00
ff70d7a48a fix: 【光环助手】右侧卡片曝光数据问题 https://jira.shanqu.cc/browse/GHZS-2518 2023-05-24 09:55:31 +08:00
4bc2374cb4 chore: 版本更新至 5.25.1 2023-05-23 15:50:38 +08:00
8efa858a01 Merge branch 'hotfix/v5.25.0-850/oaid_crash' into 'release'
fix: 修复oaid初始化sdk出现的闪退问题...

See merge request halo/android/assistant-android!1044
2023-05-23 15:28:00 +08:00
53e2297976 fix: 修复oaid初始化sdk出现的闪退问题... 2023-05-23 15:28:00 +08:00
9cd5e342ac Merge branch 'hotfix/v5.25.0-850/forum_video_crash' into 'release'
fix: 修复视频贴闪退问题...

See merge request halo/android/assistant-android!1046
2023-05-23 11:40:21 +08:00
26dfb79ece fix: 修复视频贴闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/298062/?project=22&query=dist%3A850&statsPeriod=14d 2023-05-23 11:12:22 +08:00
7bc36814b7 Merge branch 'hotfix/v5.25.0-850/geetest_crash' into 'release'
fix: 修复验证码校验闪退问题

See merge request halo/android/assistant-android!1043
2023-05-22 17:45:37 +08:00
b29651ecfb fix: 修复验证码校验闪退问题 2023-05-22 17:34:35 +08:00
74aad0e7e0 Merge branch 'fix/create_shortcut_crash' into 'release'
fix: 修复畅玩跳转创建桌面图标时偶发的闪退问题...

See merge request halo/android/assistant-android!1042
2023-05-22 15:43:54 +08:00
52a5faacfe fix: 修复畅玩跳转创建桌面图标时偶发的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/295365/?project=22&query=dist%3A835+level%3Afatal&sort=freq&statsPeriod=14d 2023-05-22 15:41:08 +08:00
5cee489ba6 Merge branch 'fix/xapk_dialog_failure_show_crash' into 'release'
fix: 修复频繁弹出 XAPK 解压失败弹窗导致的闪退问题...

See merge request halo/android/assistant-android!1041
2023-05-22 15:33:48 +08:00
f76c3e3638 fix: 修复频繁弹出 XAPK 解压失败弹窗导致的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/279064/events/339dc5e883f54c2ba11ed26e0af89bd7/?project=22&query=level%3Afatal+badtoken&statsPeriod=14d 2023-05-22 15:15:52 +08:00
386a7f82d9 Merge branch 'fix/debug_compile_error' into 'dev'
fix: 修复debug包编译问题

See merge request halo/android/assistant-android!1040
2023-05-22 11:05:31 +08:00
94983c4b7f fix: 修复debug包编译问题 2023-05-22 10:51:08 +08:00
119cdf4f91 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2023-05-19 15:55:10 +08:00
bde7685dc6 Merge branch 'fix/compile_error' into 'dev'
fix: 修复编译问题

See merge request halo/android/assistant-android!1037
2023-05-19 14:45:51 +08:00
6acaa95098 fix: 修复编译问题 2023-05-19 14:16:19 +08:00
610f116b82 Merge branch 'feature/ci_optimise' into 'dev'
ci: android build 添加 resource_group 避免资源抢夺

See merge request halo/android/assistant-android!1036
2023-05-19 14:02:42 +08:00
fe616ed87b ci: android build 添加 resource_group 避免资源抢夺 2023-05-19 13:56:36 +08:00
91ba665c4c Merge branch 'hotfix/v5.24.5-835/forum_detail_section' into 'release'
fix:【光环助手】子版块展示错位 https://jira.shanqu.cc/browse/GHZS-1867

See merge request halo/android/assistant-android!1035
2023-05-18 16:09:46 +08:00
f05b20ed98 fix:【光环助手】子版块展示错位 https://jira.shanqu.cc/browse/GHZS-1867 2023-05-18 14:17:48 +08:00
74d3e8b2d4 Merge branch 'feature/GHZS-2176' into 'dev'
合并开屏广告SDK相关代码

See merge request halo/android/assistant-android!1033
2023-05-18 11:48:52 +08:00
74364cd452 合并开屏广告SDK相关代码 2023-05-18 11:48:52 +08:00
dc2a023fbb Merge branch 'fix/GHZS-2372' into 'release'
fix: 推广渠道接入神策数据平台—05/15测试 https://jira.shanqu.cc/browse/GHZS-2372

See merge request halo/android/assistant-android!1032
2023-05-16 16:02:50 +08:00
47560daec6 fix: 推广渠道接入神策数据平台—05/15测试 https://jira.shanqu.cc/browse/GHZS-2372 2023-05-16 16:00:46 +08:00
657b900418 Merge branch 'fix/GHZS-2372' into 'release'
fix: 推广渠道接入神策数据平台—05/15测试 https://jira.shanqu.cc/browse/GHZS-2372

See merge request halo/android/assistant-android!1031
2023-05-16 15:46:05 +08:00
d826c3dcce fix: 推广渠道接入神策数据平台—05/15测试 https://jira.shanqu.cc/browse/GHZS-2372 2023-05-16 11:54:35 +08:00
935d61f910 Merge branch 'fix/CWZS-53' into 'dev'
Resolve CWZS-53

See merge request halo/android/assistant-android!1030
2023-05-15 11:09:43 +08:00
0a412feefb Merge branch 'fix/GHZS-2370' into 'dev'
fix:【光环助手】新游开测显示问题 https://jira.shanqu.cc/browse/GHZS-2370

See merge request halo/android/assistant-android!1029
2023-05-15 10:45:18 +08:00
31111a1cc8 fix:【光环助手】新游开测显示问题 https://jira.shanqu.cc/browse/GHZS-2370 2023-05-15 10:45:18 +08:00
cf901ef840 fix: 需要谷歌框架的游戏授权后无法跳转返回的问题 https://jira.shanqu.cc/browse/CWZS-53 2023-05-12 14:44:06 +08:00
8d70716f15 chore: 版本更新为 5.24.5 2023-05-12 11:53:14 +08:00
7cf086874a Merge branch 'feature/GHZS-2364' into 'release'
feat: 推广渠道接入神策数据平台 https://jira.shanqu.cc/browse/GHZS-2364

See merge request halo/android/assistant-android!1027
2023-05-12 11:51:20 +08:00
d1698f0c2d feat: 推广渠道接入神策数据平台 https://jira.shanqu.cc/browse/GHZS-2364 2023-05-12 11:48:06 +08:00
f80bcbcfb9 fix: 修复畅玩安装记录时可能错误使用同包名其它游戏实体的问题 https://jira.shanqu.cc/browse/CWZS-53 2023-05-12 11:33:37 +08:00
2ea9d46e12 Merge branch 'fix/GHZS-2340' into 'dev'
fix: 同步正式环境问题—镜像游戏安装包大小显示错误 https://jira.shanqu.cc/browse/GHZS-2340

See merge request halo/android/assistant-android!1022
2023-05-11 11:35:26 +08:00
65445859d3 fix: 同步正式环境问题—镜像游戏安装包大小显示错误 https://jira.shanqu.cc/browse/GHZS-2340 2023-05-11 11:28:46 +08:00
8c9927b9cb Merge branch 'fix/build_error' into 'dev'
fix: 处理编译问题

See merge request halo/android/assistant-android!1021
2023-05-11 10:42:40 +08:00
5477a4a4cc fix: 处理编译问题 2023-05-11 10:36:01 +08:00
3ff4a9b6cf chore: 版本更新至 5.24.4 2023-05-10 17:35:51 +08:00
174f47edb1 Merge branch 'hotfix/v5.24.3-833/home_push_crash' into 'release'
fix: 修复首页下拉推送弹出时偶发的闪退问题...

See merge request halo/android/assistant-android!1019
2023-05-10 17:35:19 +08:00
96fbe30924 fix: 修复首页下拉推送弹出时偶发的闪退问题... 2023-05-10 17:35:19 +08:00
954c7e427a Merge branch 'fix/GHZS-2262' into 'dev'
fix: 推广包修改激活上报比例没有生效 https://jira.shanqu.cc/browse/GHZS-2262

See merge request halo/android/assistant-android!1018
2023-05-10 17:22:34 +08:00
e466eb6683 fix: 推广包修改激活上报比例没有生效 https://jira.shanqu.cc/browse/GHZS-2262 2023-05-10 16:07:46 +08:00
01437e9d8a Merge branch 'fix/GHZS-2337' into 'dev'
fix:【光环助手】首页下拉推送显示问题 https://jira.shanqu.cc/browse/GHZS-2337

See merge request halo/android/assistant-android!1017
2023-05-10 14:31:17 +08:00
eac553ba46 fix:【光环助手】首页下拉推送显示问题 https://jira.shanqu.cc/browse/GHZS-2337 2023-05-10 14:11:16 +08:00
81d5a8a12c Merge branch 'fix/crashes' into 'dev'
fix: 处理查看大图页长按图片没有消费事件引起的闪退...

See merge request halo/android/assistant-android!1014
2023-05-09 16:40:56 +08:00
192ae916de Merge branch 'hotfix/v5.24.3-833/more_feature_crash' into 'release'
fix: 修复我的光环更多功能列表刷新后数量减少时发生的数组越界闪退...

See merge request halo/android/assistant-android!1013
2023-05-09 11:31:46 +08:00
5047ae5f9c fix: 修复我的光环更多功能列表刷新后数量减少时发生的数组越界闪退... 2023-05-09 11:31:46 +08:00
f5a30a7dde fix: 处理查看大图页长按图片没有消费事件引起的闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/136944/events/94b3165c29d54705b3e7d461bd04bc0a/?project=22&query=showContextMenuForChild&statsPeriod=14d 2023-05-09 10:33:59 +08:00
e9c22ef577 Merge branch 'fix/GHZS-2322' into 'dev'
尝试修复闪退问题

See merge request halo/android/assistant-android!1012
2023-05-08 17:31:31 +08:00
8292d8512d 尝试修复闪退问题 2023-05-08 17:31:31 +08:00
a606633755 Merge branch 'hotfix/v5.24.3-833/home_collection_crash' into 'release'
fix: 修复首页游戏单异步更新view时发生的数组越界闪退...

See merge request halo/android/assistant-android!1011
2023-05-08 17:14:19 +08:00
9788b632d6 fix: 修复首页游戏单异步更新view时发生的数组越界闪退... 2023-05-08 17:14:19 +08:00
0a8211d40b Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/build.gradle
#	dependencies.gradle
2023-05-08 09:50:13 +08:00
c16407e360 Merge branch 'feature-GHZS-2305' into 'dev'
feat: 长期有效的礼包客户端显示优化—客户端 https://jira.shanqu.cc/browse/GHZS-2305

See merge request halo/android/assistant-android!1006
2023-05-06 15:46:36 +08:00
b7ca5c54a3 feat: 长期有效的礼包客户端显示优化—客户端 https://jira.shanqu.cc/browse/GHZS-2305 2023-05-06 15:46:36 +08:00
d42a915ef5 Merge branch 'feature-GHZS-packet-capture-tool-support' into 'dev'
feat: internal和debug包支持抓包工具(Charles、Fiddler、ProxyMan)

See merge request halo/android/assistant-android!1005
2023-05-06 13:56:22 +08:00
91c1e8fcef feat: internal和debug包支持抓包工具(Charles、Fiddler、ProxyMan) 2023-05-06 13:51:40 +08:00
da40da432f Merge branch 'fix/GHZS-2261' into 'dev'
fix: 修复视频播放的日志 task 让线程池爆满的问题 https://jira.shanqu.cc/browse/GHZS-2261

See merge request halo/android/assistant-android!998
2023-04-28 13:46:32 +08:00
6a03b63e65 fix: 修复视频播放的日志 task 让线程池爆满的问题 https://jira.shanqu.cc/browse/GHZS-2261 2023-04-28 13:46:32 +08:00
224c17c582 Merge branch 'feature-GHZS-2256' into 'dev'
fix: 修复论坛详情ArticleItemVideoView内存泄露的问题 https://jira.shanqu.cc/browse/GHZS-2256

See merge request halo/android/assistant-android!996
2023-04-28 09:22:15 +08:00
64a35316cb fix: 修复论坛详情ArticleItemVideoView内存泄露的问题 https://jira.shanqu.cc/browse/GHZS-2256 2023-04-27 18:05:11 +08:00
78207eb0cb Merge branch 'fix/animated_webp_display_issue' into 'dev'
fix: 修复 webp 动图无法自动播放的问题

See merge request halo/android/assistant-android!994
2023-04-27 16:49:35 +08:00
c3b9b52f5d fix: 修复 webp 动图无法自动播放的问题 2023-04-27 16:34:05 +08:00
586af43050 Merge branch 'dev' into 'dev-5.25.0'
合并 5.24.0 相关变更

See merge request halo/android/assistant-android!991
2023-04-27 09:56:11 +08:00
50510b808f Merge branch 'fix/GHZS-2249' into 'dev-5.25.0'
fix: 新增镜像tab—0426测试2 https://jira.shanqu.cc/browse/GHZS-2249

See merge request halo/android/assistant-android!989
2023-04-26 21:29:00 +08:00
d46ef9f068 fix: 新增镜像tab—0426测试2 https://jira.shanqu.cc/browse/GHZS-2249 2023-04-26 21:25:35 +08:00
293561d807 Merge branch 'fix/GHZS-2249' into 'dev-5.25.0'
fix: 新增镜像tab—0426测试2 https://jira.shanqu.cc/browse/GHZS-2249

See merge request halo/android/assistant-android!988
2023-04-26 20:44:57 +08:00
4c64137e9a fix: 新增镜像tab—0426测试2 https://jira.shanqu.cc/browse/GHZS-2249 2023-04-26 20:40:46 +08:00
57e57c19d0 Merge branch 'fix/GHZS-2242' into 'dev-5.25.0'
fix: 首页tab栏新增上传图片—0426UI测试 https://jira.shanqu.cc/browse/GHZS-2242

See merge request halo/android/assistant-android!985
2023-04-26 17:20:04 +08:00
475b03d591 fix: 首页tab栏新增上传图片—0426UI测试 https://jira.shanqu.cc/browse/GHZS-2242 2023-04-26 17:19:28 +08:00
a97091bf49 Merge branch 'fix/GHZS-2247' into 'dev-5.25.0'
fix: 论坛详情页相关UI优化—0426UI测试 https://jira.shanqu.cc/browse/GHZS-2247

See merge request halo/android/assistant-android!984
2023-04-26 17:18:32 +08:00
7a12c4ab1d fix: 论坛详情页相关UI优化—0426UI测试 https://jira.shanqu.cc/browse/GHZS-2247 2023-04-26 17:12:03 +08:00
4f732c3921 Merge branch 'fix/GHZS-2202' into 'dev-5.25.0'
fix: 新游开测相关功能优化—0423测试 https://jira.shanqu.cc/browse/GHZS-2202

See merge request halo/android/assistant-android!983
2023-04-26 16:15:15 +08:00
531deacc3d fix: 新游开测相关功能优化—0423测试 https://jira.shanqu.cc/browse/GHZS-2202 2023-04-26 16:14:46 +08:00
b219e60f13 Merge branch 'fix/GHZS-2230' into 'dev-5.25.0'
fix: 新游开测相关功能优化—0425UI测试 https://jira.shanqu.cc/browse/GHZS-2230

See merge request halo/android/assistant-android!982
2023-04-26 16:05:34 +08:00
387fc37b19 fix: 新游开测相关功能优化—0425UI测试 https://jira.shanqu.cc/browse/GHZS-2230 2023-04-26 16:04:48 +08:00
1b88c3e0a3 Merge branch 'fix/GHZS-2244' into 'dev-5.25.0'
fix: 新增镜像tab—0426测试 https://jira.shanqu.cc/browse/GHZS-2244

See merge request halo/android/assistant-android!981
2023-04-26 16:01:33 +08:00
af1c7ff2c9 fix: 新增镜像tab—0426测试 https://jira.shanqu.cc/browse/GHZS-2244 2023-04-26 15:53:16 +08:00
976f315ba8 Merge branch 'fix/GHZS-2242' into 'dev-5.25.0'
fix: 首页tab栏新增上传图片—0426UI测试 https://jira.shanqu.cc/browse/GHZS-2242

See merge request halo/android/assistant-android!980
2023-04-26 15:13:11 +08:00
216c13054b fix: 首页tab栏新增上传图片—0426UI测试 https://jira.shanqu.cc/browse/GHZS-2242 2023-04-26 15:04:27 +08:00
3fd4d330d2 Merge branch 'feature/GHZS-2144' into 'dev-5.25.0'
feat: 论坛详情页相关UI优化—客户端(1-2) https://jira.shanqu.cc/browse/GHZS-2144

See merge request halo/android/assistant-android!978
2023-04-26 13:55:01 +08:00
f811759bf4 Merge branch 'feature/GHZS-2145' into 'dev-5.25.0'
feat: 新增子版块图标配置—客户端 https://jira.shanqu.cc/browse/GHZS-2145

See merge request halo/android/assistant-android!977
2023-04-26 13:54:27 +08:00
6efc5bb4fa feat: 新增子版块图标配置—客户端 https://jira.shanqu.cc/browse/GHZS-2145 2023-04-26 11:50:37 +08:00
754d7f58c0 Merge branch 'feature/GHZS-2141' into 'dev-5.25.0'
feat: 首页tab栏新增上传图片 https://jira.shanqu.cc/browse/GHZS-2141

See merge request halo/android/assistant-android!975
2023-04-26 10:48:38 +08:00
dc39f9f207 feat: 首页tab栏新增上传图片 https://jira.shanqu.cc/browse/GHZS-2141 2023-04-26 10:10:52 +08:00
65c46c2eb4 Merge branch 'dev' into 'dev-5.25.0'
fix: 合并 5.22.5 的闪退修复

See merge request halo/android/assistant-android!974
2023-04-26 09:38:32 +08:00
40e30058f9 Merge branch 'feature/GHZS-2155' into 'dev-5.25.0'
feat: 游戏详情页tab顺序调整 https://jira.shanqu.cc/browse/GHZS-2155

See merge request halo/android/assistant-android!971
2023-04-25 14:13:02 +08:00
432f8dc090 Merge branch 'dev' into 'dev-5.25.0'
Dev

See merge request halo/android/assistant-android!969
2023-04-25 13:58:40 +08:00
ea68931461 feat: 游戏详情页tab顺序调整 https://jira.shanqu.cc/browse/GHZS-2155 2023-04-25 13:54:54 +08:00
e6a2f0528a Merge branch 'fix/GHZS-2202' into 'dev-5.25.0'
fix: 新游开测相关功能优化—0423测试 https://jira.shanqu.cc/browse/GHZS-2202

See merge request halo/android/assistant-android!967
2023-04-24 18:00:15 +08:00
71f2c937db fix: 新游开测相关功能优化—0423测试 https://jira.shanqu.cc/browse/GHZS-2202 2023-04-24 17:57:21 +08:00
2a8ae9a022 Merge branch 'fix/GHZS-2204' into 'dev-5.25.0'
fix: 新游开测相关功能优化—0423UI测试 https://jira.shanqu.cc/browse/GHZS-2204

See merge request halo/android/assistant-android!966
2023-04-24 17:31:58 +08:00
3f28fcc211 fix: 新游开测相关功能优化—0423UI测试 https://jira.shanqu.cc/browse/GHZS-2204 2023-04-24 17:30:45 +08:00
dd850bdbbc Merge branch 'feature/GHZS-1512' into 'dev-5.25.0'
feat: 新增镜像tab https://jira.shanqu.cc/browse/GHZS-2200

See merge request halo/android/assistant-android!965
2023-04-24 16:39:55 +08:00
6ae8b520ac Merge branch 'fix/GHZS-2223' into 'dev-5.25.0'
fix: 普通帖/视频帖详情页相关优化—0424测试 https://jira.shanqu.cc/browse/GHZS-2223

See merge request halo/android/assistant-android!964
2023-04-24 16:29:47 +08:00
d956081d61 feat: 新增镜像tab https://jira.shanqu.cc/browse/GHZS-2200 2023-04-24 16:16:38 +08:00
fe75be35fb fix: 普通帖/视频帖详情页相关优化—0424测试 https://jira.shanqu.cc/browse/GHZS-2223 2023-04-24 16:08:04 +08:00
15d6fd98b5 Merge branch 'fix/GHZS-2149' into 'dev-5.25.0'
fix: 修改帖子详情和视频详情页标题字体大小

See merge request halo/android/assistant-android!962
2023-04-24 15:22:52 +08:00
d1d22de559 fix: 修改帖子详情和视频详情页标题字体大小 2023-04-24 15:06:06 +08:00
2f69074418 Merge branch 'feature/GHZS-2148' into 'dev-5.25.0'
feat: 专区新增搜索栏 https://jira.shanqu.cc/browse/GHZS-2148

See merge request halo/android/assistant-android!957
2023-04-24 10:52:36 +08:00
684e7a63db feat: 专区新增搜索栏 https://jira.shanqu.cc/browse/GHZS-2148 2023-04-24 10:50:55 +08:00
208c21c4ea Merge branch 'feature/GHZS-2149' into 'dev-5.25.0'
feat: 普通帖/视频帖详情页相关优化—客户端 https://jira.shanqu.cc/browse/GHZS-2149

See merge request halo/android/assistant-android!954
2023-04-23 17:34:18 +08:00
55c8fd9271 feat: 普通帖/视频帖详情页相关优化—客户端 https://jira.shanqu.cc/browse/GHZS-2149 2023-04-23 17:24:18 +08:00
664f35090d Merge branch 'feature/GHZS-2102' into 'dev-5.25.0'
fix: 消息中心—评论详情页展示错误 https://jira.shanqu.cc/browse/GHZS-2102

See merge request halo/android/assistant-android!953
2023-04-23 15:29:15 +08:00
aaec370afa fix: 消息中心—评论详情页展示错误 https://jira.shanqu.cc/browse/GHZS-2102 2023-04-23 15:21:56 +08:00
af09f28fdd Merge branch 'feature/GHZS-2101' into 'dev-5.25.0'
fix: 下载管理-解压失败点击交互 https://jira.shanqu.cc/browse/GHZS-2101

See merge request halo/android/assistant-android!952
2023-04-23 14:41:32 +08:00
00b92d2aec fix: 下载管理-解压失败点击交互 https://jira.shanqu.cc/browse/GHZS-2101 2023-04-23 14:40:08 +08:00
a90d694a48 Merge remote-tracking branch 'origin/dev' into dev-5.25.0 2023-04-21 16:57:09 +08:00
03babbfdee feat: 论坛详情页相关UI优化—客户端(1-2) https://jira.shanqu.cc/browse/GHZS-2144 2023-04-20 15:23:43 +08:00
32cf945b4d Merge branch 'feature/GHZS-2124' into 'dev-5.25.0'
feat: 徽章相关优化-第二期—客户端 https://jira.shanqu.cc/browse/GHZS-2124

See merge request halo/android/assistant-android!942
2023-04-20 11:23:59 +08:00
207813376b feat: 徽章相关优化-第二期—客户端 https://jira.shanqu.cc/browse/GHZS-2124 2023-04-20 11:04:45 +08:00
98a54ad85d Merge branch 'fix/game_icon_render_issue' into 'dev-5.25.0'
fix: 处理 GameIconView 无法预览的问题

See merge request halo/android/assistant-android!939
2023-04-19 17:36:23 +08:00
fc0a36e4b8 fix: 处理 GameIconView 无法预览的问题 2023-04-19 17:31:30 +08:00
a3a68d7550 Merge branch 'feature-ci-5.25.0' into 'dev-5.25.0'
ci: 更新 ci 配置

See merge request halo/android/assistant-android!938
2023-04-19 17:07:56 +08:00
572400a3c7 ci: 更新 ci 配置 2023-04-19 17:05:43 +08:00
8b42390175 chore: 版本更新为 5.25.0 2023-04-19 10:52:17 +08:00
ad71193089 Merge branch 'refactor-relocate_module' into 'dev-5.25.0'
refactor: 将特殊打包模块和 VPN 模块移动到 feature 目录下

See merge request halo/android/assistant-android!937
2023-04-19 10:43:36 +08:00
f631810acc refactor: 将特殊打包模块和 VPN 模块移动到 feature 目录下 2023-04-19 10:38:58 +08:00
196 changed files with 3129 additions and 1131 deletions

View File

@ -1,43 +1,155 @@
stages:
- analysis
- sendmail
# commit_sha 文件记录上一次成功流水线的commit sha用于定时计划检测是否有新代码提交有就执行流水线没有就终止流水线
cache:
# 不同的分支采用不同的 cache防止分支之间相互影响
key: "${CI_COMMIT_REF_SLUG}_commit_sha"
paths:
- commit_sha
policy: pull
## 代码检查
# 将打包&发送apk包邮件job 和代码分析job 并行执行
stages:
- build&analyze
- oss-upload&send-email
- ci_sonar_mail
# 阻止了 合并请求 或 push分支和标签的流水线。 最后的 when: always 规则运行所有其他流水线类型,包括定时计划流水线。
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
when: always
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- when: always
before_script:
# 检查是否存在 commit_sha 文件
- if [ -f commit_sha ]; then cat commit_sha; else echo "0000000" > commit_sha; fi
- export BEFORE_COMMIT_SHA=$(cat commit_sha)
# 比较commit sha ,若与上一次成功流水线的commit sha 相同,则退出流水线
- if [ "$CI_COMMIT_SHA" == "$BEFORE_COMMIT_SHA" ] && [ "$CI_PIPELINE_SOURCE" != "web" ]; then exit 137; fi
# 使用 .post 阶段使作业在流水线的末尾运行。.post 始终是流水线的最后阶段。
change_commit:
tags:
- offline-test
stage: .post
# 此job 跳过拉取git代码
variables:
GIT_STRATEGY: none
script:
# 更新 commit_sha
- if [ "$CI_COMMIT_SHA" != "$BEFORE_COMMIT_SHA" ]; then echo $CI_COMMIT_SHA > commit_sha; fi
cache:
# 不同的分支采用不同的 cache防止分支之间相互影响
key: "${CI_COMMIT_REF_SLUG}_commit_sha"
paths:
- commit_sha
policy: pull-push
allow_failure:
exit_codes: 137
android_build:
tags:
# - local-runner
- offline-test
stage: build&analyze
image: hub.shanqu.cc/library/ci-android:jdk11-sdk31-33
resource_group: android_build
variables:
GIT_SUBMODULE_STRATEGY: recursive
KUBERNETES_CPU_LIMIT: "10"
script:
- export GRADLE_USER_HOME=/home/gitlab-runner/ci-build-cache/$CI_PROJECT_PATH/.gradle
- chmod +x ./gradlew
- ./scripts/jenkins_build.sh -c
#设置打包后的产物用于job之间共享
artifacts:
paths:
- app/build/tmp/*.apk
expire_in: 48 hrs # 指定附件上载后保存的时间24h默认永久在Gitlab保存
allow_failure:
exit_codes: 137
only:
- dev
- dev-5.25.0
# 代码检查
sonarqube_analysis:
tags:
- offline-test
stage: analysis
image: sonarsource/sonar-scanner-cli:latest
dependencies: [] #禁止传递来的artifact
script:
## 获取项目的一级组和二级组和项目名作为projectKey例如projectKey=platform-backend-eci-monitor
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- sonar-scanner
-Dsonar.host.url=http://sonarqube-server.sonarqube:9000/
-Dsonar.login=be43de7264ce4c4766eb0c020373c3e74e6df257
-Dsonar.jacoco.reportPaths=target/jacoco.exec
-Dsonar.projectKey=$group
-Dsonar.projectName=$CI_PROJECT_PATH
-Dsonar.sourceEncoding=UTF-8
-Dsonar.exclusions=**/vendor/**,**/errcode/**
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
-Dsonar.gitlab.merge_request_discussion=true
-Dsonar.java.binaries=. # 如果不使用Maven或Gradle进行分析则必须手动提供测试二进制文件
only:
- dev
tags:
- offline-test
stage: build&analyze
image: sonarsource/sonar-scanner-cli:latest
dependencies: [] #禁止传递来的artifact
script:
## 获取项目的一级组和二级组和项目名作为projectKey例如projectKey=platform-backend-eci-monitor
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- sonar-scanner
-Dsonar.host.url=http://sonarqube-server.sonarqube:9000/
-Dsonar.login=be43de7264ce4c4766eb0c020373c3e74e6df257
-Dsonar.jacoco.reportPaths=target/jacoco.exec
-Dsonar.projectKey=$group
-Dsonar.projectName=$CI_PROJECT_PATH
-Dsonar.sourceEncoding=UTF-8
-Dsonar.exclusions=**/vendor/**,**/errcode/**
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
-Dsonar.gitlab.merge_request_discussion=true
-Dsonar.java.binaries=.
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
allow_failure:
exit_codes: 137
only:
- dev
- dev-5.25.0
## 发送简易检测结果报告
send_sonar_report:
tags:
- offline-test
stage: ci_sonar_mail
image: hub.shanqu.cc/library/docker:latest
# 此job 跳过拉取git代码
variables:
GIT_STRATEGY: none
script:
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- docker run -e PROJECTKEY=$group -e EMAIL=$GITLAB_USER_EMAIL -e BRANCH=$CI_COMMIT_REF_NAME --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
allow_failure:
exit_codes: 137
only:
- dev
- dev-5.25.0
oss-upload&send-email:
tags:
- offline-test
stage: sendmail
image: hub.shanqu.cc/library/docker:latest
dependencies: [] #禁止传递来的artifact
- rancher-k8s
stage: oss-upload&send-email
image: hub.shanqu.cc/devops/android-apk-oss-upload:latest
variables:
GIT_STRATEGY: none
VAULT_ADDR: https://vault.shanqu.cc # 固定值
VAULT_SECRET_PATH: prod/devops/android-apk-oss-upload # 固定值
VAULT_ROLE: android-apk-oss-upload # 固定值
ENDPOINT: "oss-cn-shenzhen-internal.aliyuncs.com" # 固定值
BUCKET: "shanqu" # 固定值
FILE_PATH: "app/build/tmp/" # APK 存放路径
Email_To_List: $EMAIL_TO_LIST # 邮件接受人列表
Email_Title: "光环助手 $CI_COMMIT_BRANCH" # 邮件标题
PIPELINE_ID: $CI_PIPELINE_ID # 流水线id
COMMIT_BRANCH: $CI_COMMIT_BRANCH # 提交分支
MAIL_MESSAGE: "[$CI_COMMIT_AUTHOR] $CI_COMMIT_MESSAGE"
needs:
- job: android_build
artifacts: true
script:
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- docker run -e PROJECTKEY=$group -e EMAIL=$GITLAB_USER_EMAIL --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
### 绑定上传参数 ###
- export OSS_PATH="release/dev/${CI_PROJECT_NAME}/$(date "+%Y/%m/%d")"
### 开启上传 ###
- /usr/local/bin/python /upload.py
### 发送邮件
- /usr/local/bin/python /ci-android-mail.py
only:
- dev
- dev-5.25.0

View File

@ -11,6 +11,7 @@ android {
String CONFIG_ID = ""
String FIRST_LAUNCH = ""
int ACTIVATE_REPORTING_RATIO = 0
buildFeatures {
viewBinding true
@ -76,6 +77,8 @@ android {
// 首次启动的跳转配置
buildConfigField "String", "FIRST_LAUNCH", "\"${FIRST_LAUNCH}\""
buildConfigField "int", "ACTIVATE_REPORTING_RATIO", "${ACTIVATE_REPORTING_RATIO}"
// All third-party appid/appkey
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
@ -294,7 +297,6 @@ dependencies {
implementation "com.lg:shortcut:${shortcut}"
compileOnly "com.github.axen1314.lancet:lancet-base:${lancet_version}"
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
@ -321,9 +323,10 @@ dependencies {
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_vpn'))
implementation(project(':module_pkg'))
// implementation(project(':feature:vpn'))
implementation(project(':feature:pkg'))
implementation(project(':feature:floating-window'))
implementation(project(':feature:beizi_startup_ad'))
}
File propFile = file('sign.properties')

View File

@ -26,7 +26,7 @@ class FlavorProviderImp : IFlavorProvider {
return channel
}
override fun init(application: Application, activity: Activity) {
override fun init(application: Application, activity: Activity, activateRatio: Int) {
// do nothing
}

View File

@ -12,7 +12,7 @@ import com.leon.channel.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
override fun init(application: Application, activity: Activity) {
override fun init(application: Application, activity: Activity, activateRatio: Int) {
GdtHelper.init(application, getChannelStr(application))
if (HaloApp.getInstance().isBrandNewInstall) {

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="user" />
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>

View File

@ -12,7 +12,7 @@ import com.leon.channel.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
override fun init(application: Application, activity: Activity) {
override fun init(application: Application, activity: Activity, activateRatio: Int) {
KuaishouHelper.init(application, getChannelStr(application))
if (HaloApp.getInstance().isBrandNewInstall) {

View File

@ -46,7 +46,8 @@
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
com.haroldadmin.whatthestack,
com.shuyu.gsyvideoplayer.armv7a,
@ -106,6 +107,7 @@
android:label="@string/app_name"
android:largeHeap="true"
android:resizeableActivity="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppCompatTheme.APP"
tools:replace="android:name,android:allowBackup"
tools:targetApi="n">
@ -119,7 +121,7 @@
android:name="io.sentry.breadcrumbs.system-events"
android:value="false" />
<service android:name = "com.gh.ndownload.NDownloadService" />
<service android:name="com.gh.ndownload.NDownloadService" />
<activity
android:name="com.gh.gamecenter.SplashScreenActivity"

View File

@ -60,7 +60,12 @@ import java.io.File
import java.io.FileOutputStream
import java.util.*
class DefaultJsApi(var context: Context, val entrance: String = "", private var mFragment: Fragment? = null) {
class DefaultJsApi(
var context: Context,
val entrance: String = "",
private var mFragment: Fragment? = null,
private var mBbsId: String? = "",
) {
private var mLoginHandler: CompletionHandler<Any>? = null
private var mDownloadWatcher: DataWatcher? = null // 下载观察者
@ -258,6 +263,24 @@ class DefaultJsApi(var context: Context, val entrance: String = "", private var
}
}
/**
* 是否为论坛详情的专区
*/
@JavascriptInterface
fun isForumZone(msg: Any): Boolean {
return !mBbsId.isNullOrEmpty()
}
/**
* 打开论坛搜索页
*/
@JavascriptInterface
fun openForumSearch(msg: Any) {
runOnUiThread {
DirectUtils.directToForumOrUserSearch(context, mBbsId ?: "", entrance.ifBlank { "内部网页" })
}
}
@JavascriptInterface
fun exitWebView(msg: Any) {
runOnUiThread { (context as Activity).finish() }

View File

@ -21,7 +21,7 @@ object FixedRateJobHelper {
private const val TIME_PERIOD: Long = 10 * 60 * 1000L
private const val LOGHUB_PERIOD: Long = 2 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 5 * 60 * 1000L
private const val REGION_SETTING_PERIOD: Long = 30 * 1000L
private const val REGION_SETTING_PERIOD: Long = 60 * 1000L
private const val VIDEO_RECORD_PERIOD: Long = 60 * 1000L
private const val DOWNLOAD_HEARTBEAT_PERIOD: Long = 60 * 1000L

View File

@ -455,7 +455,7 @@ public class BindingAdapters {
}
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity.getApk().get(0).getPackageName());
VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity);
return;
}
@ -473,10 +473,9 @@ public class BindingAdapters {
case INSTALL_NORMAL:
if (gameEntity.getApk().size() == 1) {
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
String packageName = gameEntity.getApk().get(0).getPackageName();
if (gameEntity.isVGame()) {
VHelper.installOrLaunch(v.getContext(), packageName);
VHelper.installOrLaunch(v.getContext(), gameEntity);
return;
}

View File

@ -8,6 +8,8 @@ import com.google.gson.annotations.SerializedName
class RegionSetting(
@SerializedName("game_mirror")
var mirrorGameIdSet: HashSet<String>,
@SerializedName("game_mirror2")
var mirrorGameIdSet2: HashSet<String>?,
@SerializedName("game_block")
var filterGameIdSet: HashSet<String>,
@SerializedName("channel_control")

View File

@ -23,7 +23,8 @@ object RegionSettingHelper {
private var mChannelControl: RegionSetting.ChannelControl? = null
private var mFilterGameIdSet: HashSet<String>? = hashSetOf()
private var mDisplayMirrorIfoGameIdSet: HashSet<String>? = hashSetOf()
private var mDisplayMirrorGameIdSet: HashSet<String>? = hashSetOf()
private var mDisplayMirrorGameIdSet2: HashSet<String>? = hashSetOf()
private var mGameH5DownloadList: List<RegionSetting.GameH5Download>? = listOf()
private var mGameSpecialDownloadInfoList: List<RegionSetting.GameSpecialDownloadInfo>? = listOf()
private var mIpInfo: IpInfo? = null
@ -33,7 +34,21 @@ object RegionSettingHelper {
@JvmStatic
fun shouldThisGameDisplayMirrorInfo(gameId: String): Boolean {
return mDisplayMirrorIfoGameIdSet?.contains(gameId) ?: false
return mDisplayMirrorGameIdSet?.contains(gameId) == true
|| mDisplayMirrorGameIdSet2?.contains(gameId) == true
}
/**
* 获取镜像数据的位置,是归属镜像 1 还是镜像 2
*/
fun getMirrorPosition(gameId: String): Int {
return if (mDisplayMirrorGameIdSet?.contains(gameId) == true) {
1
} else if (mDisplayMirrorGameIdSet2?.contains(gameId) == true) {
2
} else {
-1
}
}
@JvmStatic
@ -131,7 +146,8 @@ object RegionSettingHelper {
private fun updateSettingsInMemory(data: RegionSetting) {
mFilterGameIdSet = data.filterGameIdSet
mDisplayMirrorIfoGameIdSet = data.mirrorGameIdSet
mDisplayMirrorGameIdSet = data.mirrorGameIdSet
mDisplayMirrorGameIdSet2 = data.mirrorGameIdSet2
mChannelControl = data.channelControl
mGameH5DownloadList = data.gameH5DownloadList
mGameSpecialDownloadInfoList = data.gameSpecialDownloadInfoList

View File

@ -22,7 +22,7 @@ class GameDetailProviderImpl : IGameDetailProvider {
context: Context,
gameEntity: GameEntity?,
entrance: String,
defaultTab: Int,
defaultTab: String,
isSkipGameComment: Boolean,
scrollToLibao: Boolean,
scrollToServer: Boolean,

View File

@ -14,6 +14,10 @@ class RegionSettingHelperProviderImpl : IRegionSettingHelperProvider {
return RegionSettingHelper.shouldThisGameDisplayMirrorInfo(gameId)
}
override fun getMirrorPosition(gameId: String): Int {
return RegionSettingHelper.getMirrorPosition(gameId)
}
override fun shouldThisGameShowSpecialDownload(gameId: String): Boolean {
return RegionSettingHelper.shouldThisGameShowSpecialDownload(gameId)
}

View File

@ -114,7 +114,7 @@ public class DetailDownloadUtils {
if (downloadEntity == null && viewHolder.gameEntity.isVGame()) {
String packageName = viewHolder.gameEntity.getUniquePackageName();
if (!TextUtils.isEmpty(packageName)) {
downloadEntity = VHelper.getDownloadEntitySnapshot(viewHolder.gameEntity.getId(), packageName);
downloadEntity = VHelper.getVDownloadEntitySnapshot(viewHolder.gameEntity.getId(), packageName);
}
}
@ -214,7 +214,7 @@ public class DetailDownloadUtils {
if (downloadEntity == null && viewHolder.gameEntity.isVGame()) {
String packageName = viewHolder.gameEntity.getUniquePackageName();
if (!TextUtils.isEmpty(packageName)) {
downloadEntity = VHelper.getDownloadEntitySnapshot(viewHolder.gameEntity.getId(), packageName);
downloadEntity = VHelper.getVDownloadEntitySnapshot(viewHolder.gameEntity.getId(), packageName);
}
}

View File

@ -45,6 +45,7 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.forum.home.CommunityHomeFragment
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
import com.gh.gamecenter.game.commoncollection.detail.CommonCollectionDetailActivity
@ -310,13 +311,14 @@ object DirectUtils {
name = linkEntity.name,
display = linkEntity.display ?: Display()
),
entrance
entrance,
exposureEvent
)
}
"column_collection", "专题合集" -> directToColumnCollection(context, linkEntity.link!!, -1, entrance)
"server", "game_server", "开服表" -> directToGameServers(context, entrance, path)
"server", "game_server", "开服表" -> directToGameServers(context, entrance, path, exposureEvent)
"top_game_comment" -> directToAmway(context, null, entrance, path)
@ -438,11 +440,28 @@ object DirectUtils {
"game_list" -> directToGameCollectionSquare(context, entrance, "", "", "")
"game_list_detail" -> directToGameCollectionDetail(context, linkEntity.link ?: "", entrance)
"game_list_detail" -> directToGameCollectionDetail(
context,
linkEntity.link ?: "",
entrance,
exposureEvent = exposureEvent
)
"explore_column", "game_explore" -> context.startActivity(DiscoveryActivity.getIntent(context, entrance))
"explore_column", "game_explore" -> context.startActivity(
DiscoveryActivity.getIntent(
context,
entrance,
exposureEvent
)
)
"column_test_v2" -> context.startActivity(GameServerTestV2Activity.getIntent(context, entrance))
"column_test_v2" -> context.startActivity(
GameServerTestV2Activity.getIntent(
context,
entrance,
exposureEvent
)
)
"" -> {
// do nothing
@ -660,10 +679,10 @@ object DirectUtils {
bundle.putString(KEY_GAMEID, id)
if (!TextUtils.isEmpty(tab)) {
when (tab) {
"comment" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_RATING)
"desc" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_DESC)
"forum" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_BBS)
"zone" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_TRENDES)
"comment" -> bundle.putString(KEY_TARGET, GameDetailFragment.TAB_RATING)
"desc" -> bundle.putString(KEY_TARGET, GameDetailFragment.TAB_DESC)
"forum" -> bundle.putString(KEY_TARGET, GameDetailFragment.TAB_BBS)
"zone" -> bundle.putString(KEY_TARGET, GameDetailFragment.TAB_TRENDS)
}
}
if (traceEvent != null) {
@ -703,7 +722,7 @@ object DirectUtils {
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putString(KEY_GAMEID, id)
bundle.putBoolean(KEY_OPEN_VIDEO_STREAMING, true)
bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_DESC)
bundle.putString(KEY_TARGET, GameDetailFragment.TAB_DESC)
jumpActivity(context, bundle)
}
@ -711,14 +730,14 @@ object DirectUtils {
fun directToGameDetail(
context: Context,
id: String,
defaultTab: Int = GameDetailFragment.INDEX_DESC,
defaultTab: String = GameDetailFragment.TAB_DESC,
entrance: String? = null
) {
val bundle = Bundle()
bundle.putString(KEY_TO, GameDetailActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putString(KEY_GAMEID, id)
bundle.putInt(KEY_TARGET, defaultTab)
bundle.putString(KEY_TARGET, defaultTab)
jumpActivity(context, bundle)
}
@ -1352,11 +1371,17 @@ object DirectUtils {
* 跳转到板块
*/
@JvmStatic
fun directToBlock(context: Context, blockData: SubjectRecommendEntity, entrance: String) {
fun directToBlock(
context: Context,
blockData: SubjectRecommendEntity,
entrance: String,
exposureEvent: ExposureEvent? = null
) {
val bundle = Bundle()
bundle.putString(KEY_TO, BlockActivity::class.java.name)
bundle.putParcelable(KEY_BLOCK_DATA, blockData)
bundle.putString(KEY_ENTRANCE, entrance)
exposureEvent?.let { bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source)) }
jumpActivity(context, bundle)
}
@ -1364,10 +1389,11 @@ object DirectUtils {
* 跳转到开服表
*/
@JvmStatic
fun directToGameServers(context: Context, entrance: String, path: String) {
fun directToGameServers(context: Context, entrance: String, path: String, exposureEvent: ExposureEvent? = null) {
val bundle = Bundle()
bundle.putString(KEY_TO, GameServersActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, ToolBarActivity.mergeEntranceAndPath(entrance, path))
exposureEvent?.let { bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source)) }
jumpActivity(context, bundle)
}
@ -1395,7 +1421,7 @@ object DirectUtils {
response?.apply {
if (zone.status == "on") {
if (zone.style == "link") {
directToGameDetail(context, gameId, GameDetailFragment.INDEX_TRENDES, entrance)
directToGameDetail(context, gameId, GameDetailFragment.TAB_TRENDS, entrance)
} else {
directToWebView(context, url, entrance)
}
@ -1817,7 +1843,8 @@ object DirectUtils {
collectionId: String,
blockId: String = "",
blockName: String = "",
entrance: String = ""
entrance: String = "",
exposureEvent: ExposureEvent? = null
) {
if (collectionId.isEmpty()) return
val bundle = Bundle()
@ -1826,6 +1853,7 @@ object DirectUtils {
bundle.putString(KEY_BLOCK_NAME, blockName)
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putString(KEY_COLLECTION_ID, collectionId)
exposureEvent?.let { bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source)) }
jumpActivity(context, bundle)
}
@ -1861,13 +1889,20 @@ object DirectUtils {
* 跳转至游戏单详情
*/
@JvmStatic
fun directToGameCollectionDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
fun directToGameCollectionDetail(
context: Context,
id: String,
entrance: String? = null,
path: String? = null,
exposureEvent: ExposureEvent? = null
) {
if (id.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
bundle.putString(KEY_TO, GameCollectionDetailActivity::class.java.name)
bundle.putString(KEY_GAME_COLLECTION_ID, id)
exposureEvent?.let { bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source)) }
jumpActivity(context, bundle)
}
@ -1909,6 +1944,15 @@ object DirectUtils {
}
}
/**
* 跳转到论坛搜索页
* @param bbsId, 为空时搜索全范围的内容,不为空时搜索该 bbsId 对应的内容
*/
@JvmStatic
fun directToForumOrUserSearch(context: Context, bbsId: String, entrance: String) {
context.startActivity(ForumOrUserSearchActivity.getIntent(context, bbsId, entrance))
}
@JvmStatic
fun directToVGameDownload(context: Context, switchToDownloadingTab: Boolean = false) {
val bundle = Bundle()

View File

@ -29,7 +29,7 @@ object DownloadDialogHelper {
private fun retrieveAvailableDialog(gameEntity: GameEntity, apkEntity: ApkEntity): GameEntity.Dialog? {
val downloadDialog = if (gameEntity.shouldUseMirrorInfo()) {
gameEntity.mirrorData?.downloadDialog
gameEntity.obtainMirrorData()?.downloadDialog
} else {
gameEntity.downloadDialog
}

View File

@ -266,7 +266,7 @@ object DownloadItemUtils {
var downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
if (downloadEntity == null && gameEntity.isVGame()) {
downloadEntity = VHelper.getDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
downloadEntity = VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
}
if (downloadEntity == null) {
@ -884,7 +884,7 @@ object DownloadItemUtils {
}
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity.getUniquePackageName() ?: "")
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity)
} else {
install(context, gameEntity, position, adapter, refreshCallback)
}
@ -909,7 +909,7 @@ object DownloadItemUtils {
}
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity.getUniquePackageName() ?: "")
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity)
return
}

View File

@ -298,7 +298,7 @@ object GameActivityDownloadHelper {
}
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity.getUniquePackageName() ?: "")
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity)
} else {
downloadEntity?.run {
install(context, gameEntity, apk, this)
@ -336,7 +336,7 @@ object GameActivityDownloadHelper {
}
if (gameEntity.isVGame()) {
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity.getUniquePackageName() ?: "")
VHelper.installOrLaunch((context as AppCompatActivity), gameEntity)
return
}

View File

@ -107,7 +107,7 @@ public class GameUtils {
// 在下载管理找不到下载实体,并且为畅玩游戏的时候到畅玩数据库里找
if (downloadEntity == null && gameEntity.isVGame()) {
downloadEntity = VHelper.getDownloadEntitySnapshot(gameEntity.getId(), apkEntity.getPackageName());
downloadEntity = VHelper.getVDownloadEntitySnapshot(gameEntity.getId(), apkEntity.getPackageName());
}
if (downloadEntity != null) {

View File

@ -568,16 +568,19 @@ public class LogUtils {
}
public static void uploadSearchGame(String event, String location, String key, String searchType) {
uploadSearchClick(event, location, key, searchType, "", "", false, false);
uploadSearchClick(event, location, key, searchType, "", "", 0, false);
}
/**
* @param mirrorDataPosition 镜像的归类,不是镜像是为 -1 ,使用镜像 1 时为 1使用镜像 2 时为 2
*/
public static void uploadSearchClick(String event,
String location,
String key,
String searchType,
String gameId,
String gameName,
Boolean isMirrorData,
int mirrorDataPosition,
Boolean isAdData) {
JSONObject object = new JSONObject();
JSONObject payload = new JSONObject();
@ -591,7 +594,13 @@ public class LogUtils {
payload.put("search_type", searchType); //搜索类型, 有四种取值 默认搜索/历史搜索/自动搜索/主动搜索
payload.put(KEY_GAME_ID, gameId); //event为search_click才取值
payload.put(KEY_GAME_NAME, gameName); //event为search_click才取值
payload.put("is_mirror_data", isMirrorData);
// 是否使用镜像
if (mirrorDataPosition == 1) {
payload.put("is_mirror_data", true);
} else if (mirrorDataPosition == 2) {
payload.put("is_mirror2_data", true);
}
payload.put("is_ad_data", isAdData);
object.put(KEY_PAY_LOAD, payload);
} catch (JSONException e) {

View File

@ -1,6 +1,7 @@
package com.gh.common.xapk
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
@ -20,13 +21,26 @@ import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import java.lang.ref.WeakReference
object XapkDialogHelper {
private var mUnzipFailureDialogRef: WeakReference<Dialog>? = null
fun showUnzipFailureDialog(context: Context, downloadEntity: DownloadEntity, isManualAction: Boolean) {
val trigger = if (isManualAction) "手动触发" else "自动触发"
NewFlatLogUtils.logXApkUnzipFailedDialogShowed(trigger, downloadEntity.gameId, downloadEntity.name)
DialogHelper.showGuideDialog(
val previousShowedDialog = mUnzipFailureDialogRef?.get()
if (previousShowedDialog != null
&& previousShowedDialog.isShowing
&& context == previousShowedDialog.ownerActivity) {
// 上一个解压失败弹窗还在显示,当前 activity 不用再显示新的弹窗了
return
}
val dialog = DialogHelper.showGuideDialog(
context = context,
title = "",
content = "未授权允许未知来源安装、数据包格式、设备兼容性…等均可能导致解压失败。\n如果开启权限后仍未能解决,请提交反馈帮助我们改进。",
@ -107,6 +121,11 @@ object XapkDialogHelper {
},
extraConfig = DialogHelper.Config(showCloseIcon = true)
)
if (context is Activity) {
dialog?.setOwnerActivity(context)
}
mUnzipFailureDialogRef = WeakReference(dialog)
}
}

View File

@ -626,7 +626,7 @@ public class DownloadManager implements DownloadStatusListener {
}
/**
* 根据 url 获取下载任务快照 (仅保证下载状态一致)
* 根据包名获取下载任务快照 (仅保证下载状态一致)
*
* @param packageName 包名 (多包名一样时取第一个,若使用场景里有多包名,请使用 url 获取下载任务)
* @return null 表示下载列表中不存在该任务,否则返回下载任务

View File

@ -15,6 +15,7 @@ import okhttp3.Request
import okhttp3.Response
import tv.danmaku.ijk.media.exo2.ExoSourceManager
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
object ExoCacheManager {
@ -98,7 +99,9 @@ object ExoCacheManager {
.build()
var response: Response? = null
try {
response = OkHttpClient.Builder().build().newCall(request).execute()
response =
OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build()
.newCall(request).execute()
if (response!!.isSuccessful && response.body() != null) {
val length = response.body()!!.contentLength()
contentLength = if (length == 0L) -1L else length

View File

@ -27,7 +27,7 @@ class BlockActivity : DownloadToolbarActivity() {
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, BlockActivity::class.java, GameFragment::class.java)
return getTargetIntent(this, BlockActivity::class.java, GameFragment::class.java, intent?.extras)
}
override fun showDownloadMenu(): Boolean {

View File

@ -101,7 +101,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
entrance: String,
traceEvent: ExposureEvent?
) {
startGameDetailActivity(context, gameEntity, entrance, -1, traceEvent = traceEvent)
startGameDetailActivity(context, gameEntity, entrance, "", traceEvent = traceEvent)
}
/**
@ -117,7 +117,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
context: Context,
gameEntity: GameEntity?,
entrance: String,
defaultTab: Int = -1,
defaultTab: String = "",
isSkipGameComment: Boolean = false,
scrollToLibao: Boolean = false,
scrollToServer: Boolean = false,
@ -140,18 +140,18 @@ class GameDetailActivity : DownloadToolbarActivity() {
)
traceEvent.payload = payload
}
if (defaultTab != -1) {
bundle.putInt(EntranceConsts.KEY_TARGET, defaultTab)
if (defaultTab.isNotEmpty()) {
bundle.putString(EntranceConsts.KEY_TARGET, defaultTab)
}
if (isSkipGameComment) {
bundle.putBoolean(EntranceConsts.KEY_SKIP_GAME_COMMENT, true)
}
if (scrollToLibao) {
bundle.putInt(EntranceConsts.KEY_TARGET, GameDetailFragment.INDEX_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailFragment.TAB_DESC)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, true)
}
if (scrollToServer) {
bundle.putInt(EntranceConsts.KEY_TARGET, GameDetailFragment.INDEX_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailFragment.TAB_DESC)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER, true)
}
bundle.putString(EntranceConsts.KEY_GAMEID, gameEntity?.id)
@ -257,7 +257,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
if (openVideoStreaming) {
bundle.putBoolean(EntranceConsts.KEY_OPEN_VIDEO_STREAMING, true)
bundle.putInt(EntranceConsts.KEY_TARGET, GameDetailFragment.INDEX_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailFragment.TAB_DESC)
}
if (openPlatformWindow) {
bundle.putBoolean(EntranceConsts.KEY_OPEN_PLATFORM_WINDOW, true)
@ -269,7 +269,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
}
if (scrollToLibao) {
bundle.putInt(EntranceConsts.KEY_TARGET, GameDetailFragment.INDEX_TRENDES)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailFragment.TAB_DESC)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, true)
}
bundle.putString(EntranceConsts.KEY_GAMEID, gameId)

View File

@ -861,7 +861,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
imageView.setOnLongClickListener {
// 下滑的时候不弹
if (imageView.isDragging()) {
return@setOnLongClickListener false
return@setOnLongClickListener true
}
val dialog = Dialog(this@ImageViewerActivity)
@ -897,7 +897,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
}
dialog.cancel()
}
false
true
}
view.tag = position
container.addView(view)

View File

@ -26,7 +26,6 @@ import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.preference.PreferenceManager;
@ -34,6 +33,7 @@ import android.text.Html;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -43,6 +43,7 @@ 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.common.constant.Config;
@ -76,6 +77,7 @@ 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;
@ -90,6 +92,7 @@ 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;
@ -189,6 +192,8 @@ public class MainActivity extends BaseActivity {
private final Handler handler = new Handler();
public boolean showAd = false; // 是否显示广告
private IStartUpAdProvider mStartUpAdProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
showAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null;
@ -469,6 +474,8 @@ public class MainActivity extends BaseActivity {
protected void onDestroy() {
super.onDestroy();
if (mStartUpAdProvider != null) mStartUpAdProvider.cancelStartUpAd(this);
handler.removeCallbacksAndMessages(null);
releaseExoSourceCache();
}
@ -502,8 +509,17 @@ public class MainActivity extends BaseActivity {
showStartUp(startUp);
AppExecutor.getUiExecutor().executeWithDelay(() -> {
hideStartUp();
observeStartUpAd();
initStartUpAd();
}, 2000);
} else {
initStartUpAd();
}
}
private void initStartUpAd() {
mStartUpAdProvider = (IStartUpAdProvider) ARouter.getInstance().build(RouteConsts.provider.adSdk).navigation();
if (mStartUpAdProvider != null && mStartUpAdProvider.shouldEnableSDK(HaloApp.getInstance().getChannel())) {
initSDKStartUpAd();
} else {
observeStartUpAd();
}
@ -597,6 +613,12 @@ public class MainActivity extends BaseActivity {
startAdContainer.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(startAdContainer);
}
View startSdkAdContainer = findViewById(R.id.sdkStartAdContainer);
if (startSdkAdContainer != null) {
startSdkAdContainer.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(startSdkAdContainer);
if (mStartUpAdProvider != null) mStartUpAdProvider.cancelStartUpAd(this);
}
checkDialog();
}
@ -654,6 +676,18 @@ public class MainActivity extends BaseActivity {
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) {
TextView adContentTv = findViewById(R.id.adContentTv);
View containerView = findViewById(R.id.maskContainer);

View File

@ -58,6 +58,7 @@ 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.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;
@ -327,11 +328,11 @@ public class SkipActivity extends BaseActivity {
entity.setLink(path);
entity.setName(name);
entity.setText(name);
DirectUtils.directToBlock(this, entity, mEntrance);
DirectUtils.directToBlock(this, entity, mEntrance, null);
break;
case EntranceConsts.HOST_SERVER_BLOCK:
DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器");
DirectUtils.directToGameServers(this, ENTRANCE_BROWSER, "浏览器", null);
break;
case EntranceConsts.HOST_AMWAY_BLOCK:
@ -399,7 +400,7 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
break;
case HOST_GAME_COLLECTION_DETAIL:
DirectUtils.directToGameCollectionDetail(this, path, ENTRANCE_BROWSER, "");
DirectUtils.directToGameCollectionDetail(this, path, ENTRANCE_BROWSER, "", null);
break;
case HOST_GAME_COLLECTION_SQUARE:
DirectUtils.directToGameCollectionSquare(this, ENTRANCE_BROWSER, "", "", "");
@ -450,6 +451,12 @@ public class SkipActivity extends BaseActivity {
finish();
}
});
if (SkipActivity.this.isFinishing()) {
ToastUtils.toast("创建桌面图标失败,请重试");
return;
}
dialog.show();
}

View File

@ -21,7 +21,6 @@ import com.alibaba.android.arouter.launcher.ARouter
import com.g00fy2.versioncompare.Version
import com.gh.common.dialog.NewPrivacyPolicyDialogFragment
import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.util.GameSubstituteRepositoryHelper.updateGameSubstituteRepository
import com.gh.common.util.UsageStatsHelper.checkAndPostUsageStats
import com.gh.download.DownloadManager
@ -29,10 +28,12 @@ import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.callback.SimpleCallback
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.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
@ -62,6 +63,9 @@ 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,
@ -294,19 +298,45 @@ class SplashScreenActivity : BaseActivity() {
overridePendingTransition(0, 0)
startActivity(intent)
doFlavorInit()
initStartUpAdSDK()
logAppLaunch()
finish()
}
private fun doFlavorInit() {
HaloApp.getInstance().flavorProvider.init(HaloApp.getInstance(), this)
HaloApp.getInstance().flavorProvider.init(HaloApp.getInstance(), this, PkgHelper.getActivateRatio())
// 仅官网渠道和测试包启用神策
if ("GH_206" == HaloApp.getInstance().channel || PackageFlavorHelper.IS_TEST_FLAVOR) {
val whiteListChannel = arrayListOf<String>(
"GH_206",
"KS-GHZS-KY1",
"KS-GHZS-MC1",
"GDT_GHZS_MC1",
"T11-GH-APPDY-ZC01",
"T7-GH-APPDY-KY03",
"T8-GH-APPUX-KY04",
"T1-GHZS-MC01",
"T4-GHZS-MC03"
)
if (whiteListChannel.contains(HaloApp.getInstance().channel) || PackageFlavorHelper.IS_TEST_FLAVOR) {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
}
}
private fun initStartUpAdSDK() {
mStartUpAdProvider?.run {
if (shouldEnableSDK(HaloApp.getInstance().channel)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
initOAID(applicationContext) {
HaloApp.getInstance().oaid = it
MetaUtil.refreshMeta()
}
}
initSDK(applicationContext)
}
}
}
private fun getGitLogString(): String {
if (com.gh.gamecenter.common.BuildConfig.BUILD_TIME != 0L) {
val stringBuilder = StringBuilder()

View File

@ -324,7 +324,11 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
if (mLibaoDetailEntity.getTime() != null) {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm", Locale.CHINA);
String start = format.format((mLibaoDetailEntity.getTime().getStart() * 1000));
String end = format.format((mLibaoDetailEntity.getTime().getEnd() * 1000));
long libaoLingEndTime = mLibaoDetailEntity.getTime().getEnd();
String end = libaoLingEndTime == 0
? mContext.getString(R.string.libao_ling_time_infinitely) // 礼包领取结束时间为空则表示礼包长期有效
: format.format((mLibaoDetailEntity.getTime().getEnd() * 1000));
holder.binding.libaodetailTimeStart.setText(StringUtils.buildString("开始时间:", start));
holder.binding.libaodetailTimeEnd.setText(StringUtils.buildString("截止时间:", end));

View File

@ -346,7 +346,7 @@ public class DetailViewHolder {
}
if (mGameEntity.isVGame()) {
VHelper.installOrLaunch(mViewHolder.context, mGameEntity.getApk().get(0).getPackageName());
VHelper.installOrLaunch(mViewHolder.context, mGameEntity);
return;
}
@ -388,7 +388,7 @@ public class DetailViewHolder {
}
if (mGameEntity.isVGame()) {
VHelper.installOrLaunch(v.getContext(), mGameEntity.getApk().get(0).getPackageName());
VHelper.installOrLaunch(v.getContext(), mGameEntity);
return;
}

View File

@ -210,7 +210,7 @@ class AuthorizationActivity : ToolBarActivity() {
private fun backToLaunchApp(showLoading: Boolean = true) {
val gamePkg = mGamePkg
if (gamePkg != null) { // 跳转回游戏
VHelper.launch(this, gamePkg, showLoading = showLoading)
VHelper.launch(this, gamePkg, ignoreGApps = true, showLoading = showLoading)
return
}
val remotePkgName = this.mRemotePkgName

View File

@ -43,14 +43,14 @@ class SpecialCatalogSubjectCollectionAdapter(
}
val entity = mList[position]
ImageUtils.display(subjectCollectionImage, entity.image)
subjectCollectionImage.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
subjectCollectionImage.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
subjectCollectionImage.layoutParams = subjectCollectionImage.layoutParams.apply {
height = 96F.dip2px()
width = (subjectCollectionImage.aspectRatio * 96F.dip2px()).toInt()
}
}
}
})
root.setOnClickListener {
DirectUtils.directToLinkPage(
mContext,

View File

@ -338,7 +338,7 @@ class CloudArchiveManagerActivity : BaseActivity_TabLayout() {
btnText = getString(R.string.launch)
setOnClickListener {
CurrentActivityHolder.getCurrentActivity()?.let {
VHelper.installOrLaunch(it, downloadEntity.packageName)
VHelper.installOrLaunch(it, downloadEntity)
}
}
}

View File

@ -7,6 +7,9 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import java.util.ArrayList
/**
* 猜你喜欢-发现页
@ -27,9 +30,15 @@ class DiscoveryActivity : ToolBarActivity() {
}
companion object {
fun getIntent(context: Context, entrance: String): Intent {
fun getIntent(context: Context, entrance: String, exposureEvent: ExposureEvent? = null): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
exposureEvent?.let {
bundle.putParcelableArrayList(
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST,
ArrayList(exposureEvent.source)
)
}
return getTargetIntent(context, DiscoveryActivity::class.java, DiscoveryFragment::class.java, bundle)
}
}

View File

@ -151,6 +151,8 @@ class DiscoveryFragment : LazyListFragment<DiscoveryItemData, DiscoveryViewModel
override fun provideListAdapter(): ListAdapter<*> {
val basicExposureSource = arrayListOf<ExposureSource>().apply {
arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE)?.let { add(it) }
arguments?.getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
?.let { addAll(it) }
}
val outerSequence = requireArguments().getInt(EntranceConsts.KEY_POSITION, -1)

View File

@ -52,7 +52,10 @@ class ForumDetailEntity(
@SerializedName("_id")
var id: String = "",
var name: String = "",
var permissions: String = ""
var permissions: String = "",
var icon: String = "",
@SerializedName("icon_type")
var iconType: String = ""
) : Parcelable
fun convertForumDetailEntityToForumEntity(): ForumEntity {

View File

@ -41,6 +41,10 @@ data class SubjectRecommendEntity(
var display: Display = Display(),
var img: String? = "",
@SerializedName("tab_show_img")
var showImgOnSelected: Boolean? = false, // 选中时是否显示图片
// local variable
var useLightStyle: Boolean = false,
var primaryColor: Int = Color.WHITE,

View File

@ -5,6 +5,7 @@ import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
@ -14,10 +15,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import android.widget.*
import androidx.annotation.RequiresApi
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
@ -57,6 +55,7 @@ import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.FragmentForumDetailBinding
import com.gh.gamecenter.databinding.ItemForumSectionBinding
import com.gh.gamecenter.databinding.PopupForumDetailSectionsBinding
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBForumFollowChange
@ -75,6 +74,7 @@ import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayout
import com.halo.assistant.fragment.WebFragment
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@ -171,6 +171,8 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
return FragmentStateAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
}
override fun provideIndicatorWidth(): Int = 16
override fun getInflatedLayout(): View {
mBinding = FragmentForumDetailBinding.bind(layoutInflater.inflate(R.layout.fragment_forum_detail, null, false))
return mBinding.root
@ -373,6 +375,73 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
LogUtils.uploadAccessToBbs(mBbsId, "论坛详情")
}
override fun onFragmentFirstVisible() {
mTabTitleList.clear()
mFragmentsList.clear()
initTabTitleList(mTabTitleList)
mFragmentsList.addAll(restoreFragments())
if (mFragmentsList.isEmpty() || mFragmentsList.size != mTabTitleList.size) {
mFragmentsList.clear()
initFragmentList(mFragmentsList)
}
mViewPager.offscreenPageLimit = mFragmentsList.size
mViewPager.addOnPageChangeListener(this)
mViewPager.adapter = providePagerAdapter()
mViewPager.currentItem = mCheckedIndex
mTabLayout.setupWithViewPager(mViewPager)
mTabIndicatorView.setupWithTabLayout(mTabLayout)
mTabIndicatorView.setupWithViewPager(mViewPager)
mTabIndicatorView.setIndicatorWidth(provideIndicatorWidth())
initTabLayout()
mTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
updateTabStyle(tab, true)
}
override fun onTabUnselected(tab: TabLayout.Tab) {
updateTabStyle(tab, false)
}
override fun onTabReselected(tab: TabLayout.Tab) {
updateTabStyle(tab, true)
}
})
}
private fun initTabLayout() {
for (i in 0 until mTabLayout.tabCount) {
val tab = mTabLayout.getTabAt(i)
if (tab != null) {
tab.customView =
BaseFragment_TabLayout.createDefaultTabCustomView(requireContext(), tab.text.toString())
updateTabStyle(tab, i == mViewPager.currentItem)
}
}
}
private fun updateTabStyle(tab: TabLayout.Tab, isChecked: Boolean) {
tab.customView?.findViewById<TextView>(R.id.tab_title)?.run {
if (mShowZone && text == mTabTitleList[INDEX_TRENDS]) {
compoundDrawablePadding = 2F.dip2px()
setDrawableStart(
AppCompatResources.getDrawable(
requireContext(),
if (isChecked) R.drawable.icon_raiders_selected else R.drawable.icon_raiders_default
)
)
}
textSize = 16F
setTextColor(
if (isChecked) R.color.text_title.toColor(requireContext()) else R.color.text_subtitle.toColor(
requireContext()
)
)
typeface = if (isChecked) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
}
}
private fun initSection() {
val sectionLayoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
mForumSectionAdapter = ForumSectionAdapter(requireContext(), mViewModel!!) {
@ -394,7 +463,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
mViewModel?.sectionListLiveData?.observe(this) {
if (!it.isNullOrEmpty() && it.size >= 2) {
mShowSections = true
mBinding.sectionContainer.visibility = View.VISIBLE
mBinding.sectionContainer.goneIf(mViewPager.currentItem != INDEX_ALL)
if (mSectionId.isNotEmpty()) {
it.forEachIndexed { index, section ->
if (section.id == mSectionId) {
@ -569,6 +638,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
webBundle.putString(EntranceConsts.KEY_ENTRANCE, "游戏专区")
webBundle.putString(EntranceConsts.KEY_URL, it.link)
webBundle.putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, true)
webBundle.putString(EntranceConsts.KEY_BBS_ID, mBbsId)
webBundle.putString(EntranceConsts.KEY_PATH, TAB_TRENDS)
webFragment.arguments = webBundle
mTrendsFragment = webFragment
@ -586,6 +656,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
mViewPager.adapter?.notifyDataSetChanged()
mAskIndex = INDEX_ASK + 1
mVideoIndex = INDEX_VIDEO + 1
initTabLayout()
if (arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_TRENDS, false) == true) {
mViewPager.currentItem = INDEX_TRENDS
@ -1016,12 +1087,12 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
).apply { mPopupWindow = this }
mViewModel?.sectionListLiveData?.value?.forEachIndexed { index, section ->
val item = getItemTextView(section.name)
val item = getSectionItemView(section)
binding.flexbox.addView(item)
item.tag = section.name
toggleHighlightedTextView(item, mViewModel?.selectedSection?.id == section.id)
toggleHighlightedView(item, mViewModel?.selectedSection?.id == section.id)
item.setOnClickListener {
toggleHighlightedTextView(item, true)
toggleHighlightedView(item, true)
mViewModel?.selectedSection = section
setSection(index)
mForumSectionAdapter?.run {
@ -1046,25 +1117,30 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
popupWindow.showAsDropDown(mBinding.tabContainer, 0, 0)
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
private fun toggleHighlightedView(targetView: View, highlightIt: Boolean) {
val sectionTv = targetView.findViewById<TextView>(R.id.sectionTv)
if (highlightIt) {
targetTextView.background = R.drawable.button_round_primary_light.toDrawable(requireContext())
targetTextView.setTextColor(R.color.theme_font.toColor(requireContext()))
targetView.background = R.drawable.button_round_primary_light.toDrawable(requireContext())
sectionTv?.setTextColor(R.color.theme_font.toColor(requireContext()))
} else {
targetTextView.background = R.drawable.button_round_gray_light.toDrawable(requireContext())
targetTextView.setTextColor(R.color.text_subtitle.toColor(requireContext()))
targetView.background = R.drawable.button_round_gray_light.toDrawable(requireContext())
sectionTv?.setTextColor(R.color.text_subtitle.toColor(requireContext()))
}
}
private fun getItemTextView(name: String): TextView {
return TextView(requireContext()).apply {
text = name
includeFontPadding = false
textSize = 12F
gravity = Gravity.CENTER
setPadding(12F.dip2px(), 0, 12F.dip2px(), 0)
val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 24F.dip2px())
layoutParams = params
private fun getSectionItemView(entity: ForumDetailEntity.Section): View {
return ItemForumSectionBinding.bind(
LayoutInflater.from(requireContext()).inflate(R.layout.item_forum_section, null)
).apply {
iconIv.goneIf(entity.iconType.isEmpty() || entity.iconType == "none")
when {
entity.iconType == "url" && entity.icon.isNotEmpty() -> ImageUtils.display(iconIv, entity.icon)
entity.iconType == "new" -> ImageUtils.display(iconIv, R.drawable.icon_section_newest)
entity.iconType == "hot" -> ImageUtils.display(iconIv, R.drawable.icon_section_heat)
}
sectionTv.text = entity.name
}.root.apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 24F.dip2px())
}
}
@ -1143,7 +1219,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
for (i in 0 until mBinding.fragmentTabLayout.tabCount) {
val tab = mBinding.fragmentTabLayout.getTabAt(i)
if (tab != null) {
BaseFragment_TabLayout.updateTabStyle(tab, tab.isSelected)
updateTabStyle(tab, tab.isSelected)
}
}
mForumSectionAdapter?.let { it.notifyItemRangeChanged(0, it.itemCount) }

View File

@ -5,10 +5,7 @@ import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toDrawable
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.ItemForumSectionBinding
import com.gh.gamecenter.entity.ForumDetailEntity
import com.lightgame.adapter.BaseRecyclerAdapter
@ -30,26 +27,38 @@ class ForumSectionAdapter(context: Context, val viewModel: ForumDetailViewModel,
override fun onBindViewHolder(holder: ForumSectionItemViewHolder, position: Int) {
val entity = mSectionList[position]
holder.binding.root.run {
layoutParams = (layoutParams as MarginLayoutParams).apply {
leftMargin = if (position == 0) 16F.dip2px() else 6F.dip2px()
}
holder.binding.iconIv.goneIf(entity.iconType.isEmpty() || entity.iconType == "none")
when {
entity.iconType == "url" && entity.icon.isNotEmpty() -> ImageUtils.display(
holder.binding.iconIv,
entity.icon
)
entity.iconType == "new" -> ImageUtils.display(holder.binding.iconIv, R.drawable.icon_section_newest)
entity.iconType == "hot" -> ImageUtils.display(holder.binding.iconIv, R.drawable.icon_section_heat)
}
holder.binding.sectionTv.run {
text = entity.name
setTextColor(
if (entity.id == viewModel.selectedSection.id) R.color.theme_font.toColor(mContext) else R.color.text_subtitle.toColor(
mContext
)
)
background =
if (entity.id == viewModel.selectedSection.id) R.drawable.button_round_primary_light.toDrawable(mContext) else R.drawable.button_round_gray_light.toDrawable(
mContext
)
setOnClickListener {
viewModel.selectedSection = entity
notifyItemRangeChanged(0, itemCount)
onClick.invoke(position)
}
}
holder.binding.root.run {
layoutParams = (layoutParams as MarginLayoutParams).apply {
leftMargin = if (position == 0) 16F.dip2px() else 6F.dip2px()
}
background =
if (entity.id == viewModel.selectedSection.id) R.drawable.button_round_primary_light.toDrawable(mContext) else R.drawable.button_round_gray_light.toDrawable(
mContext
)
}
}
class ForumSectionItemViewHolder(val binding: ItemForumSectionBinding) : RecyclerView.ViewHolder(binding.root)

View File

@ -386,4 +386,9 @@ class ArticleItemVideoView @JvmOverloads constructor(context: Context, attrs: At
fun getCurrentPosition(): Long {
return mCurrentPosition
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
mMuteDisposable?.dispose()
}
}

View File

@ -8,6 +8,7 @@ import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.debugOnly
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.entity.HomeDataEntity
@ -26,12 +27,19 @@ class HomeSearchToolWrapperViewModel(application: Application) : AndroidViewMode
val homeDataLiveData = MutableLiveData<HomeDataEntity>()
val error = MutableLiveData<Exception>()
private var mHomeTabPosition: Int = -1
private var mHomeTab: SubjectRecommendEntity? = null
var appBarOffset = 0
init {
getHomeContentUnion()
}
fun getHomeTabEntity() = mHomeTab
fun getHomeTabPosition() = mHomeTabPosition
@SuppressLint("CheckResult")
fun getHomeContentUnion(isRefresh: Boolean = false) {
RetrofitManager.getInstance().api
@ -55,6 +63,8 @@ class HomeSearchToolWrapperViewModel(application: Application) : AndroidViewMode
tab.isSlideEmpty = true
tab.isTopViewShow = false
}
mHomeTab = tab
mHomeTabPosition = index
}
if (tab.type == "bbs") {

View File

@ -111,7 +111,7 @@ class WelcomeDialogFragment : BaseDialogFragment() {
dismissAllowingStateLoss()
}
binding.ivOpeningCover.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
binding.ivOpeningCover.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
binding.root.post {
if (binding.ivOpeningCover.measuredHeight > binding.root.resources.displayMetrics.heightPixels * .8) {
@ -121,7 +121,7 @@ class WelcomeDialogFragment : BaseDialogFragment() {
}
}
}
}
})
binding.ivCloseBackup.setOnClickListener {
dismissAllowingStateLoss()

View File

@ -136,6 +136,9 @@ class GameFragment : LazyFragment() {
arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE)?.let {
add(it)
}
arguments?.getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)?.let {
addAll(it)
}
add(
ExposureSource(
"板块",

View File

@ -45,7 +45,7 @@ class GameColumnCollectionAdapter(
val data = mSubjectEntity.data!![position]
ImageUtils.display(holder.binding.columnCollectionImage, data.image)
holder.binding.columnCollectionImage.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
holder.binding.columnCollectionImage.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
holder.binding.columnCollectionImage.layoutParams =
holder.binding.columnCollectionImage.layoutParams.apply {
@ -53,7 +53,7 @@ class GameColumnCollectionAdapter(
width = (holder.binding.columnCollectionImage.aspectRatio * columnCollectionHeight).toInt()
}
}
}
})
holder.binding.columnCollectionImage.setOnClickListener {
mClickClosure(position, data)

View File

@ -14,7 +14,8 @@ class CommonCollectionDetailActivity : ToolBarActivity() {
return getTargetIntent(
this,
CommonCollectionDetailActivity::class.java,
CommonCollectionDetailFragment::class.java
CommonCollectionDetailFragment::class.java,
intent?.extras
)
}

View File

@ -28,7 +28,8 @@ class CommonCollectionDetailAdapter(
val mViewModel: CommonCollectionDetailViewModel,
val mBlockId: String,
val mBlockName: String,
val mEntrance: String
val mEntrance: String,
private val mBasicExposureSource: List<ExposureSource>?
) : ListAdapter<CommonCollectionContentEntity>(context), IExposable {
private val mExposureEventSparseArray = SparseArray<ExposureEvent>()
@ -98,13 +99,14 @@ class CommonCollectionDetailAdapter(
if (linkEntity.type == "game") {
mExposureEventSparseArray.put(
position,
ExposureEvent.createEvent(
ExposureEvent.createEventWithSourceConcat(
GameEntity(
id = linkEntity.link,
name = linkEntity.name
).also {
it.sequence = position
},
basicSource = mBasicExposureSource ?: listOf(),
listOf(
ExposureSource(
"内容合集",

View File

@ -21,6 +21,7 @@ import com.gh.gamecenter.common.view.GridSpacingItemDecoration
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.databinding.FragmentListBaseSkeletonBinding
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.feature.exposure.ExposureSource
class CommonCollectionDetailFragment : LazyListFragment<LinkEntity, CommonCollectionDetailViewModel>() {
@ -47,13 +48,16 @@ class CommonCollectionDetailFragment : LazyListFragment<LinkEntity, CommonCollec
override fun provideListAdapter(): ListAdapter<*> {
if (mAdapter == null) {
val exposureEvent =
requireArguments().getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
mAdapter = CommonCollectionDetailAdapter(
requireContext(),
mCollectionStyle,
mViewModel,
mBlockId,
mBlockName,
mEntrance
mEntrance,
exposureEvent
)
}
return mAdapter!!

View File

@ -102,9 +102,9 @@ import org.greenrobot.eventbus.ThreadMode
import retrofit2.HttpException
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.abs
// TODO 更改现有的使用 INDEX_DESC, INDEX_BBS 等固定数值来确定 tab 位置的做法,避免后续更改 tab 位置出现奇怪的异常
class GameDetailFragment : ToolbarFragment(), IScrollable {
private var mDownloadMenuIcon: ImageView? = null
@ -118,7 +118,6 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private var mSearchMenuItem: MenuItem? = null
private var mDownloadMenuItem: MenuItem? = null
private var mTraceEvent: ExposureEvent? = null
private var mFirstTimeSelected = true
private var mIsTouchScreen = false
private var mIsShowKaifuHint: Boolean = false
private var mIsScrollToKaiFu: Boolean = false
@ -150,6 +149,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private val mFragmentsList = ArrayList<Fragment>()
private val mTabTitleList = ArrayList<String>()
private val mTabTypeList = ArrayList<String>() // tab 类型的列表,用于确定某个类型的 tab 在第几个位置
private val mLooperHandle = LooperHandle(this)
private val mServerLooperKey = 123
@ -217,6 +217,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
detailViewHolder.mDownloadTips.setDownloadTipsAnimation(true)
}
}
DownloadStatus.done,
DownloadStatus.pause,
DownloadStatus.waiting,
@ -227,6 +228,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
detailViewHolder.mDownloadTips.visibility = View.VISIBLE
detailViewHolder.mDownloadTips.setDownloadTipsAnimation(false)
}
else -> detailViewHolder.mDownloadTips.visibility = View.GONE
}
}
@ -275,6 +277,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
)
}
}
"func_libao" -> {
mBodyBinding.gamedetailVp.currentItem = 0
mBodyBinding.gamedetailAppbar.setExpanded(false, true)
@ -283,6 +286,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
fragment.scrollToLibao()
}
}
"func_related_version" -> {
mBodyBinding.gamedetailVp.currentItem = 0
mBodyBinding.gamedetailAppbar.setExpanded(false, true)
@ -291,6 +295,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
fragment.scrollToRelatedVersion()
}
}
"func_zone" -> {
val gameDetailEntity = mViewModel.gameDetailLiveData.value?.data
if (contentCardEntity.zoneTab && gameDetailEntity?.zone != null && gameDetailEntity.zone!!.style == "link") {
@ -303,12 +308,14 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
)
}
}
"func_bbs" -> {
val funcBbs = contentCardEntity.funcBbs
funcBbs?.let {
DirectUtils.directForumDetail(requireContext(), it.link, path)
}
}
"func_tool_kit" -> {
if (contentCardEntity.toolkit.isNotEmpty()) {
contentCardEntity.toolkit.safelyGetInRelease(0)?.let {
@ -329,6 +336,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
}
}
else -> DirectUtils.directToLinkPage(
requireContext(),
contentCardEntity.toLinkEntity(),
@ -336,7 +344,10 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
path,
ExposureEvent.createEvent(
null,
listOf(ExposureSource("游戏详情", mGameEntity?.id ?: ""), ExposureSource("内容卡片", contentCardEntity.id))
listOf(
ExposureSource("游戏详情", mGameEntity?.id ?: ""),
ExposureSource("内容卡片", contentCardEntity.id)
)
)
)
}
@ -420,7 +431,6 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mAutoDownload = args.getBoolean(EntranceConsts.KEY_AUTO_DOWNLOAD)
mTraceEvent = args.getParcelable(EntranceConsts.KEY_TRACE_EVENT)
mSkipGameComment = args.getBoolean(EntranceConsts.KEY_SKIP_GAME_COMMENT)
mDestinationTab = if (mDestinationTab >= 0) mDestinationTab else args.getInt(EntranceConsts.KEY_TARGET, -1)
mIsOpenPlatformWindow = args.getBoolean(EntranceConsts.KEY_OPEN_PLATFORM_WINDOW)
mSkeleton = Skeleton.bind(mBinding.listSkeleton)
@ -445,13 +455,10 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mBodyBinding.gamedetailVp.doOnPageSelected { position ->
if (!isAdded) return@doOnPageSelected
mBinding.gamedetailKaifuHint.visibleIf(mIsShowKaifuHint && position == INDEX_TRENDES)
mBinding.gamedetailKaifuHint.visibleIf(mIsShowKaifuHint && position == getTabPositionFromTabType(TAB_TRENDS))
val bbsPosition = getTabPositionFromTabName(getString(R.string.game_detail_bbs))
val trendsPosition = getTabPositionFromTabName(
if (mNewGameDetailEntity?.zone?.customName.isNullOrEmpty()) getString(R.string.game_detail_dongtai) else mNewGameDetailEntity?.zone?.customName
?: ""
)
val bbsPosition = getTabPositionFromTabType(TAB_BBS)
val trendsPosition = getTabPositionFromTabType(TAB_TRENDS)
if (mNewGameDetailEntity?.bbsTab != null && position == bbsPosition) {
DirectUtils.directToLinkPage(
@ -468,7 +475,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}, 200)
} else if (mNewGameDetailEntity?.zone != null && mNewGameDetailEntity?.zone?.style != "default" && position == trendsPosition && mNewGameDetailEntity?.bbsTab != null) {
// 跳转论坛-专区
val entrance = if (mDestinationTab == INDEX_TRENDES) {
val entrance = if (mDestinationTab == getTabPositionFromTabType(TAB_TRENDS)) {
if (mEntrance.contains("搜索")) "搜索页面" else "其他"
} else "游戏详情页"
mNewGameDetailEntity?.bbsTab?.link?.let {
@ -755,6 +762,9 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
val viewHolder = detailViewHolder
DetailDownloadUtils.detailInitDownload(viewHolder, true)
mDestinationTab =
getTabPositionFromTabType(arguments?.getString(EntranceConsts.KEY_TARGET, TAB_DESC) ?: TAB_DESC)
// destinationTab 的优先级最高,关注和关联关注在它的后面
if (mDestinationTab != -1) {
tabPerformClick(mDestinationTab)
@ -855,6 +865,8 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
@SuppressLint("ClickableViewAccessibility")
private fun initViewPage(data: NewGameDetailEntity) {
// 各个 tab 显示的顺序为:详情>云存档>评价>专区>论坛
val scrollToLibao = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO) ?: false
var scrollToServer = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER) ?: false
@ -889,18 +901,37 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mTabTitleList.clear()
val tag = "android:switcher:${mBodyBinding.gamedetailVp.id}:"
val descFragment = childFragmentManager.findFragmentByTag("${tag}$INDEX_DESC") ?: DescFragment()
val descFragment = childFragmentManager.findFragmentByTag("${tag}$TAB_DESC") ?: DescFragment()
descFragment.arguments = bundle
mFragmentsList.add(descFragment)
mTabTitleList.add(getString(R.string.game_detail_desc))
mTabTypeList.add(TAB_DESC)
if (data.showArchive) {
val cloudArchiveFragment =
childFragmentManager.findFragmentByTag("${tag}${TAB_ARCHIVE}") ?: CloudArchiveFragment()
bundle.putParcelable(EntranceConsts.KEY_GAME, mGameEntity ?: GameEntity())
bundle.putString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, data.archiveTab.configUrl)
cloudArchiveFragment.arguments = bundle
mFragmentsList.add(cloudArchiveFragment)
mTabTitleList.add(getString(R.string.game_detail_cloud_archive))
mTabTypeList.add(TAB_ARCHIVE)
NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
"cloud_save_tab_show",
mGameEntity?.id ?: "",
mGameEntity?.name ?: ""
)
}
if (data.showComment) {
val ratingFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_RATING}") ?: RatingFragment()
val ratingFragment = childFragmentManager.findFragmentByTag("${tag}${TAB_RATING}") ?: RatingFragment()
bundle.putBoolean(EntranceConsts.KEY_SKIP_GAME_COMMENT, mSkipGameComment)
bundle.putBoolean(EntranceConsts.KEY_DIRECT_COMMENT, data.directComment)
ratingFragment.arguments = bundle
mFragmentsList.add(ratingFragment)
mTabTitleList.add(getString(R.string.game_detail_comment))
mTabTypeList.add(TAB_RATING)
}
data.zone?.let {
@ -911,7 +942,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mFragmentsList.add(Fragment())
} else if (it.style == "link") {
//显示web页面
val webFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_TRENDES}") ?: WebFragment()
val webFragment = childFragmentManager.findFragmentByTag("${tag}${TAB_TRENDS}") ?: WebFragment()
val webBundle = Bundle()
webBundle.putString(EntranceConsts.KEY_ENTRANCE, "游戏专区")
webBundle.putString(EntranceConsts.KEY_URL, it.link)
@ -919,7 +950,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
webFragment.arguments = webBundle
mFragmentsList.add(webFragment)
} else {
val fuliFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_TRENDES}") ?: FuLiFragment()
val fuliFragment = childFragmentManager.findFragmentByTag("${tag}${TAB_TRENDS}") ?: FuLiFragment()
fuliFragment.arguments = bundle
mFragmentsList.add(fuliFragment)
}
@ -928,22 +959,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
} else {
mTabTitleList.add(getString(R.string.game_detail_dongtai))
}
}
if (data.showArchive) {
val cloudArchiveFragment =
childFragmentManager.findFragmentByTag("${tag}${INDEX_ARCHIVE}") ?: CloudArchiveFragment()
bundle.putParcelable(EntranceConsts.KEY_GAME, mGameEntity ?: GameEntity())
bundle.putString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, data.archiveTab.configUrl)
cloudArchiveFragment.arguments = bundle
mFragmentsList.add(cloudArchiveFragment)
mTabTitleList.add(getString(R.string.game_detail_cloud_archive))
NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
"cloud_save_tab_show",
mGameEntity?.id ?: "",
mGameEntity?.name ?: ""
)
mTabTypeList.add(TAB_TRENDS)
}
var isShowBbs = true
@ -957,6 +973,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
if (isShowBbs && mGameEntity?.shouldUseMirrorInfo() == false) {
mFragmentsList.add(Fragment())
mTabTitleList.add(getString(R.string.game_detail_bbs))
mTabTypeList.add(TAB_BBS)
}
}
@ -969,7 +986,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
gamedetailVp.doOnPageSelected {
logTabClick(it)
}
gamedetailVp.currentItem = INDEX_DESC
gamedetailVp.currentItem = getTabPositionFromTabType(TAB_DESC)
mBodyBinding.tabLayout.setupWithViewPager(gamedetailVp)
mBodyBinding.tabIndicator.setupWithTabLayout(mBodyBinding.tabLayout)
@ -978,7 +995,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
for (i in 0 until mBodyBinding.tabLayout.tabCount) {
val tab = mBodyBinding.tabLayout.getTabAt(i) ?: continue
val tabTitle = if (tab.text != null) tab.text.toString() else ""
if (data.showArchive && i == getTabPositionFromTabName(getString(R.string.game_detail_cloud_archive))) {
if (data.showArchive && i == getTabPositionFromTabType(TAB_ARCHIVE)) {
tab.customView = getArchiveTabView(tabTitle)
tab.view.run {
clipChildren = false
@ -1081,7 +1098,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
if (mNewGameDetailEntity!!.showComment) {
if (mSkipGameComment) {
tabPerformClick(INDEX_RATING)
tabPerformClick(getTabPositionFromTabType(TAB_RATING))
mBodyBinding.gamedetailAppbar.setExpanded(false)
mSkipGameComment = false
}
@ -1288,8 +1305,10 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
when {
isHighlightBg && !isLastView -> root.background =
R.drawable.bg_content_card_large_primary.toDrawable(requireContext())
!isHighlightBg && !isLastView -> root.background =
R.drawable.bg_content_card_large.toDrawable(requireContext())
!isHighlightBg && isLastView -> root.background =
R.drawable.bg_content_card_large_right.toDrawable(requireContext())
}
@ -1348,7 +1367,10 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
ExposureManager.log(
ExposureEvent.createEvent(
GameEntity(sequence = position),
listOf(ExposureSource("游戏详情", mGameEntity?.id ?: ""), ExposureSource("内容卡片", contentCardEntity.id))
listOf(
ExposureSource("游戏详情", mGameEntity?.id ?: ""),
ExposureSource("内容卡片", contentCardEntity.id)
)
)
)
}.root
@ -1383,7 +1405,10 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
ExposureManager.log(
ExposureEvent.createEvent(
GameEntity(sequence = position),
listOf(ExposureSource("游戏详情", mGameEntity?.id ?: ""), ExposureSource("内容卡片", contentCardEntity.id))
listOf(
ExposureSource("游戏详情", mGameEntity?.id ?: ""),
ExposureSource("内容卡片", contentCardEntity.id)
)
)
)
}.root
@ -1536,19 +1561,19 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(reuse: EBReuse) {
if (SKIP_DESC == reuse.type) {
tabPerformClick(INDEX_DESC)
tabPerformClick(getTabPositionFromTabType(TAB_DESC))
} else if (OPEN_APPBAR == reuse.type && !mIsTouchScreen) {
mBodyBinding.gamedetailAppbar.setExpanded(true, true)
} else if (SKIP_FULI == reuse.type) {
tabPerformClick(INDEX_TRENDES)
tabPerformClick(getTabPositionFromTabType(TAB_TRENDS))
} else if (SKIP_RATING == reuse.type) {
tabPerformClick(INDEX_RATING)
tabPerformClick(getTabPositionFromTabType(TAB_RATING))
} else if ("hideKaifuHint" == reuse.type) {
mIsShowKaifuHint = false
mBinding.gamedetailKaifuHint.visibility = View.GONE
} else if ("showKaifuHint" == reuse.type) {
mIsShowKaifuHint = true
if (mCurVpPosition == INDEX_TRENDES) {
if (mCurVpPosition == getTabPositionFromTabType(TAB_TRENDS)) {
mBinding.gamedetailKaifuHint.post { mBinding.gamedetailKaifuHint.visibility = View.VISIBLE }
}
} else if (CLOSE_APPBAR == reuse.type && !mIsTouchScreen) {
@ -1807,28 +1832,29 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
private fun tabPerformClick(position: Int) {
val trendsTabPosition = getTabPositionFromTabType(TAB_TRENDS)
val bbsTabPosition = getTabPositionFromTabType(TAB_BBS)
when (position) {
INDEX_TRENDES -> {
trendsTabPosition -> {
val zoneEntity = mNewGameDetailEntity?.zone
if (!mTabTitleList.contains(getString(R.string.game_detail_dongtai))
&& !mTabTitleList.contains(zoneEntity?.customName)
) {
performJumpContentCard("func_zone")
} else {
mBodyBinding.gamedetailVp.currentItem = getTabPositionFromTabName(
if (mNewGameDetailEntity?.zone?.customName.isNullOrEmpty()) getString(R.string.game_detail_dongtai) else mNewGameDetailEntity?.zone?.customName
?: ""
)
mBodyBinding.gamedetailVp.currentItem = getTabPositionFromTabType(TAB_TRENDS)
}
}
INDEX_BBS -> {
bbsTabPosition -> {
if (!mTabTitleList.contains(getString(R.string.game_detail_bbs))) {
performJumpContentCard("func_bbs")
} else {
mBodyBinding.gamedetailVp.currentItem =
getTabPositionFromTabName(getString(R.string.game_detail_bbs))
mBodyBinding.gamedetailVp.currentItem = getTabPositionFromTabType(TAB_BBS)
}
}
else -> {
mBodyBinding.gamedetailVp.currentItem = position
}
@ -1850,10 +1876,11 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
val entrance = if (mEntrance.contains("论坛详情")) "论坛" else "游戏"
mGameEntity?.run {
when (getTabContentForReal(position)) {
when (mTabTypeList[position]) {
TAB_DESC -> {
NewLogUtils.logGameDetailTabClick(name ?: "", id, "详情")
}
TAB_TRENDS -> {
NewLogUtils.logGameDetailTabClick(
"view_game_detail_special_area_tab",
@ -1864,6 +1891,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
)
NewLogUtils.logGameDetailTabClick(name ?: "", id, "专区")
}
TAB_ARCHIVE -> {
NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
"cloud_save_tab_click",
@ -1882,10 +1910,12 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
"last_page_business_id", getLastPageEntity().pageBusinessId
)
}
TAB_RATING -> {
NewLogUtils.logGameDetailTabClick("view_game_detail_comment_tab", entrance, id, gameType, bbsId)
NewLogUtils.logGameDetailTabClick(name ?: "", id, "评论")
}
TAB_BBS -> {
NewLogUtils.logGameDetailTabClick(name ?: "", id, "论坛")
}
@ -1893,35 +1923,13 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
}
/**
* 获取真实的 tab 内容类型
* @param position tab 的位置
* @return 真实的 tab 类型
*/
private fun getTabContentForReal(position: Int): String {
return when (mTabTitleList[position]) {
getString(R.string.game_detail_dongtai),
mNewGameDetailEntity?.zone?.customName -> TAB_TRENDS
getString(R.string.game_detail_cloud_archive) -> TAB_ARCHIVE
getString(R.string.game_detail_comment) -> TAB_RATING
getString(R.string.game_detail_bbs) -> TAB_BBS
getString(R.string.game_detail_desc) -> TAB_DESC
else -> TAB_DESC
}
}
/**
* 获取 tab 的位置
* @param tabName tab 名字
* @param tabType tab 类型
* @return tab 的真实位置
*/
private fun getTabPositionFromTabName(tabName: String): Int {
return mTabTitleList.indexOf(tabName)
private fun getTabPositionFromTabType(tabType: String): Int {
return mTabTypeList.indexOf(tabType)
}
private fun handleTabTouchEvent(title: String) {
@ -1938,8 +1946,9 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
getString(R.string.game_detail_comment),
getString(R.string.game_detail_cloud_archive) -> {
mBodyBinding.gamedetailAppbar.setExpanded(false, true)
tabPerformClick(getTabPositionFromTabName(title))
tabPerformClick(getTabPositionFromTabType(title))
}
else -> {
// do nothing
}
@ -1971,7 +1980,8 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
} else {
hintText =
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) "当前安装方式为[浏览器安装],点击切换安装方式" else "手机如何解决无法安装问题"
closeHintText = "关闭后“切换安装方式”入口将显示在左下角,您也可以前往“我的光环-设置-切换安装方式”进行设置"
closeHintText =
"关闭后“切换安装方式”入口将显示在左下角,您也可以前往“我的光环-设置-切换安装方式”进行设置"
}
mDownloadBinding.browserInstallHintTv.text = hintText
@ -2056,7 +2066,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mRecommendBinding.recommendText.text = popupDetail.text
if (popupDetail.images.isNotEmpty()) {
ImageUtils.display(mRecommendBinding.recommendImage, popupDetail.images[0])
mRecommendBinding.recommendImage.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
mRecommendBinding.recommendImage.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
mRecommendBinding.recommendImage.post {
mRecommendBinding.recommendImage.layoutParams.apply {
@ -2066,7 +2076,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
}
}
}
})
} else {
mRecommendBinding.recommendImage.visibility = View.GONE
(mRecommendBinding.recommendText.layoutParams as ConstraintLayout.LayoutParams).apply {
@ -2151,7 +2161,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private fun updateArchiveTabUI() {
mBodyBinding.tabLayout.run {
val archivePosition = getTabPositionFromTabName(getString(R.string.game_detail_cloud_archive))
val archivePosition = getTabPositionFromTabType(TAB_ARCHIVE)
getTabAt(archivePosition)?.customView?.findViewById<ImageView>(R.id.newIv)?.visibility = View.VISIBLE
}
}
@ -2168,11 +2178,13 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
override fun onBackPressed(): Boolean {
mOrientationUtils?.backToProtVideo()
if (mBodyBinding.gamedetailVp.currentItem == INDEX_TRENDES
&& mFragmentsList[INDEX_TRENDES] is WebFragment
&& mFragmentsList[INDEX_TRENDES].isAdded
val trendsTabPosition = getTabPositionFromTabType(TAB_TRENDS)
if (mBodyBinding.gamedetailVp.currentItem == trendsTabPosition
&& mFragmentsList[trendsTabPosition] is WebFragment
&& mFragmentsList[trendsTabPosition].isAdded
) {
return (mFragmentsList[INDEX_TRENDES] as WebFragment).onBackPressed()
return (mFragmentsList[trendsTabPosition] as WebFragment).onBackPressed()
}
if (CustomManager.backFromWindowFull(requireActivity(), mVideoBinding.player.getKey())) {
@ -2349,12 +2361,6 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
companion object {
const val INDEX_DESC = 0
const val INDEX_RATING = 1
const val INDEX_ARCHIVE = 2
const val INDEX_TRENDES = 3
const val INDEX_BBS = 4
const val TAB_DESC = "详情"
const val TAB_TRENDS = "专区"
const val TAB_ARCHIVE = "云存档"
@ -2368,7 +2374,6 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
const val CLOSE_APPBAR = "closeappbar"
const val SCROLL_TO_KAIFU = "scrollToKaiFu"
const val EB_SCROLLING = "EB_SCROLLING"
const val EB_STAR = "eb_star"
const val INITIAL_DELAY = 500L
const val CONTENT_CARD_LOOP_TIME = 3000L

View File

@ -208,127 +208,143 @@ class GameDetailViewModel(
}
private fun replaceWithMirrorInfoIfNeeded(data: NewGameDetailEntity) {
if (data.mirrorStatus == "on"
&& (game?.useMirrorInfo == true
|| RegionSettingHelper.shouldThisGameDisplayMirrorInfo(game?.id ?: ""))
) {
val finalItemList: ArrayList<DetailEntity> = arrayListOf()
val mirrorCustomColumnList = data.mirrorData?.customColumnList ?: arrayListOf()
mirrorCustomColumnList.sortByDescending { it.order }
for (item in data.detailEntity) {
// 去掉所有自定义栏目并把镜像相应权重的自定义栏目放到相应的位置
if (item.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
val usedMirrorCustomColumnList = arrayListOf<CustomColumn>()
for (mirrorCustomColumn in mirrorCustomColumnList) {
if ((mirrorCustomColumn.order!! > 0 && item.customColumn?.order!! > 0)
|| (mirrorCustomColumn.order == item.customColumn?.order)
) {
finalItemList.add(
DetailEntity(
type = DetailEntity.Type.CUSTOM_COLUMN.value,
customColumn = mirrorCustomColumn
)
// 获取镜像相关数据,不存在时不替换
val mirrorData = getMirrorData(data) ?: return
val finalItemList: ArrayList<DetailEntity> = arrayListOf()
val mirrorCustomColumnList = mirrorData.customColumnList ?: arrayListOf()
mirrorCustomColumnList.sortByDescending { it.order }
for (item in data.detailEntity) {
// 去掉所有自定义栏目并把镜像相应权重的自定义栏目放到相应的位置
if (item.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
val usedMirrorCustomColumnList = arrayListOf<CustomColumn>()
for (mirrorCustomColumn in mirrorCustomColumnList) {
if ((mirrorCustomColumn.order!! > 0 && item.customColumn?.order!! > 0)
|| (mirrorCustomColumn.order == item.customColumn?.order)
) {
finalItemList.add(
DetailEntity(
type = DetailEntity.Type.CUSTOM_COLUMN.value,
customColumn = mirrorCustomColumn
)
usedMirrorCustomColumnList.add(mirrorCustomColumn)
}
}
mirrorCustomColumnList.removeAll(usedMirrorCustomColumnList)
continue
}
// 历史版本入口
if (item.type == DetailEntity.Type.UPDATE_CONTENT.value) {
item.update?.historyApkStatus = "off"
}
// 不显示 "玩家评论`", "相关游戏`"
if (item.type == DetailEntity.Type.COMMENTS.value ||
item.type == DetailEntity.Type.RELATED_VERSION.value
) {
continue
}
// 处理游戏信息区域
if (item.type == DetailEntity.Type.GAME_INFO.value) {
item.info?.manufacturer = data.mirrorData?.manufacturer ?: ""
item.info?.privacyPolicyUrl = data.mirrorData?.privacyPolicyUrl ?: ""
item.info?.manufacturerType = data.mirrorData?.manufacturerType ?: ""
item.info?.publisher = data.mirrorData?.publisher ?: ""
item.info?.developer = data.mirrorData?.developer ?: ""
item.info?.supplier = data.mirrorData?.supplier ?: ""
item.info?.creditCode = data.mirrorData?.creditCode ?: ""
item.info?.updateTime = data.mirrorData?.updateTime ?: 0L
finalItemList.add(item)
continue
}
// 去掉游戏信息里的 "mod 版"
if (item.type == DetailEntity.Type.GAME_INFO.value) {
item.info?.topTags?.removeAll { it.name.toLowerCase(Locale.getDefault()) == "mod版" }
}
// 替换镜像开服信息
if (item.type == DetailEntity.Type.LATEST_SERVER.value && data.mirrorData?.server != null) {
if (data.mirrorData?.server?.status == "hide") {
continue
} else {
item.server = data.mirrorData?.server
}
}
// 镜像游戏去掉推荐游戏 (用于构建大家都在玩)
if (item.type == DetailEntity.Type.RECOMMENDED_GAMES.value) {
continue
}
finalItemList.add(item)
}
val funcServer = data.contentCard.find { it.type == "func_server" }
if (funcServer?.mirrorServer != null) {
funcServer.server = funcServer.mirrorServer
}
// 有多余的镜像自定义栏目没找到位置放统一按权重为0放到详细信息后连权重为0也没有就放到列表最后
if (!mirrorCustomColumnList.isNullOrEmpty()) {
var gameInfoPosition = finalItemList.size - 1
for ((index, item) in finalItemList.withIndex()) {
if (item.type == DetailEntity.Type.GAME_INFO.value) {
gameInfoPosition = index + 1
break
}
}
for ((index, remainingMirrorCustomColumn) in mirrorCustomColumnList.withIndex()) {
finalItemList.add(
gameInfoPosition + index,
DetailEntity(
type = DetailEntity.Type.CUSTOM_COLUMN.value,
customColumn = remainingMirrorCustomColumn
)
)
usedMirrorCustomColumnList.add(mirrorCustomColumn)
}
}
mirrorCustomColumnList.removeAll(usedMirrorCustomColumnList)
continue
}
// 历史版本入口
if (item.type == DetailEntity.Type.UPDATE_CONTENT.value) {
item.update?.historyApkStatus = "off"
}
// 不显示 "玩家评论`", "相关游戏`"
if (item.type == DetailEntity.Type.COMMENTS.value ||
item.type == DetailEntity.Type.RELATED_VERSION.value
) {
continue
}
// 处理游戏信息区域
if (item.type == DetailEntity.Type.GAME_INFO.value) {
item.info?.manufacturer = mirrorData.manufacturer ?: ""
item.info?.privacyPolicyUrl = mirrorData.privacyPolicyUrl ?: ""
item.info?.manufacturerType = mirrorData.manufacturerType
item.info?.publisher = mirrorData.publisher
item.info?.developer = mirrorData.developer
item.info?.supplier = mirrorData.supplier
item.info?.creditCode = mirrorData.creditCode
item.info?.updateTime = mirrorData.updateTime
finalItemList.add(item)
continue
}
// 去掉游戏信息里的 "mod 版"
if (item.type == DetailEntity.Type.GAME_INFO.value) {
item.info?.topTags?.removeAll { it.name.toLowerCase(Locale.getDefault()) == "mod版" }
}
// 替换镜像开服信息
if (item.type == DetailEntity.Type.LATEST_SERVER.value && mirrorData.server != null) {
if (mirrorData.server?.status == "hide") {
continue
} else {
item.server = mirrorData.server
}
}
// 不显示评论 tab
data.showComment = false
for (item in finalItemList) {
item.des = data.mirrorData?.des
item.gallery = data.mirrorData?.gallery
item.update?.updateDes = data.mirrorData?.updateDes ?: ""
item.info?.size = data.mirrorData?.apk?.firstOrNull()?.size ?: ""
item.info?.version = data.mirrorData?.apk?.firstOrNull()?.version ?: ""
// 镜像游戏去掉推荐游戏 (用于构建大家都在玩)
if (item.type == DetailEntity.Type.RECOMMENDED_GAMES.value) {
continue
}
data.tagStyle =
data.mirrorData?.tagStyle?.apply { removeAll { it.name.toLowerCase(Locale.getDefault()) == "mod版" } }
?: arrayListOf()
data.detailDialogs = data.mirrorData?.detailDialogs ?: arrayListOf()
data.detailEntity = finalItemList
finalItemList.add(item)
}
val funcServer = data.contentCard.find { it.type == "func_server" }
if (funcServer?.mirrorServer != null) {
funcServer.server = funcServer.mirrorServer
}
// 有多余的镜像自定义栏目没找到位置放统一按权重为0放到详细信息后连权重为0也没有就放到列表最后
if (!mirrorCustomColumnList.isNullOrEmpty()) {
var gameInfoPosition = finalItemList.size - 1
for ((index, item) in finalItemList.withIndex()) {
if (item.type == DetailEntity.Type.GAME_INFO.value) {
gameInfoPosition = index + 1
break
}
}
for ((index, remainingMirrorCustomColumn) in mirrorCustomColumnList.withIndex()) {
finalItemList.add(
gameInfoPosition + index,
DetailEntity(
type = DetailEntity.Type.CUSTOM_COLUMN.value,
customColumn = remainingMirrorCustomColumn
)
)
}
}
// 不显示评论 tab
data.showComment = false
for (item in finalItemList) {
item.des = mirrorData.des
item.gallery = mirrorData.gallery
item.update?.updateDes = mirrorData.updateDes
item.info?.size = mirrorData.apk?.firstOrNull()?.size ?: ""
item.info?.version = mirrorData.apk?.firstOrNull()?.version ?: ""
}
data.tagStyle =
mirrorData.tagStyle.apply { removeAll { it.name.toLowerCase(Locale.getDefault()) == "mod版" } }
data.detailDialogs = mirrorData.detailDialogs
data.detailEntity = finalItemList
}
/**
* 获取镜像数据,为空时代表不启用镜像
*/
private fun getMirrorData(data: NewGameDetailEntity): DetailEntity? {
// 游戏 id
val id = game?.id ?: ""
if (RegionSettingHelper.shouldThisGameDisplayMirrorInfo(id) || game?.useMirrorInfo == true) {
if (data.mirrorStatus == "on" || data.mirrorStatus2 == "on") {
when (RegionSettingHelper.getMirrorPosition(id)) {
1 -> return data.mirrorData
2 -> return data.mirrorData2
}
}
}
return null
}
/**

View File

@ -50,7 +50,7 @@ class GameGalleryAdapter(
is GameGalleryViewHolder -> {
holder.binding.screenshotItemIv.setTag(ImageUtils.TAG_TARGET_WIDTH, 260F.dip2px())
ImageUtils.display(holder.binding.screenshotItemIv, mGallery?.get(position))
holder.binding.screenshotItemIv.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
holder.binding.screenshotItemIv.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
holder.binding.screenshotItemIv.post {
holder.binding.screenshotItemIv.layoutParams.apply {
@ -63,7 +63,7 @@ class GameGalleryAdapter(
holder.itemView.requestLayout()
}
}
}
})
holder.itemView.setDebouncedClickListener {
DataCollectionUtils.uploadClick(context, "游戏介绍", "游戏详情")
MtaHelper.onEvent("游戏详情_新", "点击游戏截图", mGame.name)

View File

@ -40,6 +40,10 @@ class NewGameDetailEntity(
var mirrorStatus: String? = "",
@SerializedName("mirror_data")
var mirrorData: DetailEntity? = null,
@SerializedName("mirror_status2")
var mirrorStatus2: String? = "",
@SerializedName("mirror_data2")
var mirrorData2: DetailEntity? = null,
@SerializedName("bbs_tab")
var bbsTab: LinkEntity? = null,
@SerializedName("certification_tag")

View File

@ -52,6 +52,7 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
private var mMuteDisposable: Disposable? = null
private var mContentLength = 0.0
private var mIsAutoPlay = false
private var mLastGetContentLengthTime = 0L
val combinedTitleAndId: String
get() = StringUtils.combineTwoString(video?.title, video?.videoId)
@ -527,7 +528,11 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
val videoTotalTime = duration / 1000
val progress = if (videoTotalTime != 0) videoPlayTs.toFloat() / videoTotalTime.toFloat() * 100 else 0f
if (mContentLength == 0.0) {
mContentLength = ExoCacheManager.getContentLength(video!!.url) / 1024.0 / 1024.0
val newGetContentLengthTime = System.currentTimeMillis()
if (newGetContentLengthTime - mLastGetContentLengthTime > 5000) {
mLastGetContentLengthTime = newGetContentLengthTime
mContentLength = ExoCacheManager.getContentLength(video!!.url) / 1024.0 / 1024.0
}
}
//https://exoplayer.dev/hello-world.html#a-note-on-threading

View File

@ -1,9 +1,12 @@
package com.gh.gamecenter.geetest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.AppDebugConfig;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.retrofit.RetrofitManager;
@ -113,6 +116,10 @@ public class GeetestUtils {
mRetryCount = 0;
final GtDialog dialog = new GtDialog(context, params);
if (context instanceof Activity) {
dialog.setOwnerActivity((Activity) context);
}
// 启用debug可以在webview上看到验证过程的一些数据
dialog.setDebug(AppDebugConfig.IS_DEBUG);
@ -128,85 +135,88 @@ public class GeetestUtils {
@Override
public void gtCallReady(Boolean status) {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, status, mProgressDialog.isShowing());
}
AppExecutor.getUiExecutor().execute(() -> {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, status, mProgressDialog.isShowing());
}
mRetryCount = 0;
if (!mProgressDialog.isShowing()) {
//被手动取消了也就是其实用户想取消loading了那么即使回调也不弹出
return;
}
mRetryCount = 0;
if (!mProgressDialog.isShowing()) {
//被手动取消了也就是其实用户想取消loading了那么即使回调也不弹出
return;
}
mProgressDialog.dismiss();
mProgressDialog.dismiss();
if (status) {
// 验证加载完成
RuntimeUtils.getInstance().runOnUiThread(new Runnable() {
if (status) {
// 验证加载完成
Activity ownerActivity = dialog.getOwnerActivity();
@Override
public void run() {
if (dialog != null) {
dialog.show();
}
if (ownerActivity != null
&& (ownerActivity.isFinishing()
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) && ownerActivity.isDestroyed())) {
// activity 不可见
toastMsg(context, "验证加载超时,请重新尝试");
} else {
dialog.show();
}
});
} else {
// 验证加载超时,未准备完成
toastMsg(context, "验证加载超时,请重新尝试");
}
} else {
// 验证加载超时,未准备完成
toastMsg(context, "验证加载超时,请重新尝试");
}
});
}
@Override
public void gtCallClose() {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
// toastMsg("close geetest windows");
AppExecutor.getUiExecutor().execute(() -> {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
});
}
@Override
public void gtError() {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
if (mRetryCount < RETRY_MAX_COUNT) {
mRetryCount++;
checkServer(context);
} else {
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
AppExecutor.getUiExecutor().execute(() -> {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
}
if (mRetryCount < RETRY_MAX_COUNT) {
mRetryCount++;
checkServer(context);
} else {
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
});
}
@Override
public void gtResult(boolean success, String result) {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, success, result);
}
if (success) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
AppExecutor.getUiExecutor().execute(() -> {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this, success, result);
}
if (mGeetestListener != null) {
mGeetestListener.onVerified(result);
}
// toastMsg("client captcha succeed:" + result);
Utils.log("client captcha succeed:" + result);
} else {
// 验证失败
// toastMsg("client captcha failed:" + result);
Utils.log("client captcha failed:" + result);
}
if (success) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (mGeetestListener != null) {
mGeetestListener.onVerified(result);
}
Utils.log("client captcha succeed:" + result);
} else {
// 验证失败
Utils.log("client captcha failed:" + result);
}
});
}
});
@ -218,7 +228,6 @@ public class GeetestUtils {
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(this);
}
}
});

View File

@ -27,6 +27,7 @@ import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.common.view.OffsetLinearLayoutManager
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
import com.gh.gamecenter.core.provider.IStartUpAdProvider
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SPUtils
@ -103,7 +104,10 @@ class HomeFragment : LazyFragment() {
reuseLoading.root.goneIf(loadStatus != LoadStatus.INIT_LOADING)
}
mListAdapter.setLoadStatus(it)
val startAdContainerView = requireActivity().findViewById<View>(R.id.startAdContainer)
val startUpAdProvider =
ARouter.getInstance().build(RouteConsts.provider.adSdk).navigation() as? IStartUpAdProvider
val startAdContainerView =
requireActivity().findViewById<View>(if (startUpAdProvider != null) R.id.sdkStartAdContainer else R.id.startAdContainer)
if (it == LoadStatus.INIT_LOADED && startAdContainerView == null) {
AppExecutor.uiExecutor.executeWithDelay({
scroll()
@ -171,7 +175,7 @@ class HomeFragment : LazyFragment() {
super.onScrolled(recyclerView, dx, dy)
if (parentFragment is HomeSearchToolWrapperFragment) {
val bannerViewHeight = mAutomaticLayoutManager.heightMap[0] ?: 0
val type = (parentFragment as HomeSearchToolWrapperFragment).getCurrentTab()?.type
val type = (parentFragment as HomeSearchToolWrapperFragment).getCurrentTabEntity()?.type
if (type == "home") {
(parentFragment as HomeSearchToolWrapperFragment).onScrollChanged(
bannerViewHeight,
@ -195,7 +199,9 @@ class HomeFragment : LazyFragment() {
}
fun setScrollEnabled(isScrollEnabled: Boolean) {
mAutomaticLayoutManager.isScrollEnabled = isScrollEnabled
if (::mAutomaticLayoutManager.isInitialized) {
mAutomaticLayoutManager.isScrollEnabled = isScrollEnabled
}
}
fun onRefresh() {
@ -217,7 +223,10 @@ class HomeFragment : LazyFragment() {
* 2. 过早显示悬浮窗,出现首页还未显示悬浮窗就在广告页显示的情况
*/
private fun listenStartAdViewRemoved() {
val startAdContainerView = requireActivity().findViewById<View>(R.id.startAdContainer)
val startUpAdProvider =
ARouter.getInstance().build(RouteConsts.provider.adSdk).navigation() as? IStartUpAdProvider
val startAdContainerView =
requireActivity().findViewById<View>(if (startUpAdProvider != null) R.id.sdkStartAdContainer else R.id.startAdContainer)
val parentView = startAdContainerView?.parent as? ViewGroup
if (parentView == null) {

View File

@ -32,9 +32,10 @@ class HomeGameCollectionAdapter(
override fun onBindViewHolder(holder: HomeGameCollectionCardViewHolder, position: Int) {
if (gameCollectionItemDataList.isNotEmpty()) {
val gameCollectionItemData = gameCollectionItemDataList.safelyGetInRelease(position)
(holder.itemView as HomeGameCollectionItemCell).bindWhenInflated {
(holder.itemView as HomeGameCollectionItemCell).binding?.run {
holder.bindGameCollectionCard(this, gameCollectionItemDataList[position], entrance)
gameCollectionItemData?.let { holder.bindGameCollectionCard(this, it, entrance) }
}
}
}

View File

@ -4,7 +4,6 @@ import android.graphics.Typeface
import android.graphics.drawable.GradientDrawable
import android.view.MotionEvent
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
@ -34,7 +33,6 @@ import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.home.HomeItemData
import com.gh.gamecenter.home.HomeViewModel
import splitties.views.dsl.core.endMargin
import kotlin.math.abs
class HomeSlideWithCardsViewHolder(
@ -261,7 +259,6 @@ class HomeSlideWithCardsViewHolder(
)
)
)
itemData.exposureEventList?.add(exposureEvent)
when (homeSubSlide.cardType) {
"column",
@ -285,6 +282,14 @@ class HomeSlideWithCardsViewHolder(
gameIconStackIv1.visibility = View.GONE
}
homeSubSlide.cardData.games.take(3).forEachIndexed { index, gameEntity ->
itemData.exposureEventList?.add(
getGameExposureEvent(
homeSubSlide,
gameEntity,
position,
basicExposureSource
)
)
when (index) {
0 -> gameIconStackIv3.displayGameIcon(gameEntity, true)
1 -> gameIconStackIv2.displayGameIcon(gameEntity, true)
@ -314,6 +319,17 @@ class HomeSlideWithCardsViewHolder(
gameIconIv3.visibility = View.GONE
}
homeSubSlide.cardData.games.take(3).forEachIndexed { index, gameEntity ->
val gameExposureEvent =
getGameExposureEvent(homeSubSlide, gameEntity, position, basicExposureSource)
itemData.exposureEventList?.add(
getGameExposureEvent(
homeSubSlide,
gameEntity,
position,
basicExposureSource
)
)
when (index) {
0 -> {
gameIconIv1.displayGameIcon(gameEntity, true)
@ -327,10 +343,11 @@ class HomeSlideWithCardsViewHolder(
binding.root.context,
gameEntity.id,
BaseActivity.mergeEntranceAndPath("新首页", "右侧卡片"),
exposureEvent
gameExposureEvent
)
}
}
1 -> {
gameIconIv2.displayGameIcon(gameEntity, true)
gameIconIv2.setOnClickListener {
@ -343,10 +360,11 @@ class HomeSlideWithCardsViewHolder(
binding.root.context,
gameEntity.id,
BaseActivity.mergeEntranceAndPath("新首页", "右侧卡片"),
exposureEvent
gameExposureEvent
)
}
}
2 -> {
gameIconIv3.displayGameIcon(gameEntity, true)
gameIconIv3.setOnClickListener {
@ -359,7 +377,7 @@ class HomeSlideWithCardsViewHolder(
binding.root.context,
gameEntity.id,
BaseActivity.mergeEntranceAndPath("新首页", "右侧卡片"),
exposureEvent
gameExposureEvent
)
}
}
@ -417,6 +435,8 @@ class HomeSlideWithCardsViewHolder(
connect(textContainer.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP)
connect(textContainer.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
}.applyTo(cardContainer)
itemData.exposureEventList?.add(exposureEvent)
}
}
@ -431,17 +451,42 @@ class HomeSlideWithCardsViewHolder(
source = listOf(
ExposureSource(
"右侧卡片",
"${homeSubSlide.cardId} - ${getCardTypeChinese(homeSubSlide.cardType)}"
"${homeSubSlide.cardId.ifEmpty { homeSubSlide.linkId }} - ${getCardTypeChinese(homeSubSlide.cardType)}"
)
),
event = ExposureType.CLICK
)
)
com.gh.common.util.NewFlatLogUtils.logRightSideCardClick(homeSubSlide, viewModel.refreshCount, "卡片")
DirectUtils.directToLinkPage(cardCv.context, homeSubSlide.toLinkEntity(), "新首页", "右侧卡片", exposureEvent)
DirectUtils.directToLinkPage(
cardCv.context,
homeSubSlide.toLinkEntity(),
"新首页",
"右侧卡片",
exposureEvent
)
}
}
private fun getGameExposureEvent(
homeSubSlide: HomeSubSlide,
gameEntity: GameEntity,
position: Int,
basicExposureSource: List<ExposureSource>
) = ExposureEvent.createEventWithSourceConcat(
gameEntity = gameEntity.apply {
sequence = position
outerSequence = viewModel.refreshCount
},
basicSource = basicExposureSource,
source = listOf(
ExposureSource(
"右侧卡片",
"${homeSubSlide.cardId.ifEmpty { homeSubSlide.linkId }} - ${getCardTypeChinese(homeSubSlide.cardType)}"
)
)
)
private fun updateImmersiveColor(color: Int) {
callback.invoke(color)
val gradientDrawable = DrawableView.getGradientDrawable(

View File

@ -5,6 +5,7 @@ import android.view.View
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.core.utils.DisplayUtils
/**
* @author : liujiarui
@ -13,6 +14,9 @@ import com.gh.gamecenter.common.utils.dip2px
* 仅用于新游开测,让条目右侧漏出部分,或者最后一列左侧条目漏出部分
*/
class HomeGameTestV2Decoration : RecyclerView.ItemDecoration() {
private val mParentWidth = DisplayUtils.getScreenWidth() - 32F.dip2px()
companion object {
private const val SPAN_COUNT = 3
}
@ -24,7 +28,7 @@ class HomeGameTestV2Decoration : RecyclerView.ItemDecoration() {
if (lastModPosition == 0) lastModPosition = SPAN_COUNT
val isLastRow = (itemCount - position) <= lastModPosition
view.updateLayoutParams {
width = parent.width - if (isLastRow) {
width = mParentWidth - if (isLastRow) {
8F.dip2px()
} else {
24F.dip2px()

View File

@ -77,10 +77,9 @@ class HomeGameTestV2GameListViewHolder(
*/
private fun fixViewHolderTheme(gameEntity: GameEntity) {
val context = mBinding.root.context
mBinding.root.setBackgroundColor(R.color.background_white.toColor(context))
gameName.setTextColor(R.color.text_title.toColor(context))
gameDownloadBtn.background = R.drawable.download_button_normal_style.toDrawable(context)
gameDes.setTextColor(R.color.text_subtitle.toColor(context))
gameDes.setTextColor(R.color.text_title.toColor(context))
var gameRatingTextColor = R.color.theme.toColor(context)
if (gameEntity.commentCount > 3) {
gameRatingTextColor = R.color.theme_font.toColor(context)

View File

@ -185,7 +185,8 @@ class HomeGameTestV2ViewModel(application: Application) : AndroidViewModel(appli
timeType = response.timeType,
pageId = response.pageId,
action = Action.getActionByCommand(response.action),
isRefresh = false
isRefresh = false,
isSameTimeType = timeType == loadTimeType
)
}
@ -289,7 +290,8 @@ class HomeGameTestV2ViewModel(application: Application) : AndroidViewModel(appli
pageId: String,
action: Action,
firstIndex: Int = 0, //首页推荐列表左侧剩余游戏数
isRefresh: Boolean = false
isRefresh: Boolean = false,
isSameTimeType: Boolean = false //当前时间轴类型与预加载时间轴类型是否相同
) {
val currentData = getCurrentData().toMutableList()
val gameList = getFilterGameAndTrimList(currentData, list)
@ -324,7 +326,7 @@ class HomeGameTestV2ViewModel(application: Application) : AndroidViewModel(appli
gameList.reverse()
}
gameList.forEach {
addGameItemWithAction(currentData, it, action)
addGameItemWithAction(currentData, it, action, isSameTimeType)
}
}
mDataLiveData.value = currentData.toMutableList()
@ -341,11 +343,20 @@ class HomeGameTestV2ViewModel(application: Application) : AndroidViewModel(appli
dataList: MutableList<GameDataWrapper>,
gameDataWrapper: GameDataWrapper,
action: Action,
isSameTimeType: Boolean
) {
val gameTimeType = gameDataWrapper.timeType
val firstLoadedRecommendPosition =
dataList.indexOfFirst { it.timeType == "recommend" && !it.isPlaceHolder && !it.isSpace } // 推荐类型第一个非占位的位置
val lastLoadedRecommendPosition =
dataList.indexOfLast { it.timeType == "recommend" && !it.isPlaceHolder && !it.isSpace } // 推荐类型最后一个非占位的位置
val shouldInsertLoadedRecommendFront =
gameTimeType == "recommend" && isSameTimeType && firstLoadedRecommendPosition > 0 // 推荐定位不是第一个时需要插入到已加载位置的前面
val shouldInsertLoadedRecommendBehind =
gameTimeType == "recommend" && isSameTimeType && lastLoadedRecommendPosition > 0 // 推荐定位不是第一个时需要插入到已加载位置的后面
val insertPosition = when (action) {
Action.LEFT -> dataList.indexOfFirst { it.timeType == gameTimeType && it.isPlaceHolder }
Action.RIGHT -> dataList.indexOfLast { it.timeType == gameTimeType && it.isPlaceHolder }
Action.LEFT -> if (shouldInsertLoadedRecommendBehind) lastLoadedRecommendPosition + 1 else dataList.indexOfFirst { it.timeType == gameTimeType && it.isPlaceHolder }
Action.RIGHT -> if (shouldInsertLoadedRecommendFront) firstLoadedRecommendPosition - 1 else dataList.indexOfLast { it.timeType == gameTimeType && it.isPlaceHolder }
}
val exist = dataList.find { it.timeType == gameTimeType && it.gameData?.id == gameDataWrapper.gameData?.id }
if (exist != null) {

View File

@ -212,7 +212,8 @@ class HomeItemGameTestV2ViewHolder(
pageId = data.pageId,
action = HomeGameTestV2ViewModel.Action.getActionByCommand(data.action),
firstIndex = recommendLeftSurplusNum,
isRefresh = true
isRefresh = true,
isSameTimeType = true
)
//数据填充完毕后滑动到推荐列表指定位置
if (recommendLeftSurplusNum > 0) {

View File

@ -51,6 +51,7 @@ class AutomaticVideoView @JvmOverloads constructor(context: Context, attrs: Attr
private var mRandomPlaceholderColor = 0
private var mVideoViewRadius = 6F
private var mIsBottomRightAngle = true
private var mLastGetContentLengthTime = 0L
init {
val array = context.obtainStyledAttributes(attrs, R.styleable.AutomaticVideoView)
@ -310,7 +311,11 @@ class AutomaticVideoView @JvmOverloads constructor(context: Context, attrs: Attr
val videoTotalTime = duration / 1000
val progress = if (videoTotalTime != 0) videoPlayTs.toFloat() / videoTotalTime.toFloat() * 100 else 0f
if (mContentLength == 0.0) {
mContentLength = ExoCacheManager.getContentLength(topVideo.url) / 1024.0 / 1024.0
val newGetContentLengthTime = System.currentTimeMillis()
if (newGetContentLengthTime - mLastGetContentLengthTime > 5000) {
mLastGetContentLengthTime = newGetContentLengthTime
mContentLength = ExoCacheManager.getContentLength(topVideo.url) / 1024.0 / 1024.0
}
}
//https://exoplayer.dev/hello-world.html#a-note-on-threading

View File

@ -277,7 +277,7 @@ class MyFollowedGameViewHolder(var binding: ItemFollowedGameBinding) : RecyclerV
binding.root.context,
gameEntity,
entrance,
defaultTab = GameDetailFragment.INDEX_TRENDES
defaultTab = GameDetailFragment.TAB_TRENDS
)
}
} else {
@ -303,7 +303,7 @@ class MyFollowedGameViewHolder(var binding: ItemFollowedGameBinding) : RecyclerV
binding.root.context,
gameEntity,
entrance,
defaultTab = GameDetailFragment.INDEX_BBS
defaultTab = GameDetailFragment.TAB_BBS
)
}
} else {

View File

@ -378,13 +378,13 @@ class HaloPersonalFragment : BaseLazyFragment() {
}
mUserHomeViewModel.availableBadge.observe(this) { badge: BadgeEntity? ->
val badgeSevenDayMap = SPUtils.getMap(SP_BADGE_RECORD_SEVEN_DAY_MAP)
// 徽章领取弹窗每隔7天弹出一次所以要判断现在是否是上一次弹出的第7天或者之后
if (badge != null && System.currentTimeMillis() >= SPUtils.getLong(SP_BADGE_RECORD_SEVEN_DAY)) {
if (badge != null && System.currentTimeMillis() >= (badgeSevenDayMap[badge.id]?.toLong() ?: 0)) {
// 徽章领取弹窗每隔7天弹出一次所以本次弹出后就记录7天后的时间戳
SPUtils.setLong(
SP_BADGE_RECORD_SEVEN_DAY,
TimeUtils.getStartTimeOfDay(System.currentTimeMillis() + 86400000 * 6)
)
badgeSevenDayMap[badge.id] =
TimeUtils.getStartTimeOfDay(System.currentTimeMillis() + 86400000 * 6).toString()
SPUtils.setMap(SP_BADGE_RECORD_SEVEN_DAY_MAP, badgeSevenDayMap)
DialogUtils.showReceiveBadgeDialog(requireContext(), badge) {
if ("auto" == badge.receive?.type) {
DirectUtils.directToBadgeDetail(
@ -941,7 +941,7 @@ class HaloPersonalFragment : BaseLazyFragment() {
companion object {
private const val MESSAGE_READ_OVER = "MESSAGE_READ_OVER"
private const val SP_BADGE_RECORD_SEVEN_DAY = "badgeRecordSevenDay"
private const val SP_BADGE_RECORD_SEVEN_DAY_MAP = "badgeRecordSevenDayMap"
private const val REQUEST_MESSAGE = 199
private const val MAX_RECOMMEND_COUNT = 4
private const val MAX_MORE_FEATURES_COUNT = 12

View File

@ -43,7 +43,7 @@ class HaloPersonalFunctionAdapter(context: Context) : BaseRecyclerAdapter<Recycl
}
mEntityList.clear()
mEntityList.addAll(functionList)
notifyItemRangeChanged(0, itemCount)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =

View File

@ -44,7 +44,7 @@ class HaloPersonalRecommendAdapter(val context: Context) : BaseRecyclerAdapter<R
}
mEntityList.clear()
mEntityList.addAll(recommendList)
notifyItemRangeChanged(0, itemCount)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =

View File

@ -15,10 +15,23 @@ object PkgHelper {
private var mPkgConfigLink: PkgConfigEntity.PkgLinkEntity? = null
private const val SP_PKG_CONFIG_IS_USED = "pkg_config_is_used"
private var mActivateRatioFromInternet = 0
private val mPkgProvider by lazy {
ARouter.getInstance().build(RouteConsts.provider.pkg).navigation() as? IPkgProvider<PkgConfigEntity>
}
/**
* 获取激活比例
*/
fun getActivateRatio() : Int {
return if (mActivateRatioFromInternet > 0) {
mActivateRatioFromInternet
} else {
BuildConfig.ACTIVATE_REPORTING_RATIO
}
}
fun getPkgConfig(isFromHomeTopTab: Boolean): PkgConfigEntity.PkgLinkEntity? {
if (mPkgConfigLink == null
&& !SPUtils.getBoolean(SP_PKG_CONFIG_IS_USED, false)
@ -56,7 +69,9 @@ object PkgHelper {
mPkgProvider?.requestPkgConfig(configId) {
mPkgConfigLink = it.data?.link
mActivateRatioFromInternet = it.data?.activateRatio ?: 0
}
}
}

View File

@ -2,16 +2,22 @@ package com.gh.gamecenter.qa.article.detail
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Bitmap
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.Gravity
import android.view.View
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.DefaultUrlHandler
import com.gh.gamecenter.core.runOnUiThread
import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.NewLogUtils
import com.gh.common.view.RichEditor
@ -19,11 +25,15 @@ import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.ItemArticleDetailContentBinding
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.editor.OnLinkClickListener
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
import splitties.views.dsl.core.add
import splitties.views.dsl.core.lParams
import splitties.views.dsl.core.wrapContent
import java.util.*
class ArticleDetailContentViewHolder(
@ -42,12 +52,10 @@ class ArticleDetailContentViewHolder(
forumContainer.background = R.drawable.bg_shape_f5_radius_6.toDrawable(binding.root.context)
userNameTv.setTextColor(R.color.text_title.toColor(binding.root.context))
badgeTv.setTextColor(R.color.text_subtitleDesc.toColor(binding.root.context))
releaseTimeTv.setTextColor(R.color.text_subtitleDesc.toColor(binding.root.context))
lastEditTimeTv.setTextColor(R.color.text_subtitleDesc.toColor(binding.root.context))
followBtn.setTextColor(R.color.theme_font.toColor(binding.root.context))
approvalStatusTv.setTextColor(R.color.theme_green.toColor(binding.root.context))
titleTv.setTextColor(R.color.text_title.toColor(binding.root.context))
originalTv.setTextColor(R.color.theme_font.toColor(binding.root.context))
lastEditTimeTv.setTextColor(R.color.text_subtitleDesc.toColor(binding.root.context))
gameName.setTextColor(R.color.text_subtitleDesc.toColor(binding.root.context))
richEditor.enableForceDark(DarkModeUtils.isDarkModeOn(binding.root.context))
@ -81,7 +89,6 @@ class ArticleDetailContentViewHolder(
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", "帖子详情")
}
})
originalTv.goneIf(article.original != "yes")
approvalStatusTv.goneIf(article.status == "pass")
statusContainer.visibleIf(article.status != "pass")
when (article.status) {
@ -156,11 +163,20 @@ class ArticleDetailContentViewHolder(
"帖子详情"
)
}
labelIv.goneIf(article.getSimplifyChoicenessStatus() != "pass")
if (article.getSimplifyChoicenessStatus() == "pass") {
labelIv.setImageDrawable(R.drawable.ic_essence_label.toDrawable())
titleTv.text = if (article.getSimplifyChoicenessStatus() == "pass" || article.original == "yes") {
SpannableStringBuilder(" ${article.title}").apply {
getLabelBitmap(article)?.let {
setSpan(
CenterImageSpan(
binding.root.context,
it
), 0, 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
}
}
} else {
article.title
}
titleTv.text = article.title
userNameTv.text = article.user.name
userIconIv.display(article.user.border, article.user.icon, article.user.auth?.icon)
richEditor.setContentOwner(article.me.isContentOwner)
@ -169,13 +185,25 @@ class ArticleDetailContentViewHolder(
richEditor.setHtml(article.content, true)
}
if (article.source != null && article.source.region.isNotEmpty()) {
releaseTimeTv.text = "${NewsUtils.getFormattedTime(article.time.create)} · ${article.source.region}"
} else {
releaseTimeTv.text = "${NewsUtils.getFormattedTime(article.time.create)}"
regionTv.goneIf(article.source?.region.isNullOrEmpty())
regionTv.text = article.source?.region
lastEditTimeTv.text = NewsUtils.getFormattedTime(article.time.edit)
lastEditTimeTv.setDrawableEnd(
if (article.time.create != article.time.edit) AppCompatResources.getDrawable(
lastEditTimeTv.context,
R.drawable.icon_revise
) else null
)
lastEditTimeTv.setOnClickListener {
if (lastEditTimeTv.context is AppCompatActivity && article.time.editHistory.isNotEmpty()) {
val timeList = ArrayList(article.time.editHistory)
// 需加上首次发布时间
if (article.time.create != 0L) {
timeList.add(article.time.create)
}
EditHistoryDialog.show(lastEditTimeTv.context as AppCompatActivity, timeList)
}
}
lastEditTimeTv.goneIf(article.time.create == article.time.edit)
lastEditTimeTv.text = "最后编辑于${NewsUtils.getFormattedTime(article.time.edit)}"
richEditor.visibility = View.VISIBLE
article.community.let { entity ->
@ -203,9 +231,30 @@ class ArticleDetailContentViewHolder(
followBtn.isEnabled = true
updateFollowBtn(article.me.isFollower)
}
if (article.tagActivityId.isNotEmpty() && article.tagActivityName.isNotEmpty()) {
activityNameTv.text = article.tagActivityName
tagContainer.isVisible = article.sections.isNotEmpty() || article.activityTag != null
if (article.sections.isNotEmpty() && article.sections[0].id.isNotEmpty() && article.sections[0].name.isNotEmpty()) {
sectionNameTv.text = article.sections[0].name
sectionNameTv.visibility = View.VISIBLE
sectionNameTv.setOnClickListener {
DirectUtils.directForumDetailSection(
binding.root.context,
article.community.id,
article.sections[0].id,
mEntrance
)
}
} else {
sectionNameTv.visibility = View.GONE
}
if (article.activityTag != null) {
activityNameTv.text = article.activityTag.name
activityNameTv.visibility = View.VISIBLE
activityNameTv.setOnClickListener {
article.activityTag.link?.let {
DirectUtils.directToLinkPage(binding.root.context, it, mEntrance, "话题标签")
}
}
} else {
activityNameTv.visibility = View.GONE
}
@ -237,6 +286,27 @@ class ArticleDetailContentViewHolder(
}
}
private fun getLabelBitmap(article: ArticleDetailEntity): Bitmap? {
val context = binding.root.context
return LinearLayout(binding.root.context).apply {
setVerticalGravity(Gravity.CENTER)
if (article.getSimplifyChoicenessStatus() == "pass") {
add(ImageView(context).apply {
setImageResource(R.drawable.ic_essence)
}, lParams(wrapContent, wrapContent) {
setMargins(0, 0, 4F.dip2px(), 0)
})
}
if (article.original == "yes") {
add(ImageView(context).apply {
setImageResource(R.drawable.label_original)
}, lParams(wrapContent, wrapContent) {
setMargins(0, 0, 8F.dip2px(), 0)
})
}
}.convertViewToBitmap()
}
/**
* 回调列表视频播放结束时的时间
*/

View File

@ -769,21 +769,43 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
)
ImageUtils.display(mBinding.userAvatar, articleDetail.user.icon)
mBinding.forumTitleTv.text = articleDetail.community.name
if (!mEntrance.contains("论坛详情")) {
mBinding.forumContainer.visibility = View.VISIBLE
mBinding.userContainer.visibility = View.GONE
}
val icon =
if (!articleDetail.community.icon.isNullOrEmpty()) articleDetail.community.icon else articleDetail.community.game?.getIcon()
val iconSubscript =
if (!articleDetail.community.iconSubscript.isNullOrEmpty()) articleDetail.community.iconSubscript else articleDetail.community.game?.iconSubscript
mBinding.forumIv.displayGameIcon(icon, iconSubscript, articleDetail.community.game?.iconFloat)
mBinding.forumNameTv.text = articleDetail.community.name
mBinding.forumContainer.setOnClickListener {
DirectUtils.directForumDetail(requireContext(), articleDetail.community.id, "帖子详情")
}
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (!mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() > 56F.dip2px()) {
mBinding.userAvatar.visibility = View.VISIBLE
mAttentionMenu?.isVisible = articleDetail.user.id != UserManager.getInstance().userId
mBinding.forumTitleTv.visibility = View.VISIBLE
mBinding.forumTitleTv.text = articleDetail.user.name
mBinding.userNameTv.visibility = View.VISIBLE
mBinding.userNameTv.text = articleDetail.user.name
mIsToolbarUserShow = true
if (!mEntrance.contains("论坛详情")) {
mBinding.forumContainer.visibility = View.GONE
mBinding.userContainer.visibility = View.VISIBLE
}
} else if (mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() <= 56F.dip2px()) {
mBinding.userAvatar.visibility = View.GONE
mAttentionMenu?.isVisible = false
mBinding.forumTitleTv.visibility = View.GONE
mBinding.userNameTv.visibility = View.GONE
mIsToolbarUserShow = false
if (!mEntrance.contains("论坛详情")) {
mBinding.forumContainer.visibility = View.VISIBLE
mBinding.userContainer.visibility = View.GONE
}
}
}

View File

@ -0,0 +1,88 @@
package com.gh.gamecenter.qa.article.detail
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.databinding.DialogEditHistoryBinding
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.user.avatar.ChooseDefaultAvatarDialog
import splitties.views.dsl.core.add
import splitties.views.dsl.core.lParams
import splitties.views.dsl.core.wrapContent
class EditHistoryDialog : BaseDialogFragment() {
private var mBinding: DialogEditHistoryBinding? = null
private var mEditHistoryArray: LongArray? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return DialogEditHistoryBinding.inflate(layoutInflater, null, false).apply {
mBinding = this
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mEditHistoryArray = requireArguments().getLongArray(EntranceConsts.KEY_EDIT_HISTORY)
mBinding?.run {
cancelTv.setOnClickListener {
dismissAllowingStateLoss()
}
maskView.goneIf((mEditHistoryArray?.size ?: 0) <= 10)
if ((mEditHistoryArray?.size ?: 0) > 10) {
contentContainer.setPadding(0, 0, 8F.dip2px(), 22F.dip2px())
}
mEditHistoryArray?.forEach {
contentContainer.add(
getTimeTextView(it),
contentContainer.lParams(contentContainer.wrapContent, 22F.dip2px())
)
}
}
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
private fun getTimeTextView(time: Long): TextView = TextView(requireContext()).apply {
text = TimeUtils.getFormatTime(time, "-yyyy-MM-dd HH:mm:ss")
gravity = Gravity.CENTER
setTextColor(R.color.text_subtitle.toColor(requireContext()))
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(true)
val window = createDialog.window
window?.setGravity(Gravity.CENTER)
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return createDialog
}
companion object {
fun show(activity: AppCompatActivity, editHistory: List<Long>) {
EditHistoryDialog().apply {
arguments = bundleOf(EntranceConsts.KEY_EDIT_HISTORY to editHistory.toLongArray())
}.show(activity.supportFragmentManager, ChooseDefaultAvatarDialog::class.java.name)
}
}
}

View File

@ -129,6 +129,7 @@ class NewCommentDetailActivity : ToolBarActivity() {
) = Bundle().apply {
putString(EntranceConsts.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
putInt(EntranceConsts.KEY_POSITION, 1)
putBoolean(EntranceConsts.KEY_USE_ALTERNATIVE_LAYOUT, true)
putString(EntranceConsts.KEY_COMMENT_ID, commentId)
putString(EntranceConsts.KEY_TOP_COMMENT_ID, topCommentId)
putString(EntranceConsts.KEY_PATH, path)

View File

@ -8,6 +8,8 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.ethanhua.skeleton.Skeleton
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.core.AppExecutor
@ -35,6 +37,8 @@ class CommentConversationFragment :
private lateinit var mBinding: FragmentArticleDetailCommentBinding
private var mAdapterCommunity: CommentConversationAdapter? = null
private var mUseAlternativeLayout = false // 是否使用特殊布局,隐藏顶部条数显示、额外顶部间距等
override fun getLayoutId() = 0
override fun getInflatedLayout() =
@ -47,9 +51,11 @@ class CommentConversationFragment :
override fun onCreate(savedInstanceState: Bundle?) {
mViewModel = provideListViewModel()
super.onCreate(savedInstanceState)
mUseAlternativeLayout = arguments?.getBoolean(EntranceConsts.KEY_USE_ALTERNATIVE_LAYOUT) ?: false
mViewModel.getComment()
mViewModel.positionInOriginList = arguments?.getInt(EntranceConsts.KEY_POSITION)
?: -1
mViewModel.positionInOriginList = arguments?.getInt(EntranceConsts.KEY_POSITION) ?: -1
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -109,6 +115,14 @@ class CommentConversationFragment :
inputContainer.bottomStarIv.visibility = View.GONE
inputContainer.bottomStarTv.visibility = View.GONE
// 取消掉
if (mUseAlternativeLayout) {
toolbarContainer.root.visibility = View.GONE
container.updateLayoutParams { this as FrameLayout.LayoutParams
setMargins(0, 0, 0, 0)
}
}
inputContainer.replyTv.setRoundedColorBackground(R.color.background_space_2, 19F)
inputContainer.replyTv.setDebouncedClickListener {
mViewModel.commentDetail?.let { startCommentActivity(it) }

View File

@ -2,6 +2,8 @@ package com.gh.gamecenter.qa.entity
import android.os.Parcelable
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.feature.entity.UserEntity
import com.gh.gamecenter.feature.entity.*
import com.google.gson.annotations.SerializedName
@ -42,6 +44,9 @@ class ArticleDetailEntity(
var status: String? = "pass",//pass通过fail未通过pending审核中
var original: String? = "",
val source: SourceEntity? = null,
@SerializedName("activity_tag")
val activityTag: ActivityTagEntity? = null,
var sections: List<SectionEntity> = ArrayList(),
@SerializedName("section_id")
var sectionIdList: List<String> = ArrayList()
) : Parcelable {
@ -55,4 +60,19 @@ class ArticleDetailEntity(
}
}
@Parcelize
class SectionEntity(
@SerializedName("_id")
val id: String = "",
val name: String = ""
) : Parcelable
@Parcelize
class ActivityTagEntity(
@SerializedName("_id")
val id: String = "",
val name: String = "",
val link: LinkEntity? = null
) : Parcelable

View File

@ -53,7 +53,10 @@ class QuestionsDetailEntity(
var draftId: String = "",
@SerializedName("images_info")
var imagesInfo: List<ImageInfo> = ArrayList(),
val source: SourceEntity? = null
val source: SourceEntity? = null,
@SerializedName("activity_tag")
val activityTag: ActivityTagEntity? = null,
var sections: List<SectionEntity> = ArrayList()
) : Parcelable {
fun getFollowCount(): Int {

View File

@ -401,20 +401,20 @@ class NewQuestionDetailFragment :
mViewModel.getCommentText(questionDetail.count.answer, "回答")
ImageUtils.display(mBinding.userAvatar, questionDetail.user.icon)
mBinding.forumTitleTv.text = questionDetail.community.name
mBinding.userNameTv.text = questionDetail.community.name
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (!mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() > 56F.dip2px()) {
mBinding.userAvatar.visibility = View.VISIBLE
mAttentionMenu?.isVisible = questionDetail.user.id != UserManager.getInstance().userId
mBinding.forumTitleTv.visibility = View.VISIBLE
mBinding.forumTitleTv.text = questionDetail.user.name
mBinding.userNameTv.visibility = View.VISIBLE
mBinding.userNameTv.text = questionDetail.user.name
mIsToolbarUserShow = true
} else if (mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() <= 56F.dip2px()) {
mBinding.userAvatar.visibility = View.GONE
mAttentionMenu?.isVisible = false
mBinding.forumTitleTv.visibility = View.GONE
mBinding.userNameTv.visibility = View.GONE
mIsToolbarUserShow = false
}
}

View File

@ -2,16 +2,19 @@ package com.gh.gamecenter.qa.questions.newdetail
import android.annotation.SuppressLint
import android.app.Activity
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.View
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.DefaultUrlHandler
import com.gh.gamecenter.core.runOnUiThread
import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.NewLogUtils
import com.gh.common.view.RichEditor
@ -19,9 +22,11 @@ import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.ItemArticleDetailContentBinding
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.article.detail.EditHistoryDialog
import com.gh.gamecenter.qa.editor.OnLinkClickListener
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
import java.util.*
@ -135,9 +140,14 @@ class QuestionDetailContentViewHolder(
?: "", "提问帖", question.community.id, bbsType
)
}
titleTv.text = question.title
labelIv.visibility = View.VISIBLE
labelIv.setImageDrawable(if (question.finish) R.drawable.ic_ask_solved_label.toDrawable() else R.drawable.ic_ask_unsolved_label.toDrawable())
titleTv.text = SpannableStringBuilder(" ${question.title}").apply {
setSpan(
CenterImageSpan(
binding.root.context,
if (question.finish) R.drawable.ic_ask_solved_label else R.drawable.ic_ask_unsolved_label
), 0, 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
}
userNameTv.text = question.user.name
userIconIv.display(question.user.border, question.user.icon, question.user.auth?.icon)
richEditor.setContentOwner(question.me.isContentOwner)
@ -146,13 +156,20 @@ class QuestionDetailContentViewHolder(
richEditor.setHtml(question.description, true)
}
if (question.source != null && question.source.region.isNotEmpty()) {
releaseTimeTv.text = "${NewsUtils.getFormattedTime(question.time.create)} · ${question.source.region}"
} else {
releaseTimeTv.text = "${NewsUtils.getFormattedTime(question.time.create)}"
regionTv.goneIf(question.source?.region.isNullOrEmpty())
regionTv.text = question.source?.region
lastEditTimeTv.text = NewsUtils.getFormattedTime(question.time.edit)
lastEditTimeTv.setDrawableEnd(
if (question.time.create != question.time.edit) AppCompatResources.getDrawable(
lastEditTimeTv.context,
R.drawable.icon_revise
) else null
)
lastEditTimeTv.setOnClickListener {
if (lastEditTimeTv.context is AppCompatActivity && question.time.editHistory.isNotEmpty()) {
EditHistoryDialog.show(lastEditTimeTv.context as AppCompatActivity, question.time.editHistory)
}
}
lastEditTimeTv.goneIf(question.time.create == question.time.edit)
lastEditTimeTv.text = "最后编辑于${NewsUtils.getFormattedTime(question.time.edit)}"
richEditor.visibility = View.VISIBLE
question.community.let { entity ->
@ -181,9 +198,29 @@ class QuestionDetailContentViewHolder(
updateFollowBtn(question.me.isFollower)
}
if (question.tagActivityId.isNotEmpty() && question.tagActivityName.isNotEmpty()) {
activityNameTv.text = question.tagActivityName
tagContainer.isVisible = question.sections.isNotEmpty() || question.activityTag != null
if (question.sections.isNotEmpty() && question.sections[0].id.isNotEmpty() && question.sections[0].name.isNotEmpty()) {
sectionNameTv.text = question.sections[0].name
sectionNameTv.visibility = View.VISIBLE
sectionNameTv.setOnClickListener {
DirectUtils.directForumDetailSection(
binding.root.context,
question.community.id,
question.sections[0].id,
mEntrance
)
}
} else {
sectionNameTv.visibility = View.GONE
}
if (question.activityTag != null) {
activityNameTv.text = question.activityTag.name
activityNameTv.visibility = View.VISIBLE
activityNameTv.setOnClickListener {
question.activityTag.link?.let {
DirectUtils.directToLinkPage(binding.root.context, it, mEntrance, "话题标签")
}
}
} else {
activityNameTv.visibility = View.GONE
}

View File

@ -1,8 +1,14 @@
package com.gh.gamecenter.qa.video.detail.desc
import android.animation.ValueAnimator
import android.graphics.Bitmap
import android.text.Layout
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
@ -18,13 +24,15 @@ import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.entity.NormalShareEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.core.utils.CenterImageSpan
import com.gh.gamecenter.databinding.ItemVideoDescTopBinding
import com.gh.gamecenter.feature.entity.ForumVideoEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.dialog.MoreFunctionPanelDialog
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailViewModel
import kotlin.math.max
import splitties.views.dsl.core.add
import splitties.views.dsl.core.lParams
import splitties.views.dsl.core.wrapContent
class VideoDescTopViewHolder(
val binding: ItemVideoDescTopBinding,
@ -51,11 +59,29 @@ class VideoDescTopViewHolder(
if (entity.me.isFollower) R.drawable.button_round_gray_light.toDrawable() else R.drawable.button_round_primary_light.toDrawable()
setTextColor(if (entity.me.isFollower) R.color.text_subtitleDesc.toColor() else R.color.theme_font.toColor())
}
binding.titleTv.text = entity.title
binding.titleTv.text = if (entity.getSimplifyChoicenessStatus() == "pass" || entity.original == "yes") {
SpannableStringBuilder(" ${entity.title}").apply {
getLabelBitmap(entity)?.let {
setSpan(
CenterImageSpan(
binding.root.context,
it
), 0, 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
}
}
} else {
entity.title
}
binding.desTv.text = entity.des
binding.desTv.goneIf(entity.des.isEmpty())
binding.activityNameTv.goneIf(entity.tagActivityName.isEmpty())
binding.activityNameTv.text = entity.tagActivityName
binding.activityNameTv.goneIf(entity.activityTag == null)
binding.activityNameTv.text = entity.activityTag?.name
binding.activityNameTv.setOnClickListener {
entity.activityTag?.link?.let {
DirectUtils.directToLinkPage(binding.root.context, it, "视频贴详情", "话题标签")
}
}
binding.userAvatar.display(entity.user.border, entity.user.icon, entity.user.auth?.icon)
binding.likeIv.setImageDrawable(if (entity.me.isVoted) R.drawable.ic_forum_video_detail_liked.toDrawable() else R.drawable.ic_forum_video_detail_like.toDrawable())
binding.likeCountTv.text = entity.count.vote.toString()
@ -66,16 +92,19 @@ class VideoDescTopViewHolder(
binding.shareIv.setImageDrawable(R.drawable.ic_forum_video_detail_share.toDrawable())
binding.shareTv.text = entity.share.toString()
if (entity.original == "yes") {
binding.originalTv.visibility = View.VISIBLE
binding.activityNameTv.layoutParams =
(binding.activityNameTv.layoutParams as ConstraintLayout.LayoutParams).apply {
leftMargin = 8f.dip2px()
}
}
if (entity.getSimplifyChoicenessStatus() == "pass") {
binding.titleTv.text =
SpanBuilder(" ${entity.title}").image(0, 1, R.drawable.ic_essence).build()
if (entity.sections.isNotEmpty() && entity.sections[0].id.isNotEmpty() && entity.sections[0].name.isNotEmpty()) {
binding.sectionNameTv.text = entity.sections[0].name
binding.sectionNameTv.visibility = View.VISIBLE
binding.sectionNameTv.setOnClickListener {
DirectUtils.directForumDetailSection(
binding.root.context,
entity.bbs?.id,
entity.sections[0].id,
"视频贴详情"
)
}
} else {
binding.sectionNameTv.visibility = View.GONE
}
initAnimation(entity)
@ -159,35 +188,25 @@ class VideoDescTopViewHolder(
private fun initAnimation(entity: ForumVideoEntity) {
binding.root.post {
mShrinkHeight = if (mShrinkHeight == 0) {
getTextViewHeight(binding.titleTv, 1)
getTextViewHeight(binding.titleTv, 2)
} else mShrinkHeight
mExpandHeight = if (mExpandHeight == 0) {
var height = getTextViewHeight(binding.titleTv) +
getTextViewHeight(binding.desTv) +
(if (binding.desTv.visibility == View.VISIBLE) binding.desTv.marginTop else 0) +
(if (binding.activityNameTv.visibility == View.VISIBLE || binding.originalTv.visibility == View.VISIBLE) binding.activityNameTv.marginTop else 0)
if (binding.activityNameTv.visibility == View.VISIBLE || binding.originalTv.visibility == View.VISIBLE) {
height += max(
getTextViewHeight(binding.activityNameTv),
binding.originalTv.measuredHeight
)
}
height
getTextViewHeight(binding.titleTv) + getTextViewHeight(binding.desTv) + (if (binding.desTv.visibility == View.VISIBLE) binding.desTv.marginTop else 0)
} else mExpandHeight
if (mIsExpand) {
binding.titleTv.maxLines = Int.MAX_VALUE
updateTitleContainerHeight(mExpandHeight)
} else {
binding.titleTv.maxLines = 1
binding.titleTv.maxLines = 2
updateTitleContainerHeight(mShrinkHeight)
}
//若标题未超过一行或无描述内容、活动标签、原创标签,箭头不显示
//若标题未超过一行或无描述内容,箭头不显示
val ellipsisCount =
binding.titleTv.layout?.getEllipsisCount(binding.titleTv.lineCount - 1) ?: 0
binding.expandMoreIv.goneIf(entity.des.isEmpty() && entity.tagActivityName.isEmpty() && entity.original != "yes" && ellipsisCount == 0)
binding.expandMoreIv.goneIf(entity.des.isEmpty() && ellipsisCount == 0)
}
binding.expandMoreIv.setOnClickListener {
NewLogUtils.logVideoDetailClick(if (!mIsExpand) "click_detail_tab_down" else "click_detail_tab_up")
@ -209,7 +228,7 @@ class VideoDescTopViewHolder(
}
animator.doOnEnd {
if (mIsExpand) {
binding.titleTv.maxLines = 1
binding.titleTv.maxLines = 2
}
mIsExpand = !mIsExpand
binding.expandMoreIv.rotation = if (mIsExpand) 180f else 0f
@ -250,8 +269,33 @@ class VideoDescTopViewHolder(
private fun getTextViewHeight(view: TextView, lineCount: Int = 0): Int {
if (view.visibility == View.GONE) return 0
val layout: Layout = view.layout ?: return 0
val desired: Int = layout.getLineTop(if (lineCount > 0) lineCount else view.lineCount)
val desired: Int = try {
layout.getLineTop(if (lineCount > 0) lineCount else view.lineCount)
} catch (e: ArrayIndexOutOfBoundsException) {
layout.getLineTop(view.lineCount)
}
val padding = view.compoundPaddingTop + view.compoundPaddingBottom
return desired + padding
}
private fun getLabelBitmap(entity: ForumVideoEntity): Bitmap? {
val context = binding.root.context
return LinearLayout(binding.root.context).apply {
setVerticalGravity(Gravity.CENTER)
if (entity.getSimplifyChoicenessStatus() == "pass") {
add(ImageView(context).apply {
setImageResource(R.drawable.ic_essence)
}, lParams(wrapContent, wrapContent) {
setMargins(0, 0, 4F.dip2px(), 0)
})
}
if (entity.original == "yes") {
add(ImageView(context).apply {
setImageResource(R.drawable.label_original)
}, lParams(wrapContent, wrapContent) {
setMargins(0, 0, 8F.dip2px(), 0)
})
}
}.convertViewToBitmap()
}
}

View File

@ -97,7 +97,7 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
val source = listOf(ExposureSource("首页搜索 -> 搜索榜单", "${rankList.title}-${rank.name}"))
if (rank.link.type == "game") {
rank.exposureEvent = ExposureEvent.createEvent(
rank.toGameEntity().apply {
rank.linkGame?.toGameEntity()?.apply {
outerSequence = outIndex
sequence = index
},

View File

@ -172,7 +172,7 @@ class SearchGameIndexAdapter(
|| gameEntity.contentTag!!.server
|| gameEntity.contentTag!!.isBbsExists)
val isShowTagByMirror =
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.mirrorData?.contentTagStatus == "on" else isShowTag
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.obtainMirrorData()?.contentTagStatus == "on" else isShowTag
tagContainer.goneIf(!isShowTagByMirror)
if (isShowTagByMirror) {
val screenWidth = mContext.resources.displayMetrics.widthPixels
@ -228,7 +228,7 @@ class SearchGameIndexAdapter(
StringUtils.buildString(
entrance, "+(搜索-列表[", key, "=", "$type=",
(holder.adapterPosition + 1).toString(), "])"
), GameDetailFragment.INDEX_TRENDES, traceEvent = exposureEvent
), GameDetailFragment.TAB_TRENDS, traceEvent = exposureEvent
)
gameEntity.run {
@ -290,7 +290,7 @@ class SearchGameIndexAdapter(
StringUtils.buildString(
entrance, "+(搜索-列表[", key, "=", "$type=",
(holder.adapterPosition + 1).toString(), "])"
), GameDetailFragment.INDEX_BBS, traceEvent = exposureEvent
), GameDetailFragment.TAB_BBS, traceEvent = exposureEvent
)
gameEntity.run {
@ -308,7 +308,7 @@ class SearchGameIndexAdapter(
}
if (tagContainer.childCount < 4 && gameEntity.contentTag!!.server) {
if (!gameEntity.shouldUseMirrorInfo() || (gameEntity.shouldUseMirrorInfo() && gameEntity.mirrorData?.mirrorServer?.calendar?.isNotEmpty() == true)) {
if (!gameEntity.shouldUseMirrorInfo() || (gameEntity.shouldUseMirrorInfo() && gameEntity.obtainMirrorData()?.mirrorServer?.calendar?.isNotEmpty() == true)) {
val serverView = getContentTagView(
R.drawable.ic_label_server,
"",
@ -373,7 +373,7 @@ class SearchGameIndexAdapter(
SearchType.fromString(type).toChinese(),
gameEntity.id,
gameEntity.name,
gameEntity.shouldUseMirrorInfo(),
gameEntity.getMirrorPosition(),
gameEntity.adIconActive
)
}
@ -428,7 +428,7 @@ class SearchGameIndexAdapter(
SearchType.fromString(type).toChinese(),
gameEntity.id,
gameEntity.name,
gameEntity.shouldUseMirrorInfo(),
gameEntity.getMirrorPosition(),
gameEntity.adIconActive
)
}
@ -476,7 +476,7 @@ class SearchGameIndexAdapter(
SearchType.fromString(type).toChinese(),
gameEntity.id,
gameEntity.name,
gameEntity.shouldUseMirrorInfo(),
gameEntity.getMirrorPosition(),
gameEntity.adIconActive
)
}

View File

@ -152,7 +152,7 @@ class SearchGameResultAdapter(
|| gameEntity.contentTag!!.isLibaoExists
|| gameEntity.contentTag!!.server)
val isShowTagByMirror =
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.mirrorData?.contentTagStatus == "on" else isShowTag
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.obtainMirrorData()?.contentTagStatus == "on" else isShowTag
if (isShowTagByMirror) {
topDivider.visibility = View.GONE
} else {
@ -244,7 +244,7 @@ class SearchGameResultAdapter(
|| gameEntity.contentTag!!.server
|| gameEntity.contentTag!!.isBbsExists)
val isShowTagByMirror =
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.mirrorData?.contentTagStatus == "on" else isShowTag
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.obtainMirrorData()?.contentTagStatus == "on" else isShowTag
tagContainer.goneIf(!isShowTagByMirror)
if (isShowTagByMirror && gameEntity.contentTag != holder.contentTag) {
holder.contentTag = gameEntity.contentTag
@ -300,7 +300,7 @@ class SearchGameResultAdapter(
StringUtils.buildString(
entrance, "+(搜索-列表[", key, "=", "$type=",
(holder.adapterPosition + 1).toString(), "])"
), GameDetailFragment.INDEX_TRENDES, traceEvent = exposureEvent
), GameDetailFragment.TAB_TRENDS, traceEvent = exposureEvent
)
gameEntity.run {
@ -360,7 +360,7 @@ class SearchGameResultAdapter(
StringUtils.buildString(
entrance, "+(搜索-列表[", key, "=", "$type=",
(holder.adapterPosition + 1).toString(), "])"
), GameDetailFragment.INDEX_BBS, traceEvent = exposureEvent
), GameDetailFragment.TAB_BBS, traceEvent = exposureEvent
)
gameEntity.run {
@ -378,7 +378,7 @@ class SearchGameResultAdapter(
}
if (tagContainer.childCount < 4 && gameEntity.contentTag!!.server) {
if (!gameEntity.shouldUseMirrorInfo() || (gameEntity.shouldUseMirrorInfo() && gameEntity.mirrorData?.mirrorServer?.calendar?.isNotEmpty() == true)) {
if (!gameEntity.shouldUseMirrorInfo() || (gameEntity.shouldUseMirrorInfo() && gameEntity.obtainMirrorData()?.mirrorServer?.calendar?.isNotEmpty() == true)) {
val serverView = getContentTagView(
R.drawable.ic_label_server,
"",
@ -438,7 +438,7 @@ class SearchGameResultAdapter(
SearchType.fromString(type).toChinese(),
gameEntity.id,
gameEntity.name,
gameEntity.shouldUseMirrorInfo(),
gameEntity.getMirrorPosition(),
gameEntity.adIconActive
)
@ -491,7 +491,7 @@ class SearchGameResultAdapter(
SearchType.fromString(type).toChinese(),
gameEntity.id,
gameEntity.name,
gameEntity.shouldUseMirrorInfo(),
gameEntity.getMirrorPosition(),
gameEntity.adIconActive
)

View File

@ -88,7 +88,7 @@ class GameServersActivity : DownloadToolbarActivity() {
{ MtaHelper.onEvent("开服表", "Tab", if (mServersTest?.isChecked == true) "开测" else "开服") }
// init viewpager
mFragments.add(GameServersPublishFragment())
mFragments.add(GameServersTestFragment())
mFragments.add(GameServersTestFragment().with(intent.extras))
mViewpager?.setScrollable(false)
mViewpager?.offscreenPageLimit = 1
mViewpager?.adapter = FragmentAdapter(supportFragmentManager, mFragments)

View File

@ -155,6 +155,8 @@ class GameServersTestFragment : LazyFragment() {
val exposureSource = if (arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE) != null) {
listOf<ExposureSource>(arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE)!!)
} else if (requireArguments().getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST) != null) {
requireArguments().getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
} else {
null
}

View File

@ -7,6 +7,8 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.feature.exposure.ExposureEvent
import java.util.ArrayList
class GameServerTestV2Activity : ToolBarActivity() {
@ -26,9 +28,15 @@ class GameServerTestV2Activity : ToolBarActivity() {
}
companion object {
fun getIntent(context: Context, entrance: String): Intent {
fun getIntent(context: Context, entrance: String, exposureEvent: ExposureEvent? = null): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
exposureEvent?.let {
bundle.putParcelableArrayList(
EntranceConsts.KEY_EXPOSURE_SOURCE_LIST,
ArrayList(exposureEvent.source)
)
}
return getTargetIntent(
context,
GameServerTestV2Activity::class.java,

View File

@ -86,6 +86,7 @@ class GameServerTestV2ListAdapter(
if (isTheLastOfTheLatestConsecutiveGame) 16F.dip2px() else 8F.dip2px()
)
holder.bindGameItem(gameEntity, forceShowSubtitle = true)
holder.binding.gameDes.setTextColor(R.color.text_title.toColor(context))
initGameItemViewHolder(gameEntity, holder, position)
}
is GameBigImageViewHolder -> {
@ -154,7 +155,7 @@ class GameServerTestV2ListAdapter(
gameEntity,
GameViewHolder(viewHolder.binding),
true,
"star&brief"
// "star&brief"
)
viewHolder.binding.gameDes.text = gameEntity.brief
viewHolder.itemView.setOnClickListener {

View File

@ -187,6 +187,8 @@ class GameServerTestV2ListFragment :
val exposureSource =
if (requireArguments().getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE) != null) {
listOf<ExposureSource>(requireArguments().getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE)!!)
} else if (requireArguments().getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST) != null) {
requireArguments().getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
} else {
null
}

View File

@ -79,6 +79,7 @@ class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: Attrib
private var mVolumeObserver: VolumeObserver
private var mScheduledHideDisposable: Disposable? = null //延迟隐藏mBottomContainer计时器
private var mLastClickTime = 0L
private var mLastGetContentLengthTime = 0L
private var mLottieLike: LottieAnimationView? = null
private var mHandler: Handler? = null
private var weChatAnimate: AnimatorSet? = null
@ -1049,7 +1050,11 @@ class DetailPlayerView @JvmOverloads constructor(context: Context, attrs: Attrib
val videoTotalTime = duration / 1000
val progress = if (videoTotalTime != 0) videoPlayTs.toFloat() / videoTotalTime.toFloat() * 100 else 0f
if (mContentLength == 0.0) {
mContentLength = ExoCacheManager.getContentLength(mVideoEntity!!.url) / 1024.0 / 1024.0
val newGetContentLengthTime = System.currentTimeMillis()
if (newGetContentLengthTime - mLastGetContentLengthTime > 5000) {
mLastGetContentLengthTime = newGetContentLengthTime
mContentLength = ExoCacheManager.getContentLength(mVideoEntity!!.url) / 1024.0 / 1024.0
}
}
//https://exoplayer.dev/hello-world.html#a-note-on-threading
runOnUiThread {

View File

@ -149,10 +149,7 @@ class HomeRecentVGameAdapter(context: Context) : DiffUtilAdapter<VGameItemData>(
}
} else {
binding.root.setOnClickListener {
VHelper.installOrLaunch(
binding.root.context,
downloadEntity.packageName
)
VHelper.installOrLaunch(binding.root.context, downloadEntity)
}
}
}

View File

@ -180,7 +180,7 @@ class VDownloadManagerAdapter(
}
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
?: VHelper.getDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
?: VHelper.getVDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
updateDownloadBtnAndDes(
mContext,
@ -527,7 +527,7 @@ class VDownloadManagerAdapter(
btnText = context.getString(R.string.launch)
setOnClickListener {
CurrentActivityHolder.getCurrentActivity()?.let {
VHelper.installOrLaunch(it, downloadEntity.packageName)
VHelper.installOrLaunch(it, downloadEntity)
}
}
}

View File

@ -126,6 +126,9 @@ object VHelper {
// 是否已经尝试过重连
private var mHasAlreadyTriedReConnect = false
// 临时的用来临时匹配安装完成时包名对应的游戏 ID 的 Map
private var mTempPackageNameAndGameIdMap = hashMapOf<String, String>()
val vGameLiveData by lazy { mVGameDao.getAllLiveData() }
private val mVGameObserver by lazy {
@ -385,7 +388,7 @@ object VHelper {
@JvmStatic
fun getVGameSnapshot(gameId: String? = null, packageName: String? = null): VGameEntity? {
return mVGameSnapshotList.find {
it.packageName == packageName && (gameId == null || it.downloadEntity.gameId == gameId)
it.packageName == packageName && (gameId.isNullOrEmpty() || it.downloadEntity.gameId == gameId)
}
}
@ -552,6 +555,9 @@ object VHelper {
if (showDialogIfVSpaceIsNeeded(context, downloadEntity.gameId, downloadEntity.name)) return
// 更新此包名对应的 gameId Map
mTempPackageNameAndGameIdMap[downloadEntity.packageName] = downloadEntity.gameId
// 当且仅当
// 1. 全局安装完成启动游戏开关打开
// 2. 服务连接不成功或是手动触发的安装
@ -680,7 +686,9 @@ object VHelper {
*/
fun onInstallFinished(packageName: String, result: VGameInstallerResult) {
runOnIoThread {
val downloadEntity = getDownloadEntityByPackageName(packageName)
val gameId = mTempPackageNameAndGameIdMap[packageName] ?: ""
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName)
if (downloadEntity != null) {
// 去掉更新标记
@ -753,13 +761,19 @@ object VHelper {
* 游戏是否正在安装中
*/
fun isInstalling(packageName: String): Boolean {
val downloadEntity = getDownloadEntityByPackageName(packageName) ?: return false
val gameId = mTempPackageNameAndGameIdMap[packageName] ?: ""
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName) ?: return false
return (mInstallingVaPathSet.contains(downloadEntity.path))
}
private fun getDownloadEntityByPackageName(packageName: String): DownloadEntity? {
return DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName)
?: getDownloadEntitySnapshot(gameId = null, packageName = packageName)
/**
* 获取实体 (虽然实体是 DownloadEntity 其实就是游戏实体)
* 优先从下载管理里获取(根据 gameId 获取)
* 下载管理不存在时从畅玩游戏数据库的里获取
*/
private fun getVDownloadEntity(gameId: String, packageName: String): DownloadEntity? {
return DownloadManager.getInstance().getDownloadEntitySnapshot("", gameId, true)
?: getVDownloadEntitySnapshot(gameId = gameId, packageName = packageName)
}
private fun insertInstalledGameToProvider(downloadEntity: DownloadEntity, fromRetry: Boolean = false) {
@ -791,11 +805,23 @@ object VHelper {
}
}
fun installOrLaunch(context: Context, downloadEntity: DownloadEntity) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${downloadEntity.gameId}")
installOrLaunch(context, downloadEntity.packageName, downloadEntity.gameId)
}
@JvmStatic
fun installOrLaunch(context: Context, gameEntity: GameEntity) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${gameEntity.id}")
installOrLaunch(context, gameEntity.getUniquePackageName() ?: "", gameEntity.id)
}
/**
* 安装或启动应用
*/
@JvmStatic
fun installOrLaunch(context: Context, packageName: String) {
private fun installOrLaunch(context: Context, packageName: String, gameId: String) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 $packageName")
validateVSpaceBeforeAction(context, null) {
@ -809,7 +835,7 @@ object VHelper {
}
// 检查下载管理是否有下载实体,有实体表明未安装成功
val downloadEntity = getDownloadEntityByPackageName(packageName)
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName)
if (downloadEntity != null) {
val downloadedFile = File(downloadEntity.path)
@ -837,7 +863,7 @@ object VHelper {
// 置空下载挂起回调(能 launch 游戏说明畅玩组件已安装)
mPendingDownloadCallback = null
val downloadEntity = getDownloadEntityByPackageName(packageName)
val downloadEntity = getVDownloadEntity(gameId = "", packageName = packageName)
val gameId = downloadEntity?.gameId ?: "unknown"
val gameName = downloadEntity?.name ?: "unknown"
@ -973,10 +999,10 @@ object VHelper {
}
/**
* 根据游戏 ID 和包名获取下载快照
* 根据游戏 ID 和包名获取畅玩游戏的实体快照
*/
@JvmStatic
fun getDownloadEntitySnapshot(gameId: String?, packageName: String?): DownloadEntity? {
fun getVDownloadEntitySnapshot(gameId: String?, packageName: String?): DownloadEntity? {
return getVGameSnapshot(gameId, packageName)?.downloadEntity
}

View File

@ -153,10 +153,7 @@ object VLoadCompleteWindowHelper {
"启动",
mAdapter.gameEntityList[mBinding.viewPager.currentItem].id
)
VHelper.installOrLaunch(
activity,
mAdapter.gameEntityList[mBinding.viewPager.currentItem].getApk()[0].packageName
)
VHelper.installOrLaunch(activity, mAdapter.gameEntityList[mBinding.viewPager.currentItem])
}
}
}

View File

@ -1,8 +1,12 @@
package com.gh.vspace.db
import androidx.room.TypeConverter
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.common.utils.tryWithDefaultCatch
import com.gh.gamecenter.core.utils.GsonUtils
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import org.json.JSONObject
class VGameConverter {
@ -13,7 +17,35 @@ class VGameConverter {
@TypeConverter
fun convertString2DownloadEntity(string: String): DownloadEntity {
return GsonUtils.fromJson(string, DownloadEntity::class.java)
val downloadEntity = DownloadEntity()
val rawJsonObject = JSONObject(string)
val keys = rawJsonObject.keys()
var tempSize = ""
while (keys.hasNext()) {
val key = keys.next()
val value = rawJsonObject.optString(key)
if (value.startsWith("http")) {
downloadEntity.url = value
} else if (value.endsWith("apk")) {
downloadEntity.path = value
} else if (value.startsWith("{\"")) {
downloadEntity.meta = value.toObject()
downloadEntity.name = downloadEntity.meta["game_name"]
} else if (value == tempSize) {
tryWithDefaultCatch {
downloadEntity.size = value.toLong()
}
} else {
tempSize = value
}
}
downloadEntity.status = DownloadStatus.done
return downloadEntity
}
}

View File

@ -80,7 +80,7 @@ class ShortcutManager private constructor() {
*/
fun tryCreateShortCut(context: Context, gameId: String, gamePkg: String, result: OnCreateShortcutResult) {
VHelper.postOnInitialized {
val downloadEntity = VHelper.getDownloadEntitySnapshot(gameId, gamePkg)
val downloadEntity = VHelper.getVDownloadEntitySnapshot(gameId, gamePkg)
runOnUiThread {
if (downloadEntity == null) {
result.failed()

View File

@ -70,6 +70,7 @@ class WebFragment : LazyFragment(), IScrollable {
private var mToolBoxEntity: ToolBoxEntity? = null
private var newsId: String? = null
private var mBbsId: String? = null // 论坛 id
private var mNavigationTitle: String? = null //导航栏标题
private var mBackConfirmationContent: String? = null //返回确认弹窗内容
private var mGameName: String? = null
@ -290,6 +291,7 @@ class WebFragment : LazyFragment(), IScrollable {
mIsBindWechat = args.getBoolean(KEY_IS_BIND_WECHAT, false)
mIsTools = args.getBoolean(KEY_ISTOOLS, false)
mQaType = args.getInt(KEY_QA_TYPE, -1)
mBbsId = args.getString(EntranceConsts.KEY_BBS_ID)
mAutoCompletionTitle = args.getBoolean(KEY_COMPLETION_TITLE, true)
mNavigationTitle = args.getString(EntranceConsts.KEY_GAMENAME)
newsId = args.getString(EntranceConsts.KEY_NEWSID)
@ -304,7 +306,7 @@ class WebFragment : LazyFragment(), IScrollable {
mLeaveWebpageToHandleTitle = args.getBoolean(KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, false)
mWebUrl = dealWithUrl(args.getString(EntranceConsts.KEY_URL, ""))
}
mJsApi = DefaultJsApi(requireContext(), mEntrance, this)
mJsApi = DefaultJsApi(requireContext(), mEntrance, this, mBbsId)
}
@SuppressLint("SetJavaScriptEnabled")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/background_space" />
<solid android:color="@color/item_game_test_v2_recommend_label" />
<corners
android:radius="4dp" />
</shape>

View File

@ -3,7 +3,7 @@
android:shape="rectangle">
<stroke
android:width="0.5dp"
android:color="@color/divider" />
android:color="@color/item_game_test_v2_stroke" />
<corners android:radius="8dp" />
<solid android:color="@color/background_white" />
<solid android:color="@color/item_game_test_v2" />
</shape>

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