Compare commits

...

194 Commits

Author SHA1 Message Date
1040f5ff4d Merge branch 'sentry/407275' into 'release'
fix: Sentry 407275 修复Z10机型报BadTokenException的异常

See merge request halo/android/assistant-android!1915
2024-10-09 14:56:18 +08:00
97be320529 fix: Sentry 407275 修复Z10机型报BadTokenException的异常 2024-10-09 14:56:18 +08:00
59cde4e2bf Merge branch 'hotfix/v5.37.5-1095/privacy-policy' into 'release'
feat: 优化获取进程名的方式 https://jira.shanqu.cc/browse/GHZSCY-6690

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

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

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

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

See merge request halo/android/assistant-android!1874
2024-09-04 15:43:47 +08:00
d931fb5940 feat: 【光环助手】安装相关优化功能埋点事件的属性字段英文错误的问题 https://jira.shanqu.cc/browse/GHZSCY-6644 2024-09-04 14:42:17 +08:00
cea62b55e2 Merge branch 'hotfix/v5.37.4-1094/GHZSCY-6631' into 'release'
fix: 特定场景下首次启动APP未直接打开设置跳转的页面 https://jira.shanqu.cc/browse/GHZSCY-6631

See merge request halo/android/assistant-android!1871
2024-09-04 11:40:58 +08:00
ff6cdb1ba3 Merge branch 'hotfix/v5.37.4-1094/GHZSCY-6613' into 'release'
fix: 客户端启动过程中若首页视频自动播放会置顶显示在开屏广告上 https://jira.shanqu.cc/browse/GHZSCY-6613

See merge request halo/android/assistant-android!1870
2024-09-04 11:40:43 +08:00
b6e531fa96 fix: 特定场景下首次启动APP未直接打开设置跳转的页面 https://jira.shanqu.cc/browse/GHZSCY-6631 2024-09-04 11:06:39 +08:00
e7a37df690 fix: 客户端启动过程中若首页视频自动播放会置顶显示在开屏广告上 https://jira.shanqu.cc/browse/GHZSCY-6613
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-09-03 17:57:38 +08:00
239b056abb Merge branch 'hotfix/v5.37.4-1094/illegal_state_exception' into 'release'
fix: 修复请求所有文件访问权限弹窗弹出偶发的闪退问题...

See merge request halo/android/assistant-android!1864
2024-08-30 10:05:24 +08:00
315be3797c fix: 修复请求所有文件访问权限弹窗弹出偶发的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/406178/?project=22 2024-08-30 09:49:52 +08:00
bdcca58770 build: fix 编译时无法拉取远端依赖的问题 2024-08-29 15:48:16 +08:00
644b93ab02 fix: 编译问题 2024-08-28 15:10:24 +08:00
1ee0f292ba Revert "fix: 修复因为低级失误导致 sentry.onEvent 方法失效的问题"
This reverts commit 0731cc1fde.
2024-08-26 16:06:59 +08:00
f609637f0b Merge branch 'feat/GHZSCY-6578' into 'release'
feat:【光环助手】设备信息显示 https://jira.shanqu.cc/browse/GHZSCY-6578

See merge request halo/android/assistant-android!1860
2024-08-26 14:07:55 +08:00
9d10add8eb feat:【光环助手】设备信息显示 https://jira.shanqu.cc/browse/GHZSCY-6578 2024-08-26 14:07:54 +08:00
f5a39f982e chore: 版本更新至 5.37.4 2024-08-26 10:33:09 +08:00
1a063bb0c1 Merge branch 'hotfix/v5.37.3-1093/sentry_culprit' into 'release'
fix: 修复因为低级失误导致 sentry.onEvent 方法失效的问题,捕抓更多 deadSystemException

See merge request halo/android/assistant-android!1859
2024-08-26 10:30:37 +08:00
86340d603f fix: 捕抓应用安装完成后上报用户玩过的游戏有机率遇到的 deadSystemException 并上报 sentry https://sentry.shanqu.cc/organizations/lightgame/issues/404487
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-26 10:21:42 +08:00
0731cc1fde fix: 修复因为低级失误导致 sentry.onEvent 方法失效的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-26 10:20:00 +08:00
86dfee2ff9 Merge branch 'hotfix/v5.37.3-1093/null_pointer_exception' into 'release'
fix: 修复获取BusinessId时出现的空指针闪退问题...

See merge request halo/android/assistant-android!1858
2024-08-26 09:58:11 +08:00
edf82952ce fix: 修复获取BusinessId时出现的空指针闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404588/?project=22 2024-08-26 09:54:22 +08:00
4412d159bb Merge branch 'fix/sentry-404504-3' into 'release'
fix: 下载悬浮窗Detach执行图标贴边动画造成的崩溃...

See merge request halo/android/assistant-android!1856
2024-08-23 16:05:11 +08:00
e119b7fecd fix: 下载悬浮窗Detach执行图标贴边动画造成的崩溃... 2024-08-23 16:05:11 +08:00
3fe7c8252e chore: 版本更新至 5.37.3 2024-08-22 11:19:28 +08:00
36ebab77ee Merge branch 'hotfix/v5.37.2-1092/dead_system_exception' into 'release'
fix: catch 部分高频调用的包信息获取方法,遇到 DeadSystemException 时上报 sentry

See merge request halo/android/assistant-android!1853
2024-08-22 11:18:35 +08:00
e84db01984 Merge branch 'hotfix/v5.37.2-1092/view_binding' into 'release'
fix: 用 sentry 记录 SearchToolbarTabWrapperFragment ViewBinding bind 异常时 gid,尝试重试一次

See merge request halo/android/assistant-android!1852
2024-08-22 11:16:36 +08:00
ae605d4a55 fix: 用 sentry 记录 SearchToolbarTabWrapperFragment ViewBinding bind 异常时 gid,尝试重试一次
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-22 11:11:12 +08:00
882bf4b551 fix: catch 部分高频调用的包信息获取方法,遇到 DeadSystemException 时上报 sentry
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-22 10:05:09 +08:00
968164af55 Merge branch 'hotfix/v5.37.2-1092/class_cast_exception' into 'release'
fix: 修复帮助中心分类弹窗弹出时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/405504/?project=22

See merge request halo/android/assistant-android!1850
2024-08-21 10:05:47 +08:00
0119e6f123 fix: 修复帮助中心分类弹窗弹出时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/405504/?project=22 2024-08-21 09:59:40 +08:00
7093552259 Merge branch 'FIX/sentry-404504-2' into 'release'
fix: 悬浮窗Detach时机问题造成的崩溃2

See merge request halo/android/assistant-android!1847
2024-08-20 14:02:02 +08:00
2be52d21ee fix: 悬浮窗Detach时机问题造成的崩溃2 2024-08-20 14:02:02 +08:00
cb093cc3f0 Merge branch 'hotfix/v5.37.1-1091/jobservice_abstract_method_error' into 'release'
fix: 修复 94d0e2b5f19760d22381ead093c9e89778a14bf4 这个版本没有修复的...

See merge request halo/android/assistant-android!1844
2024-08-19 16:08:04 +08:00
3cbdd94189 fix: 修复 94d0e2b5f19760d22381ead093c9e89778a14bf4 这个版本没有修复的 java.lang.AbstractMethodError: abstract method "void android.app.job.IJobService.onNetworkChanged(android.app.job.JobParameters)" 错误。 2024-08-19 16:02:01 +08:00
11013319bf chore: 版本更新至 5.37.2 2024-08-19 12:40:31 +08:00
aa954b3af9 Merge branch 'hotfix/v5.37.1-1091/mmkv_wrong_usage' into 'release'
fix: 修复2.0.3光环启动32位游戏,概率没有初始化mmkv

See merge request halo/android/assistant-android!1843
2024-08-19 11:59:16 +08:00
93f279a384 fix: 修复2.0.3光环启动32位游戏,概率没有初始化mmkv 2024-08-19 11:45:12 +08:00
4e54833cc9 Merge branch 'hotfix/v5.37.1-1091/login_crash' into 'release'
fix: 临时处理登录后 token 为空引起的闪退,并上报相关日志到 sentry

See merge request halo/android/assistant-android!1842
2024-08-19 11:11:31 +08:00
f95862da8b Merge branch 'hotfix/v5.37.1-1091/class_cast_exception' into 'release'
fix: 修复偶发的类型转换异常闪退...

See merge request halo/android/assistant-android!1841
2024-08-19 10:50:23 +08:00
1515df34b5 fix: 临时处理登录后 token 为空引起的闪退,并上报相关日志到 sentry
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-19 10:44:14 +08:00
8a8ef40dc1 fix: 修复偶发的类型转换异常闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/404710/events/?project=22 2024-08-19 09:27:35 +08:00
b6194fed26 Merge branch 'chen/202408/fix-quick-login-crash' into 'release'
fix:点击快速登录有概率出现crash https://sentry.shanqu.cc/organizations/lightgame/issues/404488/?project=22

See merge request halo/android/assistant-android!1840
2024-08-16 17:39:58 +08:00
02752f6c81 fix:点击快速登录有概率出现crash https://sentry.shanqu.cc/organizations/lightgame/issues/404488/?project=22 2024-08-16 17:34:17 +08:00
b33d367dfd Merge branch 'fix/sentry-404504' into 'release'
fix: 悬浮窗Detach时机问题造成的崩溃

See merge request halo/android/assistant-android!1839
2024-08-16 14:04:09 +08:00
d5046ab431 fix: 悬浮窗Detach时机问题造成的崩溃 2024-08-16 14:04:09 +08:00
a53168c9bc Merge branch 'hotfix/v5.37.1-1091/add_game_popup_crash' into 'release'
fix: 修复退出添加游戏弹窗后弹出引导弹窗出现的闪退问题...

See merge request halo/android/assistant-android!1838
2024-08-16 10:47:28 +08:00
3cbc8c2f74 fix: 修复退出添加游戏弹窗后弹出引导弹窗出现的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404461/?project=22 2024-08-16 10:42:10 +08:00
7398b83004 Merge branch 'chen/202408/fix-bottom-tab_parse_lottie_crash' into 'release'
fix:当后台bottom tab上传的lottie文件格式不合法时,解析出现crash

See merge request halo/android/assistant-android!1837
2024-08-15 17:19:19 +08:00
8013426ded fix:当后台bottom tab上传的lottie文件格式不合法时,解析出现crash 2024-08-15 17:16:14 +08:00
b86d85b15f chore: 版本更新至 5.37.1-1091
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-15 14:42:55 +08:00
5a73afbab3 Merge branch 'hotfix/v5.37.0-1090-get_meta_data_crash' into 'release'
fix: catch 获取应用 meta data 时的 DeadSystemException 并上报至 sentry...

See merge request halo/android/assistant-android!1836
2024-08-15 14:30:46 +08:00
e19ee25839 fix: catch 获取应用 meta data 时的 DeadSystemException 并上报至 sentry https://sentry.shanqu.cc/organizations/lightgame/issues/390674
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-15 14:26:12 +08:00
61bf39e95f Merge branch 'hotfix/v5.37.0-1090/index_out_of_bounds_exception' into 'release'
fix: 修复数组越界闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404202/?project=22

See merge request halo/android/assistant-android!1835
2024-08-15 14:20:39 +08:00
ef82ae2378 fix: 修复数组越界闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/404202/?project=22 2024-08-15 14:17:32 +08:00
2dcccc22a8 Merge branch 'fix/sentry-404211' into 'release'
fix: 工作线程显示悬浮窗造成的崩溃问题

See merge request halo/android/assistant-android!1834
2024-08-15 14:09:06 +08:00
cb0e77d204 fix: 工作线程显示悬浮窗造成的崩溃问题 2024-08-15 14:09:06 +08:00
a6ea178609 Merge branch 'fix/sentry-404179' into 'release'
fix: 悬浮窗权限申请弹窗在Activity销毁后弹出造成的崩溃问题

See merge request halo/android/assistant-android!1833
2024-08-15 14:08:58 +08:00
6a62f08891 fix: 悬浮窗权限申请弹窗在Activity销毁后弹出造成的崩溃问题 2024-08-15 14:08:58 +08:00
ddb48481d2 Merge branch 'hotfix/v5.37.0-1090-dual_download_error_issue' into 'release'
fix: 双下载时使用本地下载进行下载时临时屏蔽特殊弹窗和下载悬浮窗 https://jira.shanqu.cc/browse/GHZSCY-6521

See merge request halo/android/assistant-android!1832
2024-08-14 11:36:51 +08:00
48a55a6b31 fix: 双下载时使用本地下载进行下载时临时屏蔽特殊弹窗和下载悬浮窗 2024-08-14 11:35:20 +08:00
50fcb0c3ea fix: 方法入参异常造成的编译问题 2024-08-13 16:20:01 +08:00
e97722b6fb Merge branch 'feat/cw-apk-udpate' into 'release'
feat: 优化畅玩游戏更新逻辑

See merge request halo/android/assistant-android!1790
2024-08-13 15:19:22 +08:00
2163b2ff9e Merge branch 'fix/GHZSCY-6438' into 'release'
fix: 已安装游戏替换问题 https://jira.shanqu.cc/browse/GHZSCY-6438

See merge request halo/android/assistant-android!1831
2024-08-13 15:06:03 +08:00
b9558e2732 Merge branch 'fix/GHZSCY-6414' into 'release'
fix: 安装流程相关优化—2024年8月2日测试组 https://jira.shanqu.cc/browse/GHZSCY-6414

See merge request halo/android/assistant-android!1830
2024-08-13 14:25:51 +08:00
5daddeadda Merge branch 'feat/GHZSCY-6491' into 'dev'
feat: 客户端删除已经不再应用的页面—客户端 https://jira.shanqu.cc/browse/GHZSCY-6491

See merge request halo/android/assistant-android!1827
2024-08-13 12:07:20 +08:00
58b1c0295c feat: 客户端删除已经不再应用的页面—客户端 https://jira.shanqu.cc/browse/GHZSCY-6491 2024-08-13 12:07:20 +08:00
a56082d002 Merge branch 'feat/GHZSCY-6488' into 'dev'
fixed: 跳转链接支持-客户端 https://jira.shanqu.cc/browse/GHZSCY-6488

See merge request halo/android/assistant-android!1826
2024-08-13 12:05:12 +08:00
877ab7cf39 fixed: 跳转链接支持-客户端 https://jira.shanqu.cc/browse/GHZSCY-6488 2024-08-13 12:05:12 +08:00
428e3496d8 Merge branch 'feat/sync-va' into 'dev'
chore: 组件升级到 2.0.4

See merge request halo/android/assistant-android!1828
2024-08-13 11:21:18 +08:00
b33419ea05 chore: 组件升级到 2.0.4 2024-08-13 11:20:41 +08:00
e9bcd0a0d6 Merge branch 'fix/GHZSCY-6470' into 'dev'
fix: 搜索配置顺序显示问题 https://jira.shanqu.cc/browse/GHZSCY-6470

See merge request halo/android/assistant-android!1825
2024-08-12 10:03:06 +08:00
98b877671a fix: 搜索配置顺序显示问题 https://jira.shanqu.cc/browse/GHZSCY-6470
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-09 16:47:09 +08:00
6c61a62799 Merge branch 'fix/splash_video_flick' into 'dev'
fix: 处理启动时的广告视频图片闪烁问题

See merge request halo/android/assistant-android!1824
2024-08-09 14:24:39 +08:00
391e409ee1 Merge branch 'feat/sync-va' into 'dev'
refactor: sync vasdk

See merge request halo/android/assistant-android!1823
2024-08-09 10:27:17 +08:00
cfd1ee845a refactor: sync vasdk 2024-08-09 10:26:56 +08:00
34b123a0a7 Merge branch 'feat/GHZSCY-6447' into 'dev'
feat: 移除部分已经废弃的 activity 及仅这些 activity 所依赖的资源文件 https://jira.shanqu.cc/browse/GHZSCY-6447

See merge request halo/android/assistant-android!1821
2024-08-09 10:14:54 +08:00
51515171a8 feat: 移除部分已经废弃的 activity 及仅这些 activity 所依赖的资源文件 https://jira.shanqu.cc/browse/GHZSCY-6447 2024-08-09 10:14:54 +08:00
e9139c66e1 fix: 已安装游戏替换问题 https://jira.shanqu.cc/browse/GHZSCY-6438
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-08 17:43:31 +08:00
24941a165a feat: 取消启动时广告视频的循环播放,改为播放完成后停留在最后一帧
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-08 16:40:34 +08:00
9d661eefa7 Merge branch 'fix/GHZSCY-6463' into 'dev'
fix:【光环助手】游戏专题-游戏名称显示问题 https://jira.shanqu.cc/browse/GHZSCY-6463

See merge request halo/android/assistant-android!1820
2024-08-08 16:05:30 +08:00
373fa7fc80 fix:【光环助手】游戏专题-游戏名称显示问题 https://jira.shanqu.cc/browse/GHZSCY-6463 2024-08-08 15:52:56 +08:00
d9743a89d6 fix: 处理启动时的广告视频图片闪烁问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-08 10:39:00 +08:00
0f596836dc Merge branch 'fix/temporaily_fix_long_start_up' into 'dev'
fix: 简单优化启动耗时问题

See merge request halo/android/assistant-android!1815
2024-08-07 18:03:37 +08:00
eb08575f3e fix: 简单优化启动耗时问题 2024-08-07 17:43:09 +08:00
405268bbce Merge branch 'fix/vgame_tab_typo' into 'dev'
fix: 调整畅玩 tab 文案 https://jira.shanqu.cc/browse/GHZSCY-6275

See merge request halo/android/assistant-android!1819
2024-08-07 16:17:34 +08:00
2453e34a74 fix: 调整畅玩 tab 文案 https://jira.shanqu.cc/browse/GHZSCY-6275
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-07 16:16:46 +08:00
2830367826 Merge branch 'ci/add_tokens' into 'dev'
ci: add id_tokens

See merge request halo/android/assistant-android!1818
2024-08-07 16:14:42 +08:00
782d94289f ci: add id_tokens
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-07 15:44:20 +08:00
3e2c2fe18f Merge branch 'fix/GHZSCY-6428' into 'dev'
fix:【光环助手】下载数据神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-6428

See merge request halo/android/assistant-android!1817
2024-08-07 09:22:35 +08:00
1afd154364 fix:【光环助手】下载数据神策上报问题 https://jira.shanqu.cc/browse/GHZSCY-6428 2024-08-07 09:11:08 +08:00
b24cac0cb1 Merge branch 'feat/sync-va' into 'dev'
fix: mmkv初始化时机太晚导致的crash

See merge request halo/android/assistant-android!1816
2024-08-06 17:18:44 +08:00
d5db516112 fix: mmkv初始化时机太晚导致的crash 2024-08-06 17:18:27 +08:00
b2a7a606e5 Merge branch 'fix/GHZSCY-6312' into 'dev'
fix:【光环助手】通用内容合集在深色模式下显示问题 https://jira.shanqu.cc/browse/GHZSCY-6312

See merge request halo/android/assistant-android!1814
2024-08-06 11:44:52 +08:00
219866e195 Merge branch 'fix/GHZSCY-6401' into 'dev'
fix:【光环助手】通用内容合集-轮播banner 背景色显示问题 https://jira.shanqu.cc/browse/GHZSCY-6401

See merge request halo/android/assistant-android!1810
2024-08-06 11:33:22 +08:00
dea7ceb5f6 Merge branch 'feat/sync-va' into 'dev'
fix: 32位埋点没有上报va_version的问题

See merge request halo/android/assistant-android!1813
2024-08-06 10:00:39 +08:00
da1da1c1af fix: 32位埋点没有上报va_version的问题 2024-08-06 09:59:33 +08:00
9b4fa45492 Merge branch 'feat/sync-va' into 'dev'
refactor: update vasdk commit id.

See merge request halo/android/assistant-android!1812
2024-08-05 16:50:57 +08:00
01df42b76b refactor: update vasdk commit id. 2024-08-05 16:50:41 +08:00
cef8aa1968 Merge branch 'fix/GHZSCY-6423' into 'dev'
fix:【光环助手】助手闪退问题(1) https://jira.shanqu.cc/browse/GHZSCY-6423

See merge request halo/android/assistant-android!1811
2024-08-05 15:47:22 +08:00
4147612d9b fix:【光环助手】助手闪退问题(1) https://jira.shanqu.cc/browse/GHZSCY-6423 2024-08-05 15:34:04 +08:00
9b57d10e2d Merge branch 'feature-GHZS-5551' into 'dev'
feat: 评论回复\游戏评分\消息推送需支持链接点击跳转—客户端 https://jira.shanqu.cc/browse/GHZSCY-5551

See merge request halo/android/assistant-android!1743
2024-08-05 11:11:24 +08:00
19f4e70ada feat: 评论回复\游戏评分\消息推送需支持链接点击跳转—客户端 https://jira.shanqu.cc/browse/GHZSCY-5551 2024-08-05 11:11:24 +08:00
49b7e4c245 Merge branch 'feat/sync-va' into 'dev'
fix:32位埋点没有32位版本号的问题,修复32位畅玩助手包可见性的问题

See merge request halo/android/assistant-android!1809
2024-08-05 10:01:03 +08:00
638de59562 fix:32位埋点没有32位版本号的问题,修复32位畅玩助手包可见性的问题 2024-08-05 09:57:05 +08:00
69b092be46 Merge branch 'fix/uid_package_error' into 'dev'
fix: 修复在 UID 不为 0 的时候获取已安装应用卡死的问题

See merge request halo/android/assistant-android!1808
2024-08-02 17:56:19 +08:00
27d1d02d58 fix: 修复在 UID 不为 0 的时候获取已安装应用卡死的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 17:55:16 +08:00
e4bfa5e6bf Merge branch 'fix/android_10_crash' into 'dev'
fix: 修复在 android 9~10 设备上重建多 fragment 页面时的闪退问题...

See merge request halo/android/assistant-android!1802
2024-08-02 16:40:23 +08:00
3ea3238011 Merge branch 'feat/sync-va' into 'dev'
fix: sentry捕获到的NPE问题 https://sentry.shanqu.cc/organizations/lightgame/issues/393310

See merge request halo/android/assistant-android!1807
2024-08-02 16:32:42 +08:00
2dcae2168b fix: sentry捕获到的NPE问题 https://sentry.shanqu.cc/organizations/lightgame/issues/393310 2024-08-02 16:31:48 +08:00
4b1c198818 Merge branch 'feat/download-suspend-window-compatibility' into 'dev'
fix: 安装流程优化-悬浮窗-客户端

See merge request halo/android/assistant-android!1806
2024-08-02 15:19:17 +08:00
e42e2fbd56 fix: 安装流程优化-悬浮窗-客户端 2024-08-02 15:19:17 +08:00
713e4157db Merge branch 'feat/sync-va' into 'dev'
fix:修复王国守卫者闪退

See merge request halo/android/assistant-android!1805
2024-08-02 14:58:29 +08:00
76cf7dce1d fix:修复王国守卫者闪退 2024-08-02 14:58:02 +08:00
f492d2ea97 fix: 安装流程相关优化—2024年8月2日测试组 https://jira.shanqu.cc/browse/GHZSCY-6414
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 14:49:59 +08:00
37a3689a2c Merge branch 'feat/sync-va' into 'dev'
fix:多用户模式下获取userId错误

See merge request halo/android/assistant-android!1804
2024-08-02 14:39:23 +08:00
7429f17538 fix:多用户模式下获取userId错误 2024-08-02 14:38:59 +08:00
32ba015686 Merge branch 'feat/annotation' into 'dev'
feat: 添加Nullable注解到icon字段

See merge request halo/android/assistant-android!1803
2024-08-02 14:35:58 +08:00
e5365fd527 feat: 添加Nullable注解到icon字段 2024-08-02 14:35:31 +08:00
1c873d0194 fix: 修复在 android 9~10 设备上重建多 fragment 页面时的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/396730/events/83ef86539ca34141a926afe44f161cf2
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 11:42:14 +08:00
1424ee2b45 Merge branch 'fix/GHZSCY-6413' into 'dev'
fix: downloadEntity.icon NPE...

See merge request halo/android/assistant-android!1801
2024-08-02 11:34:19 +08:00
69cb916364 fix: downloadEntity.icon NPE 问题,给kotlin方法传参时,如果定义的是String而不是String?类型触发。https://jira.shanqu.cc/browse/GHZSCY-6413 2024-08-02 11:27:38 +08:00
04f1d712cd Merge branch 'feat/GHZSCY-6357' into 'dev'
fix: 安装流程相关优化-2024/7/30-验收问题 https://jira.shanqu.cc/browse/GHZSCY-6357

See merge request halo/android/assistant-android!1794
2024-08-02 11:25:22 +08:00
ee14ae51be feat: 安装流程优化-2024/7/31-优化补充 https://jira.shanqu.cc/browse/GHZSCY-6368
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-08-02 11:05:59 +08:00
4683217e44 fix:【光环助手】通用内容合集-轮播banner 背景色显示问题 https://jira.shanqu.cc/browse/GHZSCY-6401 2024-08-01 17:26:23 +08:00
df94d6677a Merge branch 'chen/202408/GHZSCY-6396-2' into 'dev'
fix:按需求将倒计时延长1s,视频广告时长不够就循环播放 https://jira.shanqu.cc/browse/GHZSCY-6396

See merge request halo/android/assistant-android!1797
2024-08-01 11:30:12 +08:00
6f85e12edf fix:按需求将倒计时延长1s,视频广告时长不够就循环播放 https://jira.shanqu.cc/browse/GHZSCY-6396 2024-08-01 11:26:57 +08:00
020c826f1d Merge branch 'chen/202408/GHZSCY-6396' into 'dev'
fix:启动广告图相关优化—0731验收问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6396

See merge request halo/android/assistant-android!1796
2024-08-01 11:17:15 +08:00
5640d778a2 fix:启动广告图相关优化—0731验收问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6396 2024-08-01 11:14:28 +08:00
2300475a9e Merge branch 'feat/GHZSCY-6356' into 'dev'
fix: 【光环助手】QQ小游戏闪退问题 https://jira.shanqu.cc/browse/GHZSCY-6356

See merge request halo/android/assistant-android!1788
2024-07-31 17:09:01 +08:00
612b4061d5 fix: 【光环助手】QQ小游戏闪退问题 https://jira.shanqu.cc/browse/GHZSCY-6356 2024-07-31 17:09:01 +08:00
49c7ff8f8e Merge branch 'feat/GHZSCY-6340' into 'dev'
新游开测测试验收优化&修复

See merge request halo/android/assistant-android!1792
2024-07-31 09:32:08 +08:00
1c408f3966 Merge branch 'fix/GHZSCY-6346' into 'dev'
fix: QA图片放大显示问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6346

See merge request halo/android/assistant-android!1793
2024-07-31 09:31:35 +08:00
055f5b23da fix: QA图片放大显示问题-客户端 https://jira.shanqu.cc/browse/GHZSCY-6346 2024-07-31 09:31:34 +08:00
9810b3e8fe fix: 新游开测相关功能优化(第三期)-0730测试验收-客户端(2) https://jira.shanqu.cc/browse/GHZSCY-6364 2024-07-31 09:16:28 +08:00
dba7042b12 fix: 新游开测相关功能优化(第三期)-0730测试验收-客户端 https://jira.shanqu.cc/browse/GHZSCY-6364 2024-07-31 09:16:28 +08:00
6695dc596e Merge branch 'fix/sentry-virtualruntime-crash' into 'dev'
fix: 主进程远程调用失败时闪退,这里需要catch异常,不能影响光环闪退

See merge request halo/android/assistant-android!1791
2024-07-30 18:23:09 +08:00
079ba014f8 fix: 主进程远程调用失败时闪退,这里需要catch异常,不能影响光环闪退 2024-07-30 17:36:10 +08:00
46955685bb feat: 优化畅玩游戏更新逻辑 2024-07-30 16:54:30 +08:00
14eeb00539 Merge branch 'chen/202407/GHZSCY-6365' into 'dev'
fix:通用内容合集组件优化—前端部分-0730验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6365

See merge request halo/android/assistant-android!1789
2024-07-30 16:20:02 +08:00
56843f18d4 fix:通用内容合集组件优化—前端部分-0730验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6365 2024-07-30 16:18:18 +08:00
53a46892a4 feat: 新游开测相关功能优化(第三期)-0729测试优化-客户端 https://jira.shanqu.cc/browse/GHZSCY-6340 2024-07-30 15:19:26 +08:00
a2153761c2 fix: 安装流程相关优化-2024/7/30-验收问题 https://jira.shanqu.cc/browse/GHZSCY-6357
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-30 14:21:07 +08:00
26a8c0abd8 Merge branch 'fix/GHZSCY-6351' into 'dev'
fix: 页面tab增加引导文案-0729验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6351

See merge request halo/android/assistant-android!1787
2024-07-30 11:22:05 +08:00
21bf0fd8e9 fix: 页面tab增加引导文案-0729验收—客户端 https://jira.shanqu.cc/browse/GHZSCY-6351 2024-07-30 11:22:05 +08:00
9787d23ea0 Merge branch 'fix/download_button_overlay_issue' into 'dev'
fix: 修复下载畅玩游戏也会显示未安装提示的问题

See merge request halo/android/assistant-android!1786
2024-07-30 11:04:29 +08:00
6ae34b81db fix: 修复下载畅玩游戏也会显示未安装提示的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-30 10:23:33 +08:00
0b1e770c03 Merge branch 'fix/download_button_overlay_issue' into 'dev'
fix: 修复游戏详情页双下载按钮时的文案重叠问题

See merge request halo/android/assistant-android!1785
2024-07-29 18:03:52 +08:00
f4681dab31 fix: 修复开启纯净模式的华为设备无法使用快速安装的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-29 17:56:29 +08:00
79a7f994eb fix: 修复进入下载管理自动下载已暂停游戏的问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-29 17:56:29 +08:00
3276fca27c fix: 修复游戏详情页双下载按钮时的文案重叠问题
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-29 17:56:28 +08:00
372db8e52c Merge branch 'chen/202407/fix-resource' into 'dev'
fix:恢复common库中的shape文件(在完成专题组件优化时,改到了common库中的shape文件)

See merge request halo/android/assistant-android!1784
2024-07-29 17:00:31 +08:00
9b6d986f1c fix:恢复common库中的shape文件(在完成专题组件优化时,改到了common库中的shape文件) 2024-07-29 16:58:11 +08:00
0e88db1600 Merge branch 'feat/sync-va' into 'dev'
feat: 畅玩阿里云替换为火山云

See merge request halo/android/assistant-android!1783
2024-07-29 14:37:45 +08:00
05b59c8732 feat: 畅玩阿里云替换为火山云 2024-07-29 14:37:01 +08:00
28f68cae95 Merge branch 'feat/revert_get_installed_list' into 'dev'
feat: 还原无网络恢复时重新获取已收录应用列表的功能

See merge request halo/android/assistant-android!1782
2024-07-29 11:16:53 +08:00
22713db44e feat: 还原无网络恢复时重新获取已收录应用列表的功能 2024-07-29 11:14:55 +08:00
d9389ac4aa Merge branch 'feat/GHZSCY-5307' into 'dev'
feat: 页面tab增加引导文案—客户端 https://jira.shanqu.cc/browse/GHZSCY-5307

See merge request halo/android/assistant-android!1734
2024-07-26 14:38:20 +08:00
31ec9311fc feat: 页面tab增加引导文案—客户端 https://jira.shanqu.cc/browse/GHZSCY-5307 2024-07-26 14:38:20 +08:00
fca62df263 Merge branch 'feat/GHZSCY-6277' into 'dev'
feat: 畅玩游戏相关文案提示优化 GHZSCY-6277 https://jira.shanqu.cc/browse/GHZSCY-6277

See merge request halo/android/assistant-android!1781
2024-07-26 14:29:14 +08:00
978c01d7dc Merge branch 'feat/GHZSCY-5554' into 'dev'
feat: 新游开测相关功能优化(第三期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-5554

See merge request halo/android/assistant-android!1774
2024-07-26 14:28:42 +08:00
b7a24e331a feat: 新游开测相关功能优化(第三期)—客户端 https://jira.shanqu.cc/browse/GHZSCY-5554 2024-07-26 14:28:42 +08:00
b1eac6a043 Merge branch 'chen/202407/remove-useless-log' into 'dev'
移除多余的日志

See merge request halo/android/assistant-android!1780
2024-07-26 09:46:10 +08:00
9f8a712be6 移除多余的日志 2024-07-26 09:45:32 +08:00
930ab904ed Merge branch 'feat/GHZSCY-5389' into 'dev'
feat: 安装流程相关优化 https://jira.shanqu.cc/browse/GHZSCY-6005

See merge request halo/android/assistant-android!1749
2024-07-25 17:34:03 +08:00
3c207244e6 feat: 安装流程相关优化 https://jira.shanqu.cc/browse/GHZSCY-6005 2024-07-25 17:34:03 +08:00
0f59e03afa Merge branch 'feat/GHZSCY-5302-pr' into 'dev'
Resolve GHZSCY-5302 "Feat/ pr"

See merge request halo/android/assistant-android!1777
2024-07-25 17:33:01 +08:00
c5d99fa304 Merge branch 'feat/GHZSCY-5302-pr' into 'dev' 2024-07-25 17:33:01 +08:00
a313cd8050 Merge branch 'feat/GHZSCY-5310-pr' into 'dev'
Resolve GHZSCY-5310 "Feat/ pr"

See merge request halo/android/assistant-android!1779
2024-07-25 16:58:02 +08:00
ce477e2bd0 Resolve GHZSCY-5310 "Feat/ pr" 2024-07-25 16:58:02 +08:00
7cf2adaa37 Merge branch 'feat/GHZSCY-5564' into 'dev'
feat: XApk游戏解压相关优化 https://jira.shanqu.cc/browse/GHZSCY-5564

See merge request halo/android/assistant-android!1770
2024-07-25 15:54:05 +08:00
0852497df2 feat: XApk游戏解压相关优化 https://jira.shanqu.cc/browse/GHZSCY-5564 2024-07-25 15:17:32 +08:00
592df6ea44 Merge branch 'feat/GHZSCY-5834-pr' into 'dev'
feat:通用内容合集组件优化—前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5294

See merge request halo/android/assistant-android!1775
2024-07-25 15:13:03 +08:00
7b5d1b1bf3 feat:通用内容合集组件优化—前端部分—客户端 https://jira.shanqu.cc/browse/GHZSCY-5294 2024-07-25 15:13:03 +08:00
5b1a614eb7 Merge branch 'feat/GHZSCY-5594-pr' into 'dev'
feat:启动广告图相关优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5594

See merge request halo/android/assistant-android!1776
2024-07-25 15:07:01 +08:00
ae9fbfb8c4 Merge branch 'feat/GHZSCY-5733-pr' into 'dev'
feat:一键登录优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5733

See merge request halo/android/assistant-android!1772
2024-07-25 14:41:28 +08:00
48b118d342 feat:一键登录优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5733 2024-07-25 14:41:28 +08:00
39625369d7 fix:【光环助手】通用内容合集在深色模式下显示问题 https://jira.shanqu.cc/browse/GHZSCY-6312 2024-07-25 14:16:02 +08:00
05b9920f6d feat:启动广告图相关优化—客户端 https://jira.shanqu.cc/browse/GHZSCY-5594 2024-07-25 10:20:46 +08:00
8a5fa2c31a Merge branch 'feature-hotfix-gitlab-ci' into 'dev'
feat: 清除gitlab测试分支信息

See merge request halo/android/assistant-android!1773
2024-07-25 09:48:26 +08:00
c2dc6d7dbe feat: 清除gitlab测试分支信息 2024-07-25 09:48:06 +08:00
db4eb9f811 feat: 畅玩游戏相关文案提示优化 GHZSCY-6277 https://jira.shanqu.cc/browse/GHZSCY-6277
Signed-off-by: chenjuntao <chenjuntao@ghzhushou.com>
2024-07-23 16:51:23 +08:00
611 changed files with 17123 additions and 10101 deletions

View File

@ -72,7 +72,7 @@ android_build:
only:
- dev
- release
- feature-GHZS-6019
- feat/GHZSCY-6644
# 代码检查
sonarqube_analysis:
@ -128,6 +128,9 @@ oss-upload&send-email:
- sysadm-devops
stage: oss-upload&send-email
image: hub.shanqu.cc/devops/android-apk-oss-upload:latest
id_tokens:
VAULT_ID_TOKEN:
aud: https://vault.shanqu.cc
variables:
GIT_STRATEGY: none
VAULT_ADDR: https://vault.shanqu.cc # 固定值
@ -146,6 +149,7 @@ oss-upload&send-email:
artifacts: true
script:
### 绑定上传参数 ###
- export OSS_PATH="release/dev/${CI_PROJECT_NAME}/$(date "+%Y/%m/%d")"
### 开启上传 ###
- /usr/local/bin/python /upload.py
@ -154,4 +158,4 @@ oss-upload&send-email:
only:
- dev
- release
- feature-GHZS-6019
- feat/GHZSCY-6644

View File

@ -9,6 +9,7 @@
<queries>
<package android:name="com.lg.vspace" />
<package android:name="com.gh.gamecenter.addon" />
</queries>
<!-- 华为/荣耀角标 -->
@ -55,6 +56,9 @@
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 悬浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
@ -305,10 +309,6 @@
android:name="com.gh.gamecenter.CleanApkActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation="portrait"
@ -333,14 +333,6 @@
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".category.CategoryDirectoryActivity"
android:screenOrientation="portrait" />
<activity
android:name=".category.CategoryListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserInfoActivity"
android:screenOrientation="portrait" />
@ -497,9 +489,6 @@
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
android:theme="@style/TransparentStatusBarAndNavigationBar" />
<activity
android:name=".gamedetail.myrating.MyRatingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity"
@ -565,14 +554,6 @@
android:name=".simulatorgame.SimulatorManagementActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.CatalogActivity"
android:screenOrientation="portrait" />
<activity
android:name=".catalog.NewCatalogListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.search.ForumOrUserSearchActivity"
android:screenOrientation="portrait" />
@ -875,6 +856,8 @@
<service android:name="com.gh.gamecenter.install.InstallService" />
<service android:name="com.gh.download.suspendwindow.DownloadSuspendWindowService" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">

File diff suppressed because one or more lines are too long

View File

@ -61,6 +61,9 @@ object AdDelegateHelper {
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
val splashAdDisplayInterval: Int
get() = mSplashAd?.ownerAd?.startAd?.displayInterval ?: 3
private const val AD_SDK_CSJ = "穿山甲"
const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
const val AD_TYPE_OWNER = "owner_ads" // 自有广告
@ -523,12 +526,15 @@ object AdDelegateHelper {
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
val jumpBtn: View = startAdContainer.findViewById(R.id.jumpBtn)
val jumpBtn = startAdContainer.findViewById<TextView>(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
val adVideo = startAdContainer.findViewById<SplashAdVideoView>(R.id.ad_video)
val icpContainer: View? = startAdContainer.findViewById(R.id.startAdIcpContainer)
startAdContainer.visibility = View.VISIBLE
icpContainer?.visibility = View.VISIBLE
jumpBtn.text = startAdContainer.context.getString(R.string.splash_jump, splashAdDisplayInterval)
jumpDetailBtn.text = ad.desc
jumpDetailBtn.setDrawableEnd(
AppCompatResources.getDrawable(
@ -536,7 +542,16 @@ object AdDelegateHelper {
R.drawable.ic_startup_ad_arrow
), null, null
)
adImage.visibleIf(true)
ImageUtils.display(adImage, ad.img)
if (ad.isImageType) {
adVideo.visibleIf(false)
} else {
adVideo.visibleIf(true)
adVideo.startPlay(ad.video.url)
}
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}

View File

@ -0,0 +1,78 @@
package com.gh.ad
import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.view.WindowManager
import com.gh.gamecenter.R
import com.gh.gamecenter.video.detail.CustomManager
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import com.shuyu.gsyvideoplayer.utils.GSYVideoType.SCREEN_TYPE_FULL
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
class SplashAdVideoView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) :
StandardGSYVideoPlayer(context, attrs) {
fun startPlay(url: String) {
GSYVideoType.setShowType(SCREEN_TYPE_FULL)
GSYVideoType.setRenderType(GSYVideoType.SUFRACE)
CustomManager.getCustomManager(getKey()).isNeedMute = true
setUp(url, true, "")
setNeedAutoAdaptation(false)
startPlayLogic()
}
override fun getGSYVideoManager(): GSYVideoViewBridge {
CustomManager.getCustomManager(getKey()).initContext(context.applicationContext)
return CustomManager.getCustomManager(getKey())
}
private fun getKey() = "splash_ad"
/**
* 覆盖父类方法,防止在是视频 Preparing 阶段封面图被隐藏,导致白屏
*/
override fun changeUiToPreparingShow() = Unit
override fun getLayoutId(): Int {
return R.layout.layout_splash_ad_video
}
override fun onAutoCompletion() {
setStateAndUi(CURRENT_STATE_AUTO_COMPLETE);
mSaveChangeViewTIme = 0
mCurrentPosition = 0
if (!mIfCurrentIsFullscreen) {
getGSYVideoManager().setLastListener(null)
}
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
if (mContext is Activity) {
try {
(mContext as Activity).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} catch (e: Exception) {
e.printStackTrace()
}
}
releaseNetWorkState()
if (mVideoAllCallBack != null && isCurrentMediaListener()) {
mVideoAllCallBack.onAutoComplete(mOriginUrl, mTitle, this)
}
mHadPlay = false
}
fun clearAll() {
GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_DEFAULT)
GSYVideoType.setRenderType(GSYVideoType.TEXTURE)
release()
CustomManager.removeManager(getKey())
}
}

View File

@ -21,13 +21,13 @@ import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.gamecenter.va.VCore
import com.gh.gamecenter.login.utils.QuickLoginHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
// TODO移动到对应的模块
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
private var isFromBackgroundToForeground = false // 是否后台回到前台
private var activityCount = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
// do nothing
@ -35,8 +35,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
GlobalActivityManager.currentActivity = activity
activityCount++
if (activityCount == 1 && isFromBackgroundToForeground) {
GlobalActivityManager.activityCount ++
if (GlobalActivityManager.activityCount == 1 && isFromBackgroundToForeground) {
if (AdDelegateHelper.shouldShowStartUpAd(true)
&& !HaloApp.getInstance().isDisableSplashAdTemporarily
&& activity !is SplashScreenActivity
@ -50,13 +50,16 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
isFromBackgroundToForeground = false
}
if (activityCount == 1) {
if (GlobalActivityManager.activityCount == 1) {
// 清除桌面角标
if (activity !is SplashScreenActivity && activity !is AuthorizationActivity) {
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
pushProvider?.cleanBadgeNumber(activity.applicationContext)
}
}
if (QuickLoginHelper.isLoginAuthPage(activity)) {
QuickLoginHelper.addCustomViewToLoginAuthPage(activity)
}
}
override fun onActivityResumed(activity: Activity) {
@ -108,8 +111,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
override fun onActivityStopped(activity: Activity) {
activityCount--
isFromBackgroundToForeground = activityCount <= 0
GlobalActivityManager.activityCount --
isFromBackgroundToForeground = GlobalActivityManager.activityCount <= 0
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
@ -117,7 +120,9 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
override fun onActivityDestroyed(activity: Activity) {
// do nothing
if (QuickLoginHelper.isLoginAuthPage(activity)) {
QuickLoginHelper.release()
}
}
private fun isSuggestionActivity(activity: Activity): Boolean {

View File

@ -49,6 +49,7 @@ import com.gh.gamecenter.login.user.LoginTag
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.login.utils.LoginHelper
import com.gh.gamecenter.login.utils.QuickLoginHelper
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.setting.SettingBridge
@ -138,12 +139,12 @@ class DefaultJsApi(
@JavascriptInterface
fun login(msg: Any) {
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
// QuickLoginHelper.startLogin(context, "浏览器")
// } else {
if (NetworkUtils.isQuickLoginEnabled(context)) {
QuickLoginHelper.startLogin(context, "浏览器")
} else {
val intent = LoginActivity.getIntent(context, "浏览器")
context.startActivity(intent)
// }
}
}
@JavascriptInterface

View File

@ -268,10 +268,6 @@ object DefaultUrlHandler {
directToGameVideo(context, id, entrance, "")
}
EntranceConsts.HOST_CATEGORY -> {
val title = uri.getQueryParameter("title")
DirectUtils.directCategoryDirectory(context, id, title ?: "", entrance, "")
}
EntranceConsts.HOST_COLUMN_COLLECTION -> {
val name = uri.getQueryParameter("name")
DirectUtils.directToColumnCollection(context, id, -1, entrance, name ?: "")

View File

@ -20,6 +20,7 @@ import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.DarkModeUtils;
import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
@ -47,7 +48,6 @@ import java.util.Locale;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
@ -225,7 +225,6 @@ public class Config {
RetrofitManager.getInstance()
.getVApi().getSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<VSetting>() {
@Override
public void onSuccess(VSetting data) {
@ -258,7 +257,6 @@ public class Config {
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<AppEntity>() {
@Override
public void onSuccess(AppEntity data) {
@ -290,7 +288,6 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getSettings(PackageUtils.getGhVersionName(), channel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<SettingsEntity>() {
@Override
public void onResponse(SettingsEntity response) {
@ -303,7 +300,7 @@ public class Config {
edit.apply();
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
EventBus.getDefault().post(new EBReuse("Refresh"));
AppExecutor.getUiExecutor().execute(() -> EventBus.getDefault().post(new EBReuse("Refresh")));
}
}
});
@ -311,7 +308,6 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewSettingsEntity>() {
@Override
public void onSuccess(NewSettingsEntity data) {
@ -326,7 +322,6 @@ public class Config {
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<GameGuidePopupEntity>() {
@Override
public void onSuccess(GameGuidePopupEntity data) {
@ -338,7 +333,6 @@ public class Config {
if (manufacturer.equals("OPPO") || manufacturer.equals("VIVO")) {
RetrofitManager.getInstance().getNewApi().getBrowserHintUrl(manufacturer)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<ResponseBody>() {
@Override
public void onSuccess(ResponseBody data) {
@ -369,7 +363,6 @@ public class Config {
RetrofitManager.getInstance()
.getNewApi().getNewSettings(PackageUtils.getGhVersionName(), channel, filterString)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<NewApiSettingsEntity>() {
@Override
public void onSuccess(NewApiSettingsEntity data) {
@ -378,7 +371,7 @@ public class Config {
mNewSimulatorEntity = data.getSimulator();
if (HaloApp.getInstance().isNewForThisVersion && mNightModeSetting != null && mNightModeSetting.getInstall()) {
DarkModeUtils.INSTANCE.updateFollowSystemDarkModeToSp(true);
DarkModeUtils.INSTANCE.initDarkMode();
AppExecutor.getUiExecutor().execute(DarkModeUtils.INSTANCE::initDarkMode);
}
SPUtils.setString(Constants.SP_NEW_API_SETTINGS, GsonUtils.toJson(data));
@ -396,7 +389,7 @@ public class Config {
// 更新包名监听是否开启
if (mNewApiSettingsEntity.isPackageObserveEnable()) {
observePackageChange(mNewApiSettingsEntity.getPackageObserveActions());
AppExecutor.getUiExecutor().execute(() -> observePackageChange(mNewApiSettingsEntity.getPackageObserveActions()));
}
}
});

View File

@ -158,7 +158,7 @@ class InstallPermissionDialogFragment : BaseDialogFragment() {
}
if (isXapk) {
val xapkUnzipVersions = Config.getSettings()?.permissionPopupAppliedVersions?.xapkUnzip
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false) {
if (xapkUnzipVersions?.contains(Build.VERSION.SDK_INT.toString()) == false || XapkInstaller.systemHasFlaw) {
callBack?.invoke(false)
return
}

View File

@ -6,16 +6,16 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.fromHtml
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.fromHtml
import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.databinding.DialogReserveBinding
import com.gh.gamecenter.databinding.DialogReserveItemBinding
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.mygame.MyGameActivity
import com.lightgame.adapter.BaseRecyclerAdapter
@ -43,7 +43,7 @@ class ReserveDialog : BaseDialogFragment() {
View.VISIBLE
} else View.GONE
binding.more.setOnClickListener {
val intent = MyGameActivity.getIntentWithConfig(requireContext(), 2)
val intent = MyGameActivity.getIntentWithConfig(requireContext(), MyGameActivity.RESERVATION_INDEX)
startActivity(intent)
dismissAllowingStateLoss()
}

View File

@ -1,13 +1,13 @@
package com.gh.common.prioritychain
import android.app.Activity
import android.os.Handler
import android.view.Gravity
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.DisplayUtils
@ -19,7 +19,7 @@ import com.gh.gamecenter.wrapper.MainWrapperViewModel
class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priority) {
private var mActivity: Activity? = null
private var mBaseHandler: BaseFragment.BaseHandler? = null
private var mHandler: Handler? = null
private var mGameList: List<GameEntity>? = null
private var mViewModel: MainWrapperViewModel? = null
@ -28,13 +28,13 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
*/
fun doPreProcess(
activity: Activity,
baseHandler: BaseFragment.BaseHandler,
handler: Handler,
gameEntityList: List<GameEntity>?,
viewModel: MainWrapperViewModel
) {
mActivity = activity
mGameList = gameEntityList
mBaseHandler = baseHandler
mHandler = handler
mViewModel = viewModel
if (getStatus() == STATUS_PENDING) {
@ -59,7 +59,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
val accelerateSet =
HashSet(SPUtils.getStringSet(Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET))
if (!mGameList.isNullOrEmpty() && !accelerateSet.contains(mGameList!![0].messageId)) {
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mBaseHandler, mGameList!![0]) {
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mHandler, mGameList!![0]) {
processNext()
}
accelerateSet.add(mGameList!![0].messageId)
@ -82,7 +82,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
fun showAccelerateNotificationPopupWindow(
activity: Activity,
viewModel: MainWrapperViewModel?,
baseHandler: BaseFragment.BaseHandler?,
handler: Handler?,
gameEntity: GameEntity?,
dismissCallback: (() -> Unit)?
) {
@ -131,7 +131,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
setOnDismissListener {
dismissCallback?.invoke()
}
baseHandler?.postDelayed({ dismiss() }, 5000)
handler?.postDelayed({ dismiss() }, 5000)
}
}
}

View File

@ -0,0 +1,169 @@
package com.gh.common.prioritychain
import android.app.Activity
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.PopupBottomTabGuideBinding
import com.gh.gamecenter.entity.BottomTab
class BottomTabGuideHandler(priority: Int): PriorityChainHandler(priority) {
private var mActivity: Activity? = null
private var mHandler: Handler? = null
private var mViewPager: ViewGroup? = null
private var mGuide: BottomTab.Guide? = null
private var mTriangleTransX = 0F
private var mGuideTransX = 0F
private var mRestWidth = 0F
private var mIsCenterPosition = false
private var mIsRightPosition = false
private var mPopupWindow: PopupWindow? = null
fun doPreProcess(
shouldShow: Boolean,
activity: Activity? = null,
handler: Handler? = null,
viewPager: ViewGroup? = null,
guide: BottomTab.Guide? = null,
triangleTransX: Float = 0F,
guideTransX: Float = 0F,
restWidth: Float = 0F,
isCenterPosition: Boolean = false,
isRightPosition: Boolean = false
) {
mActivity = activity
mHandler = handler
mViewPager = viewPager
mGuide = guide
mTriangleTransX = triangleTransX
mGuideTransX = guideTransX
mRestWidth = restWidth
mIsCenterPosition = isCenterPosition
mIsRightPosition = isRightPosition
if (getStatus() == STATUS_PENDING) {
if (shouldShow) {
updateStatus(STATUS_VALID)
process()
} else {
processNext()
}
} else {
if (shouldShow) {
updateStatus(STATUS_VALID)
} else {
updateStatus(STATUS_INVALID)
}
}
}
override fun onProcess(): Boolean {
when (getStatus()) {
STATUS_VALID -> {
if (mGuide == null || mActivity == null || mViewPager == null) {
processNext()
return false
}
val guideSet = HashSet(SPUtils.getStringSet(Constants.SP_BOTTOM_TAB_GUIDE_SET))
if (!guideSet.contains(mGuide?.bottomTabId + mGuide?.text)) {
mPopupWindow = showBottomTabPopupWindow(
mActivity!!,
mHandler,
mViewPager!!,
mGuide!!,
mTriangleTransX,
mGuideTransX,
mRestWidth,
mIsCenterPosition,
mIsRightPosition
) {
processNext()
}
guideSet.add(mGuide?.bottomTabId + mGuide?.text)
SPUtils.setStringSet(Constants.SP_BOTTOM_TAB_GUIDE_SET, guideSet)
return true
} else {
processNext()
}
}
STATUS_INVALID -> {
processNext()
}
}
return false
}
fun dismiss() {
if (mPopupWindow?.isShowing == true) {
mPopupWindow?.dismiss()
}
}
companion object {
const val KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS = 100
private const val AUTO_DISMISS_DELAY_TIME = 5000L
fun showBottomTabPopupWindow(
activity: Activity,
handler: Handler?,
viewPager: ViewGroup,
guide: BottomTab.Guide,
triangleTransX: Float,
guideTransX: Float,
restWidth: Float,
isCenterPosition: Boolean,
isRightPosition: Boolean,
dismissCallback: (() -> Unit)?
): PopupWindow {
val binding = PopupBottomTabGuideBinding.inflate(LayoutInflater.from(activity))
binding.guideTv.text = guide.text
binding.guideTriangleIv.translationX = triangleTransX
binding.guideTv.translationX = guideTransX
binding.guideIconIv.translationX = guideTransX
binding.guideTv.updateLayoutParams<ConstraintLayout.LayoutParams> {
horizontalBias = if (isCenterPosition) 0.5F else if (isRightPosition) 1F else 0F
}
val popupWindow = BugFixedPopupWindow(
binding.root,
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val measureWidth = popupWindow.contentView.measuredWidth
val measureHeight = popupWindow.contentView.measuredHeight
if (measureWidth > restWidth) {
binding.guideTv.translationX = 0F
binding.guideIconIv.translationX = 0F
}
return popupWindow.apply {
isFocusable = false
isOutsideTouchable = false
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
setOnDismissListener {
dismissCallback?.invoke()
}
handler?.post {
if (!activity.isFinishing) {
showAsDropDown(viewPager, 0, 8F.dip2px() - measureHeight)
}
handler.sendEmptyMessageDelayed(KEY_BOTTOM_TAB_GUIDE_AUTO_DISMISS, AUTO_DISMISS_DELAY_TIME)
}
}
}
}
}

View File

@ -60,7 +60,7 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority
when (getStatus()) {
STATUS_VALID -> {
_showFloatingAction.value = Event(data)
processNext()
return true
// floatingWindowProvider.showFloatingWindowOnly(
// mFragment!!,
// mRecyclerView!!,
@ -79,4 +79,9 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority
return false
}
fun dismiss() {
if (getStatus() == STATUS_HANDLING || getStatus() == STATUS_VALID) {
processNext()
}
}
}

View File

@ -18,6 +18,8 @@ import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.DialogEntity
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
import com.gh.gamecenter.hud.PendingInstallHUDHandler
import com.gh.gamecenter.hud.ResumeDownloadHudHandler
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
@ -57,6 +59,8 @@ object GlobalPriorityChainHelper : ISuperiorChain {
val notificationPermissionDialogHandler = NotificationPermissionDialogHandler(0)
val reserveDialogHandler = ReserveDialogHandler(1)
val welcomeDialogHandler = WelcomeDialogHandler(2)
val pendingInstallHandler = PendingInstallHUDHandler(3)
val resumeDownloadHandler = ResumeDownloadHudHandler(4)
mainChain.addHandler(launchRedirectHandler)
mainChain.addHandler(updateDialogHandler)
@ -64,6 +68,8 @@ object GlobalPriorityChainHelper : ISuperiorChain {
mainChain.addHandler(welcomeDialogHandler)
mainChain.addHandler(reserveDialogHandler)
mainChain.addHandler(notificationPermissionDialogHandler)
mainChain.addHandler(pendingInstallHandler)
mainChain.addHandler(resumeDownloadHandler)
launchRedirectHandler.doPreProcess()
updateDialogHandler.doPreProcess()

View File

@ -0,0 +1,297 @@
package com.gh.common.prioritychain
import android.app.Activity
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.widget.PopupWindow
import androidx.constraintlayout.widget.ConstraintLayout
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.common.view.NoDefaultMinWidthTabLayout
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.PopupMultiTabGuideBinding
import com.gh.gamecenter.entity.BottomTab
import com.gh.gamecenter.wrapper.BaseTabWrapperFragment
import com.gh.gamecenter.wrapper.MainWrapperFragment
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.TabView
class MultiTabGuideHandler(priority: Int): PriorityChainHandler(priority) {
private var mActivity: Activity? = null
private var mHandler: Handler? = null
private var mGuide: BottomTab.Guide? = null
private var mTabLayout: TabLayout? = null
private var mTabView: TabView? = null
private var mIsSingleLineTab = false
private var mMainWrapperFragment: MainWrapperFragment? = null
private var mTabWrapperFragment: BaseTabWrapperFragment? = null
fun doPreProcess(
shouldShow: Boolean,
activity: Activity? = null,
handler: Handler? = null,
guide: BottomTab.Guide? = null,
tabLayout: TabLayout? = null,
tabView: TabLayout.TabView? = null,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment? = null,
tabWrapperFragment: BaseTabWrapperFragment? = null
) {
mActivity = activity
mHandler = handler
mGuide = guide
mTabLayout = tabLayout
mTabView = tabView
mIsSingleLineTab = isSingleLineTab
mMainWrapperFragment = mainWrapperFragment
mTabWrapperFragment = tabWrapperFragment
if (getStatus() == STATUS_PENDING) {
if (shouldShow) {
updateStatus(STATUS_VALID)
process()
} else {
processNext()
}
} else {
if (shouldShow) {
updateStatus(STATUS_VALID)
} else {
updateStatus(STATUS_INVALID)
}
}
}
override fun onProcess(): Boolean {
when (getStatus()) {
STATUS_VALID -> {
if (mGuide == null || mActivity == null || mTabView == null || mTabLayout == null) {
processNext()
return false
}
return showMultiTabGuide(
true,
mActivity!!,
mHandler,
mGuide!!,
mTabLayout!!,
mTabView!!,
mIsSingleLineTab,
mMainWrapperFragment,
mTabWrapperFragment
) {
processNext()
}
}
STATUS_INVALID -> {
processNext()
}
}
return false
}
companion object {
private const val TAB_GUIDE_TRIANGLE_OFFSET_DP = 5F
private const val TAB_GUIDE_START_TRIANGLE_OFFSET_DP = 12F
private const val TAB_GUIDE_RIGHT_SIDE_ICON_RIGHT_RESERVED_OFFSET_DP = 51F + TAB_GUIDE_TRIANGLE_OFFSET_DP // 光宝在文案右侧时预留引导到屏幕右侧的距离
private const val TAB_GUIDE_RIGHT_SIDE_ICON_LEFT_RESERVED_OFFSET_DP = TAB_GUIDE_START_TRIANGLE_OFFSET_DP + TAB_GUIDE_TRIANGLE_OFFSET_DP // 光宝在文案作侧时预留引导到屏幕右侧的距离
fun showMultiTabGuide(
isImmediately: Boolean,
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabLayout: TabLayout,
tabView: TabView,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment? = null,
tabWrapperFragment: BaseTabWrapperFragment? = null,
dismissCallback: (() -> Unit)? = null
): Boolean {
val guideSet = HashSet(SPUtils.getStringSet(Constants.SP_MULTI_TAB_NAV_GUIDE_SET))
val hasShownGuide = guideSet.contains(guide.multiTabId + guide.text)
val isCurrentBottomTab = mainWrapperFragment == null || guide.bottomTabId == mainWrapperFragment.currentTab?.id
if (!hasShownGuide && isCurrentBottomTab) {
val screenWidth = DisplayUtils.getScreenWidth(activity)
val outLocation = IntArray(2)
tabView.getLocationOnScreen(outLocation)
val tabViewCenterPosX = outLocation.first() + tabView.width / 2F
val iconLeftMaxPosX = if (isSingleLineTab) tabLayout.width else tabLayout.width - TAB_GUIDE_RIGHT_SIDE_ICON_LEFT_RESERVED_OFFSET_DP.dip2px()
val iconRightMaxPosX = if (isSingleLineTab) tabLayout.width else tabLayout.width - TAB_GUIDE_RIGHT_SIDE_ICON_RIGHT_RESERVED_OFFSET_DP.dip2px()
val isIconLeftValid = tabViewCenterPosX <= iconLeftMaxPosX
val isIconRightValid = tabViewCenterPosX <= iconRightMaxPosX
val isTabViewShowOnScreen = tabViewCenterPosX > 0 && (isIconLeftValid || isIconRightValid)
val isTabLayoutScrollStateIdle = (tabLayout as? NoDefaultMinWidthTabLayout)?.isScrollStateIdle == true
if (isTabViewShowOnScreen && isTabLayoutScrollStateIdle) {
val trianglePosX = tabViewCenterPosX - TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
val guideStartPosX = trianglePosX - TAB_GUIDE_START_TRIANGLE_OFFSET_DP.dip2px()
val xoff = tabView.width / 2 - TAB_GUIDE_START_TRIANGLE_OFFSET_DP.dip2px() - TAB_GUIDE_TRIANGLE_OFFSET_DP.dip2px()
val restGuideWidth = screenWidth - guideStartPosX
showMultiTabPopupWindow(
activity,
handler,
guide,
tabView,
xoff,
screenWidth,
restGuideWidth,
isIconRightValid,
dismissCallback
)
guideSet.add(guide.multiTabId + guide.text)
SPUtils.setStringSet(Constants.SP_MULTI_TAB_NAV_GUIDE_SET, guideSet)
return true
} else if (isImmediately) {
(tabLayout as? NoDefaultMinWidthTabLayout)?.let {
it.onScrollListener = object :
NoDefaultMinWidthTabLayout.OnScrollListener() {
override fun onScrollStateChanged(view: NoDefaultMinWidthTabLayout, scrollState: Int) {
if (scrollState == SCROLL_STATE_IDLE) {
showMultiTabGuideIfTabViewShow(
activity,
handler,
guide,
it,
tabView,
isSingleLineTab,
mainWrapperFragment
)
}
}
}
}
}
} else if (isImmediately && !isCurrentBottomTab) {
tabWrapperFragment?.setResumeAndPauseListener {
if (it) {
handler?.post {
(tabLayout as? NoDefaultMinWidthTabLayout)?.let { tl ->
showMultiTabGuideIfBottomTabShow(
activity,
handler,
guide,
tl,
tabView,
isSingleLineTab,
mainWrapperFragment,
tabWrapperFragment
)
}
}
}
}
}
dismissCallback?.invoke()
return false
}
fun showMultiTabGuideIfTabViewShow(
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabLayout: NoDefaultMinWidthTabLayout,
tabView: TabView,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment?
) {
if (showMultiTabGuide(
false,
activity,
handler,
guide,
tabLayout,
tabView,
isSingleLineTab,
mainWrapperFragment
)
) {
tabLayout.onScrollListener = null
}
}
fun showMultiTabGuideIfBottomTabShow(
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabLayout: NoDefaultMinWidthTabLayout,
tabView: TabView,
isSingleLineTab: Boolean = false,
mainWrapperFragment: MainWrapperFragment?,
tabWrapperFragment: BaseTabWrapperFragment?
) {
if (showMultiTabGuide(
false,
activity,
handler,
guide,
tabLayout,
tabView,
isSingleLineTab,
mainWrapperFragment,
tabWrapperFragment
)
) {
tabWrapperFragment?.setResumeAndPauseListener(null)
}
}
fun showMultiTabPopupWindow(
activity: Activity,
handler: Handler?,
guide: BottomTab.Guide,
tabView: TabView,
xoff: Int,
screenWidth: Int,
restGuideWidth: Float,
isIconRight: Boolean,
dismissCallback: (() -> Unit)?
): PopupWindow {
val binding = PopupMultiTabGuideBinding.inflate(LayoutInflater.from(activity))
binding.guideTv.text = guide.text
binding.guideTriangleIv.translationX = 12F.dip2px().toFloat()
binding.guideTv.setPadding(if (isIconRight) 8F.dip2px() else 52F.dip2px(), 0, if (isIconRight) 52F.dip2px() else 8F.dip2px(), 0)
binding.guideIconIv.goneIf(!isIconRight)
binding.guideIconFlipIv.goneIf(isIconRight)
val popupWindow = BugFixedPopupWindow(
binding.root,
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
popupWindow.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val measureWidth = popupWindow.contentView.measuredWidth
if (measureWidth >= screenWidth) {
popupWindow.width = screenWidth
binding.guideTriangleIv.translationX += screenWidth - restGuideWidth
} else if (measureWidth > restGuideWidth) {
binding.guideTriangleIv.translationX += measureWidth - restGuideWidth
}
return popupWindow.apply {
isTouchable = false
isFocusable = false
isOutsideTouchable = true
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
setOnDismissListener {
dismissCallback?.invoke()
}
handler?.post {
if (!activity.isFinishing) {
showAsDropDown(tabView, xoff, (-25F).dip2px())
}
}
}
}
}
}

View File

@ -0,0 +1,16 @@
package com.gh.common.prioritychain
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
class VideoHandler(priority: Int, val scrollCalculatorHelper: ScrollCalculatorHelper): PriorityChainHandler(priority) {
init {
updateStatus(STATUS_VALID)
}
override fun onProcess(): Boolean {
scrollCalculatorHelper.enableAndPlayIfValid()
return true
}
}

View File

@ -89,4 +89,8 @@ class AppProviderImpl : IAppProvider {
}
override fun getPluginVersion(): String = VCore.getInstance().getPluginVersion()
override fun initImageLoaderIfNeeded() {
HaloApp.getInstance().initFresco()
}
}

View File

@ -100,6 +100,10 @@ class ConfigProviderImpl : IConfigProvider {
return Config.getNightModeSetting()?.setting ?: false
}
override fun isJiguangSwitch(): Boolean {
return Config.getNewApiSettingsEntity()?.jiguangSwitch ?: false
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -1,11 +1,16 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.FragmentActivity
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.common.avoidcallback.Callback
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IEntranceUtilsProvider
import com.lightgame.utils.AppManager
@Route(path = RouteConsts.provider.entranceUtils, name = "EntranceUtils暴露服务")
class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
@ -17,6 +22,19 @@ class EntranceUtilsProviderImpl : IEntranceUtilsProvider {
EntranceUtils.saveShortcut(activityName, bundle)
}
override fun jumpActivityWithCallback(context: Context, bundle: Bundle, callback: () -> Unit) {
if (context is FragmentActivity && !context.supportFragmentManager.isDestroyed) {
EntranceUtils.jumpActivity(context, null, bundle, object : Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
callback()
}
})
} else {
EntranceUtils.jumpActivity(AppManager.getInstance().currentActivity(), bundle)
}
}
override fun init(context: Context?) {
// Do nothing
}

View File

@ -0,0 +1,23 @@
package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IMiniGameRecentlyPlayedProvider
import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase
@Route(path = RouteConsts.provider.miniGameRecentPlayed, name = "MiniGameRecentlyPlayed暴露服务")
class MiniGameRecentlyPlayedProviderImpl : IMiniGameRecentlyPlayedProvider {
override fun clearMiniGameRecentlyPlayed(gameType: String) {
MiniGameRecentlyPlayUseCase.clearRecentlyPlayedMiniGameList(gameType)
}
override fun refreshQQMiniRecentPlayed() {
MiniGameRecentlyPlayUseCase.loadRecentlyPlayedMiniGameList(Constants.QQ_MINI_GAME)
}
override fun init(context: Context?) {
// no implement
}
}

View File

@ -1,14 +1,21 @@
package com.gh.common.util;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.login.view.LoginActivity;
import com.gh.gamecenter.common.utils.NetworkUtils;
import com.gh.gamecenter.core.utils.CurrentActivityHolder;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.login.utils.QuickLoginHelper;
import com.gh.gamecenter.login.view.LoginActivity;
import com.lightgame.utils.Utils;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
/**
* Created by khy on 28/06/17.
@ -22,15 +29,15 @@ public class CheckLoginUtils {
LogUtils.login("dialog", null, entrance);
LogUtils.login("activity", null, entrance);
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
// startQuickLogin(context, entrance);
// } else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, bundle);
// }
if (NetworkUtils.isQuickLoginEnabled(context)) {
startQuickLogin(context, entrance, null);
} else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, bundle);
}
} else {
if (listener != null) {
listener.onLogin();
@ -38,16 +45,16 @@ public class CheckLoginUtils {
}
}
// private static void startQuickLogin(Context context, String entrance) {
// // 需要确保传入的 context 不为 application
// if (!(context instanceof Activity)) {
// context = CurrentActivityHolder.getCurrentActivity();
// }
//
// if (context != null) {
// QuickLoginHelper.startLogin(context, entrance);
// }
// }
private static void startQuickLogin(Context context, String entrance, Function0<Unit> callback) {
// 需要确保传入的 context 不为 application
if (!(context instanceof Activity)) {
context = CurrentActivityHolder.getCurrentActivity();
}
if (context != null) {
QuickLoginHelper.startLogin(context, entrance, callback);
}
}
public static void checkLogin(final Context context, Bundle nextToBundle, boolean isTriggerNextStep, String entrance, OnLoginListener listener) {
if (!isLogin()) {
@ -55,15 +62,25 @@ public class CheckLoginUtils {
LogUtils.login("dialog", null, entrance);
LogUtils.login("activity", null, entrance);
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, nextToBundle, bundle, (resultCode, data) -> {
if (isTriggerNextStep && listener != null && isLogin()) {
listener.onLogin();
}
});
if (NetworkUtils.isQuickLoginEnabled(context)) {
startQuickLogin(context, entrance, () -> {
if (isTriggerNextStep && listener != null && isLogin()) {
listener.onLogin();
}
return null;
});
} else {
// 有可能App未启动
Bundle bundle = new Bundle();
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance);
bundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(context, nextToBundle, bundle, (resultCode, data) -> {
if (isTriggerNextStep && listener != null && isLogin()) {
listener.onLogin();
}
});
}
} else {
if (listener != null) {
listener.onLogin();

View File

@ -5,7 +5,6 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.repository.ReservationRepository;
@ -19,6 +18,7 @@ import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.SpeedUtils;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.PluginLocation;
import com.gh.gamecenter.feature.view.DownloadButton;
@ -48,11 +48,6 @@ public class DetailDownloadUtils {
GameEntity gameEntity = viewHolder.getGameEntity();
String downloadAddWord = gameEntity.getDownloadAddWord();
// 隐藏下载按钮上的畅玩文案
if (viewHolder.getOverlayTv() != null) {
viewHolder.getOverlayTv().setVisibility(View.GONE);
}
// 多版本下载箭头
if (viewHolder.getMultiVersionDownloadTv() != null) {
viewHolder.getMultiVersionDownloadTv().setVisibility(View.GONE);
@ -117,17 +112,6 @@ public class DetailDownloadUtils {
}
}
// 更新默认的下载按钮
updateWithSingleApk(
gameEntity,
viewHolder,
viewHolder.getDownloadPb(),
downloadAddWord,
showVGame,
showDualDownloadButton,
downloadEntity
);
if (showDualDownloadButton) {
// 双下载按钮时更新占位的下载按钮
updateWithSingleApk(
@ -140,6 +124,17 @@ public class DetailDownloadUtils {
downloadEntity
);
}
// 更新默认的下载按钮
updateWithSingleApk(
gameEntity,
viewHolder,
viewHolder.getDownloadPb(),
downloadAddWord,
showVGame,
showDualDownloadButton,
downloadEntity
);
} else {
// 游戏包含多 APK 的情况
viewHolder.getMultiVersionDownloadTv().setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord));
@ -192,49 +187,53 @@ public class DetailDownloadUtils {
Context context = viewHolder.getContext();
TextView overlayTv = viewHolder.getOverlayTv();
String status = GameUtils.getDownloadBtnText(context, gameEntity, false, showAsVGame, PluginLocation.only_game);
boolean containsAddWord = !TextUtils.isEmpty(downloadAddWord); // 是否存在下载补充文案
// 根据游戏实体获取下载按钮文案
String rawBtnText = GameUtils.getDownloadBtnText(context, gameEntity, false, showAsVGame, PluginLocation.only_game);
if (showAsVGame) {
// 显示为畅玩游戏
if (context.getString(R.string.launch).equals(status)) {
if (context.getString(R.string.launch).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
}
String btnText;
String decoratedBtnText;
// 双下载按钮时,显示特殊样式
if (showDualDownloadButton
&& (context.getString(R.string.launch).equals(status) || context.getString(R.string.install).equals(status) || context.getString(R.string.smooth).equals(status) || context.getString(R.string.update).equals(status))) {
if (context.getString(R.string.smooth).equals(status)) {
btnText = context.getString(R.string.download_v);
} else if (context.getString(R.string.update).equals(status)) {
btnText = context.getString(R.string.update_v);
&& (context.getString(R.string.launch).equals(rawBtnText) || context.getString(R.string.install).equals(rawBtnText) || context.getString(R.string.smooth).equals(rawBtnText) || context.getString(R.string.update).equals(rawBtnText))) {
if (context.getString(R.string.smooth).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.download_v);
} else if (context.getString(R.string.update).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.update_v);
} else {
btnText = context.getString(R.string.launch_v);
decoratedBtnText = context.getString(R.string.launch_v);
}
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
overlayTv.setVisibility(View.VISIBLE);
overlayTv.setText(btnText);
overlayTv.setText(decoratedBtnText);
downloadButton.setText("");
}
} else {
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
decoratedBtnText = rawBtnText + (containsAddWord? "" : downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
if (overlayTv != null && downloadButton.getVisibility() != View.GONE) {
if (context.getString(R.string.launch).equals(status)
|| context.getString(R.string.install).equals(status)) {
if (context.getString(R.string.launch).equals(rawBtnText)
|| context.getString(R.string.install).equals(rawBtnText)) {
overlayTv.setVisibility(View.VISIBLE);
overlayTv.setText("启动(畅玩)");
} else {
overlayTv.setVisibility(View.GONE);
downloadButton.setText(btnText);
downloadButton.setText(decoratedBtnText);
}
} else {
if (overlayTv != null) {
overlayTv.setVisibility(View.GONE);
}
downloadButton.setText(btnText);
downloadButton.setText(decoratedBtnText);
}
}
@ -247,11 +246,11 @@ public class DetailDownloadUtils {
}
} else {
// 非畅玩,显示为普通游戏
if (context.getString(R.string.pluggable).equals(status)) {
if (context.getString(R.string.pluggable).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
} else if (context.getString(R.string.launch).equals(status)) {
} else if (context.getString(R.string.launch).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else if (context.getString(R.string.install).equals(status)) {
} else if (context.getString(R.string.install).equals(rawBtnText)) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
} else {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
@ -271,48 +270,78 @@ public class DetailDownloadUtils {
}
}
String btnText;
String extraBtnText;
String decoratedBtnText;
String localBtnText;
boolean useAlternativeTextStyle = false; // 是否使用带图标的文案,仅不包含补充文案时使用且
// 更新下载按钮文案
if (viewHolder.isNewsDetail()) {
btnText = status;
extraBtnText = status;
} else if (context.getString(R.string.pluggable).equals(status)) {
btnText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "" + downloadAddWord) + getDownloadSizeText(viewHolder);
extraBtnText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "" + downloadAddWord);
} else if (context.getString(R.string.launch).equals(status)) {
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord);
extraBtnText = context.getString(R.string.launch_local);
} else if (context.getString(R.string.attempt).equals(status)) {
btnText = status + getDownloadSizeText(viewHolder);
extraBtnText = status;
decoratedBtnText = rawBtnText;
localBtnText = rawBtnText;
} else if (context.getString(R.string.pluggable).equals(rawBtnText)) {
decoratedBtnText = "升级" + (!containsAddWord ? "" : "" + downloadAddWord) + getWrappedDownloadSizeText(viewHolder);
localBtnText = "升级" + (!containsAddWord ? "" : "" + downloadAddWord);
} else if (context.getString(R.string.launch).equals(rawBtnText)) {
decoratedBtnText = rawBtnText + (!containsAddWord ? "" : "-" + downloadAddWord);
localBtnText = context.getString(R.string.launch_local);
} else if (context.getString(R.string.attempt).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.attempt);
localBtnText = rawBtnText;
if (showDualDownloadButton
&& viewHolder.getLocalDownloadContainer() != null
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
} else if (viewHolder.getOverlayTv() != null) {
useAlternativeTextStyle = true;
}
} else if (context.getString(R.string.install).equals(status)) {
btnText = context.getString(R.string.install);
extraBtnText = context.getString(R.string.install_local);
} else if (context.getString(R.string.update).equals(status)) {
btnText = context.getString(R.string.update);
extraBtnText = context.getString(R.string.update_local);
} else if (context.getString(R.string.install).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.install);
localBtnText = context.getString(R.string.install_local);
} else if (context.getString(R.string.update).equals(rawBtnText)) {
decoratedBtnText = context.getString(R.string.update);
localBtnText = context.getString(R.string.update_local);
if (showDualDownloadButton
&& viewHolder.getLocalDownloadContainer() != null
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
}
} else {
btnText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
extraBtnText = context.getString(R.string.download_local);
if (containsAddWord) {
decoratedBtnText = rawBtnText + downloadAddWord + getWrappedDownloadSizeText(viewHolder);
} else {
decoratedBtnText = rawBtnText;
}
localBtnText = context.getString(R.string.download_local);
if (showDualDownloadButton
&& viewHolder.getLocalDownloadContainer() != null
&& viewHolder.getLocalDownloadContainer().getVisibility() == View.VISIBLE) {
viewHolder.getLocalDownloadSizeTv().setVisibility(View.VISIBLE);
} else if (viewHolder.getOverlayTv() != null && !containsAddWord) {
useAlternativeTextStyle = true;
}
}
downloadButton.setText(btnText);
if (useAlternativeTextStyle) {
downloadButton.setText("");
viewHolder.getOverlayTv().setText(decoratedBtnText);
viewHolder.getOverlayTv().setVisibility(View.VISIBLE);
viewHolder.getOverlayTv().setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_special_download, 0, 0, 0);
if (viewHolder.getExtraOverlayTv() != null) {
viewHolder.getExtraOverlayTv().setVisibility(View.VISIBLE);
viewHolder.getExtraOverlayTv().setText(gameEntity.getApk().get(0).getSize());
}
} else {
if (viewHolder.getOverlayTv() != null && !showDualDownloadButton) {
viewHolder.getOverlayTv().setVisibility(View.GONE);
if (viewHolder.getExtraOverlayTv() != null) {
viewHolder.getExtraOverlayTv().setVisibility(View.GONE);
}
}
downloadButton.setText(decoratedBtnText);
}
if (viewHolder.getLocalDownloadTitleTv() != null) {
viewHolder.getLocalDownloadTitleTv().setText(extraBtnText);
viewHolder.getLocalDownloadTitleTv().setText(localBtnText);
}
}
@ -349,10 +378,13 @@ public class DetailDownloadUtils {
if (overlayTv != null
&& downloadEntity.getStatus() != DownloadStatus.done) {
overlayTv.setVisibility(View.GONE);
if (viewHolder.getExtraOverlayTv() != null) {
viewHolder.getExtraOverlayTv().setVisibility(View.GONE);
}
}
if (showAsVGame) {
updateVStyleDownloadButton(viewHolder, downloadButton, downloadEntity, status);
updateVStyleDownloadButton(viewHolder, downloadButton, downloadEntity, rawBtnText);
} else {
updateDefaultStyleDownloadButton(context, viewHolder, downloadButton, gameEntity, downloadEntity);
}
@ -441,7 +473,7 @@ public class DetailDownloadUtils {
return false;
}
private static String getDownloadSizeText(DetailViewHolder viewHolder) {
private static String getWrappedDownloadSizeText(DetailViewHolder viewHolder) {
return String.format("%s", viewHolder.getGameEntity().getApk().isEmpty() ? "" : viewHolder.getGameEntity().getApk().get(0).getSize());
}
@ -452,7 +484,7 @@ public class DetailDownloadUtils {
switch (downloadEntity.getStatus()) {
case redirected:
case downloading:
downloadButton.setText("游戏加载中 " + downloadEntity.getPercent() + "%");
downloadButton.setText(SpeedUtils.getSpeed(downloadEntity.getSpeed()));
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
break;
case waiting:
@ -466,11 +498,13 @@ public class DetailDownloadUtils {
case diskisfull:
case diskioerror:
case pause:
downloadButton.setText("继续加载 " + downloadEntity.getPercent() + "%");
String pausedText = viewHolder.getContext().getString(R.string.paused);
downloadButton.setText(getValidProgress(downloadEntity) + "% " + pausedText);
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
break;
case done:
if (!status.contains("更新")) {
String updateText = viewHolder.getContext().getString(R.string.update);
if (!status.contains(updateText)) {
if (VHelper.isInstalled(downloadEntity.getPackageName())) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
} else {
@ -510,8 +544,9 @@ public class DetailDownloadUtils {
case diskisfull:
case diskioerror:
case overflow:
String downloadingText = "游戏加载中 " + downloadEntity.getPercent() + "%";
String resumeText = "继续加载 " + downloadEntity.getPercent() + "%";
String pausedText = context.getString(R.string.paused);
String downloadingText = SpeedUtils.getSpeed(downloadEntity.getSpeed());
String resumeText = getValidProgress(downloadEntity) + "% " + pausedText;
downloadButton.setText((downloadEntity.getStatus() == DownloadStatus.downloading || downloadEntity.getStatus() == DownloadStatus.redirected) ? downloadingText : resumeText);
if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN);
@ -561,6 +596,10 @@ public class DetailDownloadUtils {
}
}
public static int getValidProgress(DownloadEntity downloadEntity) {
return (int) Math.ceil(downloadEntity.getPercent());
}
private static boolean handleDownloadButtonAsXapk(DownloadEntity downloadEntity, DownloadButton downloadButton) {
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);

View File

@ -19,8 +19,6 @@ import com.gh.common.util.EntranceUtils.jumpActivity
import com.gh.common.util.EntranceUtils.jumpActivityCompat
import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.catalog.CatalogActivity
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.category2.CategoryV2Activity
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
@ -151,14 +149,12 @@ object DirectUtils {
"qqqun",
"tag",
"all_community_article",
"category",
"block",
"column_collection",
"server",
"top_game_comment",
"wechat_bind",
"video",
"catalog",
"category_v2",
"common_collection",
"game_list",
@ -285,10 +281,6 @@ object DirectUtils {
)
)
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
"category_v2" -> directCategoryV2(
context,
linkEntity.link!!,
@ -481,6 +473,7 @@ object DirectUtils {
"column_test_v2" -> context.startActivity(
GameServerTestV2Activity.getIntent(
context,
linkEntity.link ?: "none",
entrance,
exposureEvent
)
@ -1422,47 +1415,6 @@ object DirectUtils {
}
}
/**
* 跳转分类
*/
@JvmStatic
fun directCategoryDirectory(
context: Context,
categoryId: String,
categoryTitle: String,
entrance: String? = null,
path: String? = ""
) {
if (categoryId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
bundle.putString(KEY_CATEGORY_ID, categoryId)
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
/**
* 跳转新分类
*/
@JvmStatic
fun directCatalog(
context: Context,
catalogId: String,
catalogTitle: String,
entrance: String? = null,
path: String? = "",
) {
if (catalogId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CatalogActivity::class.java.name)
bundle.putString(KEY_CATALOG_ID, catalogId)
bundle.putString(KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转新分类2.0
*/

View File

@ -37,10 +37,10 @@ import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
import com.gh.vspace.VHelper
import com.lightgame.download.DownloadConfig
@ -697,7 +697,7 @@ object DownloadItemUtils {
// 为 downloadButton 添加游戏实体,供点击的时候上报用
downloadBtn.putObject(gameEntity)
val gamePermissionDialogFragment = (context as AppCompatActivity).supportFragmentManager.findFragmentByTag(
val gamePermissionDialogFragment = (context as? AppCompatActivity)?.supportFragmentManager?.findFragmentByTag(
GamePermissionDialogFragment::class.java.name
) as GamePermissionDialogFragment?
gamePermissionDialogFragment?.dismissAllowingStateLoss()
@ -1162,7 +1162,11 @@ object DownloadItemUtils {
isSubscribe,
traceEvent
)
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (asVGame) {
ToastUtils.toast(gameEntity.name + "已加入加载队列")
} else {
ToastUtils.toast(gameEntity.name + "已加入下载队列")
}
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({

View File

@ -499,7 +499,7 @@ object DownloadObserver {
"game_name", downloadEntity.name,
"game_id", downloadEntity.gameId,
"game_type", downloadEntity.categoryChinese,
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
*kvs
)
} else if (downloadEntity.gameId == Constants.HALO_FUN_GAME_ID) {
@ -534,7 +534,7 @@ object DownloadObserver {
"game_name", downloadEntity.meta[Constants.GAME_NAME] ?: "",
"game_type", downloadEntity.meta[Constants.GAME_CATEGORY_IN_CHINESE] ?: "",
"game_label", downloadEntity.tags.joinToString(","),
"game_schema_type", if (downloadEntity.getMetaExtra(VHelper.KEY_BIT) == "32") "32位" else "64位",
"game_schema_type", if (downloadEntity.getMetaExtra(Constants.KEY_BIT) == "32") "32位" else "64位",
"page_name", getCurrentPageEntity().pageName,
"page_id", getCurrentPageEntity().pageId,
"page_business_id", getCurrentPageEntity().pageBusinessId,

View File

@ -105,9 +105,14 @@ public class EntranceUtils {
//TODO:添加FLAG_ACTIVITY_NEW_TASK会导致一跳转页面callback就被调用
//intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtras(bundle);
if (context instanceof AppCompatActivity) {
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
.startForResult(intent1, callback);
} else {
// 不要回调,正常跳转
context.startActivity(intent1);
}
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
.startForResult(intent1, callback);
}
} else {
// 应用未在运行

View File

@ -7,6 +7,7 @@ import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
@ -111,6 +112,14 @@ object GameSubstituteRepositoryHelper {
}
}
// 检查是否已安装该游戏 id
if (PackagesManager.getInstalledDataByGameId(game.id) != null) {
// 将该位置的游戏标记为需要替换
positionOfGameToBeReplacedList.add(index)
thisPositionNeedToBeReplaced = true
break
}
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
if (!thisPositionNeedToBeReplaced) {
var relatedPackageList = arrayListOf<String>()

View File

@ -308,7 +308,7 @@ object GameUtils {
}
/**
* 是否以畅玩游戏的形式来处理
* 是否默认以畅玩游戏的形式来处理
*/
@JvmStatic
fun shouldPerformAsVGame(gameEntity: GameEntity): Boolean {

View File

@ -57,6 +57,10 @@ object HomeBottomBarHelper {
return BottomTab(name = "我的光环", jsCode = animationCode, iconSelector = R.drawable.selector_ic_user, link = LinkEntity(type = TYPE_MY_HALO))
}
fun isDefaultHomeBottomTabDataExist(): Boolean {
return SPUtils.getString(KEY_HOME_BOTTOM_TAB).isNotEmpty()
}
@JvmStatic
fun getDefaultHomeBottomTabData(): List<BottomTab> {
try {

View File

@ -734,18 +734,6 @@ public class LogUtils {
LoghubUtils.log(object, LOG_STORE_EVENT, false);
}
public static void logNewCatalogAppearanceEvent(String entrance, String key) {
logCatalogEvent("access_to_classification", entrance, key, -1, -1, -1, -1);
}
public static void logSubCatalogClickEvent(String entrance, String key, int seq1) {
logCatalogEvent("click_first_classification", entrance, key, seq1, -1, -1, -1);
}
public static void logSubCatalogContentClickEvent(String entrance, String key, int seq1, int seq2) {
logCatalogEvent("click_secondary_classification", entrance, key, seq1, seq2, -1, -1);
}
public static void logSpecialCatalogContentClickEvent(String entrance, String key, int seq1, int seqContent) {
logCatalogEvent("click_content", entrance, key, seq1, -1, seqContent, -1);
}

View File

@ -4,12 +4,18 @@ import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.gh.download.DownloadManager
import com.gh.download.PackageObserver
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.hud.HeadUpDisplayHelper
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.R
import com.gh.gamecenter.hud.HeadUpDisplayLogHelper
import com.lightgame.utils.Utils
import org.greenrobot.eventbus.EventBus
@ -22,8 +28,10 @@ object PackageChangeHelper : DefaultLifecycleObserver {
private const val UPDATE_PENDING = 3
// <包名pending 类型,应用版本> Triple
private var pendingPackagePair: Triple<String, Int, String>? = null
private var pendingGhId: String ? = null
private var pendingPackageTriple: Triple<String, Int, String>? = null
private var pendingGhId: String? = null
private var pendingHUDShowed: Boolean = false
/**
* 添加一个等待中,待确定是否已成功安装的应用
@ -33,7 +41,9 @@ object PackageChangeHelper : DefaultLifecycleObserver {
if (installData == null) {
Utils.log(TAG, "添加了: $packageName 包名等待安装成功")
pendingPackagePair = Triple(packageName, INSTALL_PENDING, "")
pendingHUDShowed = false
pendingPackageTriple = Triple(packageName, INSTALL_PENDING, "")
} else {
Utils.log(TAG, "添加了: $packageName 包名等待安装更新成功")
@ -44,44 +54,58 @@ object PackageChangeHelper : DefaultLifecycleObserver {
pendingGhId = ghId.toString()
}
pendingPackagePair = Triple(packageName, UPDATE_PENDING, installData.version)
pendingHUDShowed = false
pendingPackageTriple = Triple(packageName, UPDATE_PENDING, installData.version)
}
}
fun isInstallPendingPackage(packageName: String): Boolean {
return pendingPackageTriple?.first == packageName
}
/**
* 添加一个等待中,待确定是否已成功卸载的应用
*/
fun addUninstallPendingPackage(packageName: String) {
Utils.log(TAG, "添加了: $packageName 包名等待卸载成功")
pendingPackagePair = Triple(packageName, UNINSTALL_PENDING, "")
pendingPackageTriple = Triple(packageName, UNINSTALL_PENDING, "")
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
if (pendingPackagePair != null) {
val packageName = pendingPackagePair?.first ?: return
val isInstallPending = pendingPackagePair?.second == INSTALL_PENDING
val isUninstallPending = pendingPackagePair?.second == UNINSTALL_PENDING
val isUpdatePending = pendingPackagePair?.second == UPDATE_PENDING
if (pendingPackageTriple != null) {
val packageName = pendingPackageTriple?.first ?: return
val isInstallPending = pendingPackageTriple?.second == INSTALL_PENDING
val isUninstallPending = pendingPackageTriple?.second == UNINSTALL_PENDING
val isUpdatePending = pendingPackageTriple?.second == UPDATE_PENDING
val pendingVersion = pendingPackagePair?.third ?: ""
val pendingVersion = pendingPackageTriple?.third ?: ""
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
val isInstalled = installedVersionName != null
if (isInstallPending && isInstalled) {
pendingPackagePair = null
pendingGhId = null
if (isInstallPending) {
if (isInstalled) {
pendingPackageTriple = null
pendingGhId = null
PackageRepository.addInstalledGame(packageName)
PackageRepository.addInstalledGame(PackageRepository.packageFilterManager, packageName)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
performInstallSuccessAction(packageName)
performInstallSuccessAction(packageName)
} else {
// 任务不存在了,将等待更新安装结果的 triple 置为 null
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
pendingPackageTriple = null
} else {
showHUDIfNeeded(packageName)
}
}
} else if (isUninstallPending && !isInstalled) {
pendingPackagePair = null
pendingPackageTriple = null
pendingGhId = null
// 从额外的包名白名单移除,下次启动时不再查询此包的安装情况
@ -95,12 +119,19 @@ object PackageChangeHelper : DefaultLifecycleObserver {
!pendingGhId.isNullOrEmpty() && pendingGhId != PackageUtils.getGhId(packageName).toString()
}
pendingPackagePair = null
pendingPackageTriple = null
pendingGhId = null
if (isUpdateValid) {
performUninstallSuccessAction(packageName)
performInstallSuccessAction(packageName)
} else {
// 任务不存在了,将等待更新安装结果的 triple 置为 null
if (DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) == null) {
pendingPackageTriple = null
} else {
showHUDIfNeeded(packageName)
}
}
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
@ -109,6 +140,27 @@ object PackageChangeHelper : DefaultLifecycleObserver {
}
}
private fun showHUDIfNeeded(packageName: String) {
if (pendingHUDShowed) return
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName) ?: return
val activity = CurrentActivityHolder.getCurrentActivity() ?: return
if (activity is DownloadManagerActivity) return
pendingHUDShowed = true
HeadUpDisplayHelper.showHUD(activity,
downloadEntity.icon ?: "",
activity.getString(R.string.hud_has_pending_install_game),
activity.getString(R.string.hud_head_to_download_manager),
showingCallback = {
HeadUpDisplayLogHelper.trackInstallationShow(downloadEntity, "游戏下载")
},
clickedCallback = {
DirectUtils.directToDownloadManager(activity, "HUD")
HeadUpDisplayLogHelper.trackInstallationClick(downloadEntity, "游戏下载")
})
}
/**
* 对外暴露的方法,用于添加一个安装成功的应用
* @param packageName 包名
@ -134,9 +186,11 @@ object PackageChangeHelper : DefaultLifecycleObserver {
* @param cachedGameEntity 缓存的 GameEntity用于快速更新状态
* @param withLog 是否需要记录日志
*/
private fun performInstallSuccessAction(packageName: String,
cachedGameEntity: GameEntity? = null,
withLog: Boolean = true) {
private fun performInstallSuccessAction(
packageName: String,
cachedGameEntity: GameEntity? = null,
withLog: Boolean = true
) {
Utils.log(TAG, "安装了: $packageName 包名的程序")
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName)
val gameId = if (downloadEntity != null && downloadEntity.gameId != null) downloadEntity.gameId else ""

View File

@ -6,6 +6,7 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
import android.os.Build
import android.os.Process
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LiveData
@ -75,25 +76,33 @@ object PackageHelper {
private var uploadUIDGapLog = true
// 光环运行的环境是否为默认的 UID (0)
private val isRunningOnDefaultUid by lazy { Process.myUid() / 100000 == 0 }
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
private var _commentPackageNameBlackList = arrayListOf<String>()
val commentPackageNameBlackList: ArrayList<String> = _commentPackageNameBlackList
val commentPackageNameBlackList: ArrayList<String>
get() = _commentPackageNameBlackList
// 关闭下载的包列表
private var _downloadPackageNameBlackList = arrayListOf<String>()
val downloadPackageNameBlackList: ArrayList<String> = _downloadPackageNameBlackList
val downloadPackageNameBlackList: ArrayList<String>
get() = _downloadPackageNameBlackList
// 本地已安装的包去掉关闭下载的包后的列表
private var _validLocalPackageNameSet = hashSetOf<String>()
val validLocalPackageNameSet: HashSet<String> = _validLocalPackageNameSet
val validLocalPackageNameSet: HashSet<String>
get() = _validLocalPackageNameSet
// 游戏包名匹配列表
private var _relatedPackageList = arrayListOf<SettingsEntity.GameWithPackages>()
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages> = _relatedPackageList
val relatedPackageList: ArrayList<SettingsEntity.GameWithPackages>
get() = _relatedPackageList
// 接口控制的已安装应用列表获取开关状态 (UI 显示)
private var _installedPackageApiSwitchStatusLiveData = MutableLiveData<Boolean>()
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean> = _installedPackageApiSwitchStatusLiveData
val installedPackageApiSwitchStatusLiveData: LiveData<Boolean>
get() = _installedPackageApiSwitchStatusLiveData
// 本地已安装包的列表
var localPackageNameSet = hashSetOf<String>()
@ -117,12 +126,16 @@ object PackageHelper {
val isSupportGetInstalledAppsPermission = isSupportGetInstalledAppsPermission(context)
if (!isSupportGetInstalledAppsPermission) {
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
if (isRunningOnDefaultUid) {
// 设备不支持动态管理获取已安装应用列表,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
}
onGetInstalledPackagesAgreed()
} else if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
if (isRunningOnDefaultUid) {
// 设备支持动态管理获取已安装应用列表但已经授权,忽略接口控制,使用另类方式获取已安装应用列表
updateUseAlternativeWayToGetInstalledPackages()
}
onGetInstalledPackagesAgreed()
}
@ -258,8 +271,10 @@ object PackageHelper {
isGetInstalledPackagesAgreedRequired = DISABLED
// 启用另类获取已安装应用列表的 API
updateUseAlternativeWayToGetInstalledPackages()
if (isRunningOnDefaultUid) {
// 启用另类获取已安装应用列表的 API
updateUseAlternativeWayToGetInstalledPackages()
}
onGetInstalledPackagesAgreed()
}
@ -531,6 +546,7 @@ object PackageHelper {
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
PackageRepository.addInstalledGames(
packageFilterManager = PackageRepository.packageFilterManager,
pkgNameList = ArrayList(installedPackageNameSet),
updateInstallStatus = true
)

View File

@ -22,12 +22,15 @@ import com.gh.gamecenter.install.InstallService
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import java.io.File
// TODO 将弹窗改成以责任链模式来处理
object PackageInstaller {
private val listeners = mutableListOf<OnInstallListener>()
/**
* 为了兼容java代码
*/
@ -58,7 +61,7 @@ object PackageInstaller {
val isDownloadAsVGame = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VGAME
|| downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.DUAL_DOWNLOAD_VGAME
val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return
val currentActivity = AppManager.getInstance().currentActivity() ?: return
if (!ignoreAsVGame && isDownloadAsVGame) {
VHelper.install(currentActivity, downloadEntity)
@ -126,6 +129,7 @@ object PackageInstaller {
installWithPureModeHandled(
context,
pkgPath,
downloadEntity?.packageName,
downloadEntity?.gameId ?: "unknown",
downloadEntity?.name ?: "unknown",
downloadEntity?.categoryChinese ?: "unknown"
@ -165,19 +169,20 @@ object PackageInstaller {
private fun installWithPureModeHandled(
context: Context,
pkgPath: String,
pkgName: String?,
gameId: String,
gameName: String,
gameType: String,
) {
PureModeHelper.handlePureModeIfNeeded(context, gameId, gameName, gameType) {
install(context, pkgPath)
install(context, pkgPath, pkgName)
}
}
/**
* 最终执行安装的方法
*/
private fun install(context: Context, pkgPath: String) {
private fun install(context: Context, pkgPath: String, pkgName: String?) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU && Build.MANUFACTURER.lowercase().contains("xiaomi")) {
@ -188,10 +193,13 @@ object PackageInstaller {
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
dispatchOnInstallListener(pkgPath, pkgName)
}
fun installMultiple(
context: Context,
pkgName: String,
pkgPath: String,
sessionId: Int = -1
) {
@ -214,6 +222,24 @@ object PackageInstaller {
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
// 提交数据流并执行安装
session.commit(pendingIntent.intentSender)
dispatchOnInstallListener(pkgName, pkgPath)
}
fun registerOnInstallListener(listener: OnInstallListener) {
if (!listeners.contains(listener)) {
listeners.add(listener)
}
}
fun unregisterOnInstallListener(listener: OnInstallListener) {
listeners.remove(listener)
}
private fun dispatchOnInstallListener(pkgPath: String, pkgName: String?) {
for (listener in listeners) {
listener.onInstalling(pkgName, pkgPath)
}
}
/**
@ -305,4 +331,8 @@ object PackageInstaller {
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis())
}
interface OnInstallListener {
fun onInstalling(packageName: String?, packagePath: String)
}
}

View File

@ -14,6 +14,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.AndroidException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -222,8 +223,19 @@ public class PackageUtils {
if (metaDate != null) {
return metaDate.get(name);
}
} catch (NameNotFoundException e) {
// e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_META_DATA_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return null;
}
@ -627,8 +639,19 @@ public class PackageUtils {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (NameNotFoundException e) {
// do nothing
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_VERSION_NAME_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return null;
}
@ -640,8 +663,18 @@ public class PackageUtils {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
} catch (NameNotFoundException e) {
// do nothing
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_VERSION_CODE_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return 0;
}
@ -654,8 +687,18 @@ public class PackageUtils {
try {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationIcon(packageName);
} catch (NameNotFoundException e) {
// do nothing
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_ICON_ERROR",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
}
return null;
}
@ -706,8 +749,19 @@ public class PackageUtils {
jsonObject.put("version", packageInfo.versionName);
}
return jsonObject;
} catch (JSONException | NameNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
if (e instanceof AndroidException) {
// 有些设备会出现 DeadSystemException
SentryHelper.INSTANCE.onEvent(
"GET_APP_BASIC_INFO_BY_PACKAGE_NAME",
"packageName",
packageName,
"exception_digest",
e.getLocalizedMessage()
);
}
return jsonObject;
}
}

View File

@ -3,12 +3,12 @@ package com.gh.common.util
import android.annotation.SuppressLint
import com.gh.gamecenter.common.entity.SignatureEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.schedulers.Schedulers
/**
* 存储光环网游使用的签名
@ -24,7 +24,7 @@ object SignatureRepository {
RetrofitManager.getInstance()
.newApi
.ghSignature
.compose(singleToMain())
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<ArrayList<SignatureEntity>>() {
override fun onSuccess(data: ArrayList<SignatureEntity>) {
signDigestList = ArrayList()

View File

@ -190,6 +190,8 @@ object ViewPagerFragmentHelper {
// 新游开测
TYPE_COLUMN_TEST -> {
className = GameServerTestV2Fragment::class.java.name
bundle.putString(EntranceConsts.KEY_ID, entity.link)
bundle.putString(EntranceConsts.KEY_NAME, entity.text)
}
// 分类2.0
TYPE_CATEGORY_V2 -> {

View File

@ -1,331 +0,0 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.setDrawableEnd
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.visibleIf
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.google.android.flexbox.FlexboxLayout
class CatalogFilterView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private var mTypeTv: TextView
private var mCatalogTv: TextView
private var mSizeTv: TextView
private var mTypeContainer: View
private var mCatalogContainer: View
private var mSizeContainer: View
private var mTypeFilterArray = ArrayList<SortType>()
private var mCatalogFilterArray = ArrayList<CatalogEntity.SubCatalogEntity>()
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
private var mOnCatalogFilterSetupListener: OnCatalogFilterSetupListener? = null
private var mTypePopupWindow: PopupWindow? = null
private var mCatalogPopupWindow: PopupWindow? = null
private var mSizePopupWindow: PopupWindow? = null
init {
View.inflate(context, R.layout.layout_catalog_filter, this)
mTypeTv = findViewById(R.id.type_tv)
mCatalogTv = findViewById(R.id.catalog_tv)
mSizeTv = findViewById(R.id.size_tv)
mTypeContainer = findViewById(R.id.container_type)
mCatalogContainer = findViewById(R.id.container_catalog)
mSizeContainer = findViewById(R.id.container_size)
mTypeContainer.setOnClickListener {
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
}
mCatalogContainer.setOnClickListener {
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
}
mSizeContainer.setOnClickListener {
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
}
fun setTypeList(switch: CatalogEntity.CatalogSwitch) {
switch.run {
if ("on" == hotSort) mTypeFilterArray.add(SortType.RECOMMENDED)
if ("on" == newSort) mTypeFilterArray.add(SortType.NEWEST)
if ("on" == starSort) mTypeFilterArray.add(SortType.RATING)
}
if (mTypeFilterArray.isNotEmpty()) mTypeTv.text = mTypeFilterArray[0].value
}
fun setCatalogList(subCatalogList: List<CatalogEntity.SubCatalogEntity>, initCatalogName: String) {
mCatalogFilterArray = ArrayList(subCatalogList)
mCatalogTv.text = initCatalogName
}
fun setOnConfigSetupListener(onCatalogFilterSetupListener: OnCatalogFilterSetupListener) {
mOnCatalogFilterSetupListener = onCatalogFilterSetupListener
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
targetTextView.setTextColor(Color.WHITE)
} else {
targetTextView.background = null
targetTextView.setTextColor(R.color.text_757575.toColor(context))
}
}
private fun showSelectTypePopupWindow(containerView: View, typeTv: TextView, typeText: String) {
typeTv.setTextColor(R.color.text_theme.toColor(context))
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
val inflater = LayoutInflater.from(typeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply { mTypePopupWindow = this }
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (type in mTypeFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = typeTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = type.value
toggleHighlightedTextView(tv, typeText == type.value)
tv.tag = type.value
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
typeTv.text = type.value
mOnCatalogFilterSetupListener?.onSetupSortType(type)
}
}
popupWindow.setOnDismissListener {
typeTv.setTextColor(R.color.text_757575.toColor(context))
typeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
mTypePopupWindow = null
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectCatalogPopupWindow(containerView: View, catalogTv: TextView, catalogText: String) {
catalogTv.setTextColor(R.color.text_theme.toColor(context))
catalogTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
val inflater = LayoutInflater.from(catalogTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply { mCatalogPopupWindow = this }
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (entity in mCatalogFilterArray) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = catalogTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
val iv = item.findViewById<ImageView>(R.id.recommend_iv)
tv.text = entity.name
iv.visibleIf(entity.recommended)
toggleHighlightedTextView(tv, catalogText == entity.name)
tv.tag = entity.name
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
catalogTv.text = entity.name
mOnCatalogFilterSetupListener?.onSetupSortCatalog(entity)
}
}
popupWindow.setOnDismissListener {
catalogTv.setTextColor(R.color.text_757575.toColor(context))
catalogTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
mCatalogPopupWindow = null
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun showSelectSizePopupWindow(containerView: View, sizeTv: TextView, sizeText: String) {
sizeTv.setTextColor(R.color.text_theme.toColor(context))
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_up)
val inflater = LayoutInflater.from(sizeTv.context)
val layout = inflater.inflate(R.layout.layout_filter_size, null)
val popupWindow = PopupWindow(
layout,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply { mSizePopupWindow = this }
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
val backgroundView = layout.findViewById<View>(R.id.background)
sizeFilterArray = if (sizeFilterArray == null) {
getDefaultSizeFilterArray()
} else {
sizeFilterArray?.apply {
if (firstOrNull()?.text != "全部大小") {
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
}
}
}
backgroundView.setOnClickListener {
popupWindow.dismiss()
}
for (size in sizeFilterArray!!) {
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
// 单列 3 个,强行设置宽度为屏幕的 1/3
val width = sizeTv.context.resources.displayMetrics.widthPixels / 3
val height = item.layoutParams.height
item.layoutParams = ViewGroup.LayoutParams(width, height)
flexboxLayout.addView(item)
val tv = item.findViewById<TextView>(R.id.size_tv)
tv.text = size.text
toggleHighlightedTextView(tv, sizeText == size.text)
tv.tag = size.text
item.setOnClickListener {
toggleHighlightedTextView(tv, true)
popupWindow.dismiss()
sizeTv.text = size.text
mOnCatalogFilterSetupListener?.onSetupSortSize(size)
}
}
popupWindow.setOnDismissListener {
sizeTv.setTextColor(R.color.text_757575.toColor(context))
sizeTv.setDrawableEnd(R.drawable.ic_filter_arrow_down)
mSizePopupWindow = null
}
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.animationStyle = 0
popupWindow.showAsDropDown(containerView, 0, 0)
}
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
return arrayListOf<SubjectSettingEntity.Size>().apply {
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
add(SubjectSettingEntity.Size(min = -1, max = 100, text = "100M以下"))
add(SubjectSettingEntity.Size(min = 100, max = 300, text = "100-300M"))
add(SubjectSettingEntity.Size(min = 300, max = 500, text = "300-500M"))
add(SubjectSettingEntity.Size(min = 500, max = 1000, text = "500M-1G"))
add(SubjectSettingEntity.Size(min = 1000, max = -1, text = "1G以上"))
}
}
fun setRootBackgroundColor(@ColorInt color: Int) {
findViewById<View>(R.id.config_controller).setBackgroundColor(color)
}
fun setItemTextColor(@ColorInt color: Int) {
mTypeTv.setTextColor(color)
mCatalogTv.setTextColor(color)
mSizeTv.setTextColor(color)
}
fun updatePopupWindow() {
when {
mTypePopupWindow != null && mTypePopupWindow!!.isShowing -> {
mTypePopupWindow?.dismiss()
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
}
mCatalogPopupWindow != null && mCatalogPopupWindow!!.isShowing -> {
mCatalogPopupWindow?.dismiss()
showSelectCatalogPopupWindow(this, mCatalogTv, mCatalogTv.text.toString())
}
mSizePopupWindow != null && mSizePopupWindow!!.isShowing -> {
mSizePopupWindow?.dismiss()
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
}
}
interface OnCatalogFilterSetupListener {
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
fun onSetupSortType(sortType: SortType)
fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity)
}
enum class SortType(val value: String) {
RECOMMENDED("热门推荐"),
NEWEST("最新上线"),
RATING("最高评分")
}
}

View File

@ -0,0 +1,18 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
class InterceptTouchContainView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr) {
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return true
}
}

View File

@ -0,0 +1,65 @@
package com.gh.common.view
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.children
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.visibleIf
/**
* 单游戏卡片标签样式专用
* 根据宽度展示标签个数,最多展示三个标签
*/
class SingleCardTagContainerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : LinearLayout(context, attrs) {
private val childViews = arrayListOf<TextView>()
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
children.forEach {
// 父容器不限制子View的宽度
it.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec)
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
// 如果有显示不完整的标签,直接隐藏
children.forEach {
it.visibleIf(it.right <= width)
}
}
fun setData(tags: List<String>) {
removeAllViews()
tags.forEachIndexed { index, tag ->
if (index < 3) {
// 缓存子View 避免频繁创建新View
val tvTag = childViews.getOrNull(index) ?: TextView(context).also { childViews.add(it) }
if (index == 0) {
tvTag.text = tag
} else {
tvTag.text = "$DELIMITER$tag"
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
tvTag.setTextAppearance(R.style.TextCaption2)
} else {
tvTag.setTextAppearance(context, R.style.TextCaption2)
}
tvTag.setTextColor(R.color.text_tertiary.toColor(context))
addView(tvTag)
}
}
}
companion object {
private const val DELIMITER = "·"
}
}

View File

@ -1,64 +0,0 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import com.gh.gamecenter.R
import com.gh.gamecenter.category.CategoryListActivity
import com.gh.gamecenter.entity.CategoryEntity
class SubCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
LinearLayout(context, attrs, defStyleAttr) {
var leftTv: TextView
var centerTv: TextView
var rightTv: TextView
var leftDivider: View
var rightDivider: View
var primeCategory: CategoryEntity? = null
var categoryTitle: String? = ""
init {
View.inflate(context, R.layout.layout_sub_category, this)
leftTv = findViewById(R.id.tv_left_sub_category)
centerTv = findViewById(R.id.tv_center_sub_category)
rightTv = findViewById(R.id.tv_right_sub_category)
leftDivider = findViewById(R.id.divider_left)
rightDivider = findViewById(R.id.divider_right)
}
fun setLeftCategory(category: CategoryEntity) {
setCategory(leftTv, category)
}
fun setCenterCategory(category: CategoryEntity) {
setCategory(centerTv, category)
leftDivider.visibility = View.VISIBLE
}
fun setRightCategory(category: CategoryEntity) {
setCategory(rightTv, category)
rightDivider.visibility = View.VISIBLE
}
private fun setCategory(tv: TextView, category: CategoryEntity) {
tv.text = category.name
tv.setOnClickListener {
tv.context.startActivity(
CategoryListActivity.getIntent(
tv.context,
categoryTitle!!,
primeCategory!!,
category.name!!
)
)
}
}
}

View File

@ -207,7 +207,7 @@ object XapkDialogHelper {
SuggestType.GAME,
null,
hint,
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon)
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, downloadEntity.icon?: "")
)
NewFlatLogUtils.logXApkUnzipFailedDialogClick(
"提交反馈",

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Environment
import android.provider.Settings
import com.gh.common.constant.Config
import com.gh.common.util.DirectUtils
@ -46,8 +47,6 @@ import java.util.*
@SuppressLint("StaticFieldLeak")
object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path"
const val XAPK_EXTENSION_NAME = "xapk"
// 通过解压过程存放于 DownloadEntity meta
@ -57,12 +56,21 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
const val XAPK_DATA_EXTENSION_NAME = "obb"
const val PACKAGE_EXTENSION_NAME = "apk"
// 系统是否有 obb 访问漏洞
val systemHasFlaw by lazy {
val systemMatched = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
val rootPath = Environment.getExternalStorageDirectory().path
val fileListMatched = File(rootPath, "Android").list().contentEquals(File(rootPath, "\u200bAndroid").list())
systemMatched && fileListMatched
}
private const val GUIDE_TYPE_MIUI_OPTIMIZATION = "miui_optimization"
private const val MIUI_OPTIMIZATION_WARNING_DIALOG_ENTRANCE = "MIUI优化关闭提示弹窗"
private var mContext = HaloApp.getInstance().application.applicationContext
private val mXApkUnZipper = XApkUnZipper(this)
private val mXApkUnZipper = XApkUnZipper(this, useFlawToUnzip = systemHasFlaw)
.also {
it.registerCallback(this)
}
@ -343,7 +351,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
PackageInstaller.installMultiple(applicationContext, downloadEntity.path, sessionId)
PackageInstaller.installMultiple(applicationContext, downloadEntity.packageName, downloadEntity.path, sessionId)
NDataChanger.notifyDataChanged(downloadEntity)
}
}

View File

@ -356,9 +356,10 @@ public class DownloadManager implements DownloadStatusListener {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE, Constants.VGAME);
ExtensionsKt.addMetaExtra(downloadEntity, DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200");
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_REQUIRED_G_APPS, gameEntity.getGAppsSwitch());
ExtensionsKt.addMetaExtra(downloadEntity, VHelper.KEY_BIT, apkEntity.getBit());
}
ExtensionsKt.addMetaExtra(downloadEntity, Constants.KEY_BIT, apkEntity.getBit());
// 记录是否为双下载按钮模式
if (isDualDownloadTypeEnabled) {
if (asVGame) {
@ -541,6 +542,7 @@ public class DownloadManager implements DownloadStatusListener {
checkDownloadEntryRecordValidate(url);
if (isDownloadCompleted(url)) {
downloadEntity.setStatus(DownloadStatus.done);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
} else if (!isTaskDownloading(url)) {
DownloadEntity daoEntity = mDownloadDao.get(downloadEntity.getUrl());
@ -994,19 +996,21 @@ public class DownloadManager implements DownloadStatusListener {
* 3.检查是否显示下载通知栏
*/
public void initDownloadService() {
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
packageExecutor.execute(() -> {
final Set<String> urlSet = NDataChanger.INSTANCE.getDownloadingTaskUrlSet();
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlSet.contains(downloadEntity.getUrl())
&& (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
}
}
}
startDownloadService();
checkAndRetryDownload();
startDownloadService();
checkAndRetryDownload(true);
});
}
/**
@ -1097,13 +1101,15 @@ public class DownloadManager implements DownloadStatusListener {
/**
* 检查并尝试重试下载
*/
public void checkAndRetryDownload() {
public void checkAndRetryDownload(boolean includePausedTask) {
if (!NetworkUtils.isWifiConnected(mContext)) return;
for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeDoneTask()) {
if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())) {
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())
|| (includePausedTask && DownloadStatus.pause.equals(downloadEntity.getStatus()))
) {
DownloadManager.getInstance().put(downloadEntity.getUrl(), System.currentTimeMillis());
Message msg = Message.obtain();
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_AUTO_TASK;

View File

@ -59,8 +59,8 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
override fun getBusinessId(): Pair<String, String> {
val fragment = targetFragment as GameDetailFragment
return if (fragment.arguments != null) {
val fragment = targetFragment as? GameDetailFragment?
return if (fragment?.arguments != null) {
Pair(fragment.requireArguments().getString(EntranceConsts.KEY_GAMEID) ?: "", "")
} else {
super.getBusinessId()

View File

@ -847,6 +847,8 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
mFinalUrl = finalUrl ?: ""
imageView.setImageLoaderCallback(object : SimpleImageLoader() {
var tryCount = 0
override fun onSuccess(image: File) {
if (finalUrl != mUrlList!![position]) {
val options = BitmapFactory.Options()
@ -867,6 +869,15 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
onBackPressed()
}
}
override fun onFail(error: java.lang.Exception?) {
super.onFail(error)
// 加载压缩图片失败时尝试加载原图
if (finalUrl != rawUrl && tryCount == 0) {
loadImage(thumbnailImageUrl, rawUrl, imageView)
tryCount ++
}
}
})
loadImage(thumbnailImageUrl, compressedStandardImageUrl, imageView)

View File

@ -43,6 +43,7 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import com.gh.ad.AdDelegateHelper;
import com.gh.ad.SplashAdVideoView;
import com.gh.common.constant.Config;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryDatabase;
@ -98,6 +99,7 @@ import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.home.custom.model.CustomPageShareRepository;
import com.gh.gamecenter.home.skip.PackageSkipActivity;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.login.utils.QuickLoginHelper;
import com.gh.gamecenter.packagehelper.PackageViewModel;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.room.AppDatabase;
@ -128,7 +130,6 @@ import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import io.reactivex.SingleSource;
@ -147,7 +148,7 @@ public class MainActivity extends BaseActivity {
public static final String SHOW_AD = "show_ad";
public static final int COUNTDOWN_AD = 100;
public static final int COUNTDOWN_MAX_COUNT = 3;
private int mCountdownMaxCount = 3;
private int mCountdownCount = 0;
private static final String CURRENT_PAGE = "current_page";
@ -254,9 +255,6 @@ public class MainActivity extends BaseActivity {
}
}
// 必须放在这里,否则会导致获取 baseActivity 不是本应用包名
DownloadManager.getInstance().initDownloadService();
ReservationRepository.refreshReservations();
// 跳转至其它页面
@ -319,7 +317,7 @@ public class MainActivity extends BaseActivity {
mMainWrapperViewModel.requestAllDialogData();
// QuickLoginHelper.getPhoneInfo();
QuickLoginHelper.preLogin(this);
// TODO 搞清楚为什么这里要获取微信相关配置
WechatBindHelper.getWechatConfig(null);
@ -507,6 +505,11 @@ public class MainActivity extends BaseActivity {
float screenHeightInDp = DisplayUtils.px2dip(this, screenHeightInPx);
if (startAdContainer != null && sdkStartAdContainer != null && adsFl != null) {
mCountdownMaxCount = AdDelegateHelper.INSTANCE.getSplashAdDisplayInterval();
TextView jumpBtn = findViewById(R.id.jumpBtn);
if (jumpBtn != null) {
jumpBtn.setText(getString(R.string.splash_jump, mCountdownMaxCount));
}
AdDelegateHelper.requestSplashAd(
this,
screenWidthInPx,
@ -536,7 +539,7 @@ public class MainActivity extends BaseActivity {
super.handleMessage(msg);
if (msg.what == COUNTDOWN_AD) {
mCountdownCount++;
if (COUNTDOWN_MAX_COUNT < mCountdownCount) {
if (mCountdownMaxCount < mCountdownCount) {
AdDelegateHelper.INSTANCE.setShowingSplashAd(false);
hideSplashAd();
@ -556,7 +559,7 @@ public class MainActivity extends BaseActivity {
}
} else {
TextView jumpBtn = findViewById(R.id.jumpBtn);
jumpBtn.setText(String.format(Locale.CHINA, "跳过 %d", COUNTDOWN_MAX_COUNT - mCountdownCount));
jumpBtn.setText(getString(R.string.splash_jump, mCountdownMaxCount - mCountdownCount));
Message newMsg = Message.obtain();
newMsg.what = COUNTDOWN_AD;
newMsg.obj = msg.obj;
@ -584,6 +587,11 @@ public class MainActivity extends BaseActivity {
getIntent().putExtra(SHOW_AD, false);
View startAdContainer = findViewById(R.id.startAdContainer);
if (startAdContainer != null) {
// 如果有播放开屏视频广告,需要及时释放
SplashAdVideoView adVideoView = startAdContainer.findViewById(R.id.ad_video);
if (adVideoView != null) {
adVideoView.clearAll();
}
startAdContainer.setVisibility(View.GONE);
ExtensionsKt.removeFromParent(startAdContainer, true);
}
@ -739,7 +747,7 @@ public class MainActivity extends BaseActivity {
ToastUtils.showToast("游戏启动中,请稍后~");
handler.postDelayed(() -> {
if(VHelper.isInnerInstalled(gamePackageName)) {
if (VHelper.isInnerInstalled(gamePackageName)) {
launchGame(gamePackageName).invoke();
} else {
VHelper.postOnInitialized(launchGame(gamePackageName));
@ -799,7 +807,7 @@ public class MainActivity extends BaseActivity {
public void onFailure(@Nullable HttpException e) {
super.onFailure(e);
try {
ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, "", "", "内容实名", null, null, code -> {
ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, "", "", "内容实名", null, null, code -> {
if (code == 404001) {
if (mShouldShowAd) {
AppExecutor.getUiExecutor().executeWithDelay(() -> {
@ -938,7 +946,7 @@ public class MainActivity extends BaseActivity {
Config.getNewSetting();
}
// mPackageViewModel.checkData();
mPackageViewModel.checkData();
deleteSimulatorGame();
}
}

View File

@ -1,21 +0,0 @@
package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.halo.assistant.fragment.user.SelectPortraitFragment;
/**
* Created by khy on 2017/2/10.
*/
public class SelectUserIconActivity extends ToolBarActivity {
@NonNull
public static Intent getIntent(Context context) {
return getTargetIntent(context, SelectUserIconActivity.class, SelectPortraitFragment.class);
}
}

View File

@ -9,6 +9,7 @@ import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.amway.AmwaySuccessFragment
import com.gh.gamecenter.gamedetail.LibaoListFragment
import com.halo.assistant.fragment.SwitchInstallMethodFragment
import com.halo.assistant.fragment.user.ManuallyRealNameFragment
import com.halo.assistant.fragment.user.RealNameInfoFragment
@ -29,12 +30,14 @@ class ShellActivity : ToolBarActivity() {
private fun handleIntent(bundle: Bundle?) {
// We parse the bundle to fragment to let fragment get data from bundle itself to survive configuration changes.
val intentType = Type.fromString(bundle?.getString(INTENT_TYPE) ?: "")
val extraData = bundle?.getBundle(EntranceConsts.KEY_DATA)
when (intentType) {
Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle))
Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment())
Type.REAL_NAME_INFO -> startFragment(RealNameInfoFragment().with(bundle))
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(bundle?.getBundle(EntranceConsts.KEY_DATA)))
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(extraData))
Type.SIMPLE_LIBAO_LIST -> startFragment(LibaoListFragment.newInstance(extraData))
}
}
@ -68,7 +71,8 @@ class ShellActivity : ToolBarActivity() {
AMWAY_SUCCESS("amway_success"),
SWITCH_INSTALL_METHOD("switch_install_method"),
REAL_NAME_INFO("real_name_info"),
MANUALLY_REAL_NAME("manually_real_name");
MANUALLY_REAL_NAME("manually_real_name"),
SIMPLE_LIBAO_LIST("simple_libao_list");
companion object {
fun fromString(typeString: String): Type {

View File

@ -5,7 +5,6 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_PUSH;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ANSWER;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARCHIVE_LOGIN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARTICLE;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_CATEGORY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN_COLLECTION;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COMMUNITY;
@ -15,6 +14,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_DOWNLOAD;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECTION_DETAIL;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_GAME_COLLECTION_SQUARE;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INSTALL;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_INVOKE_ONLY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_LIBAO;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ;
@ -56,6 +56,8 @@ import androidx.annotation.Nullable;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
@ -77,6 +79,7 @@ import com.gh.vspace.shortcut.OnCreateShortcutResult;
import com.gh.vspace.shortcut.ShortcutManager;
import com.gh.vspace.shortcut.ShortcutPermissionTipsDialog;
import com.lightgame.config.CommonDebug;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Utils;
import com.muugi.shortcut.core.Executor;
@ -311,10 +314,6 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToCommunityColumn(this, community, columnId, entrance, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, entrance, pathName);
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, entrance, "", "", "", "", null,false);
break;
@ -434,6 +433,13 @@ public class SkipActivity extends BaseActivity {
String restartGamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
VHelper.launch(this, restartGamePkg, false, true);
break;
case HOST_INSTALL:
String packageName = uri.getQueryParameter("package_name");
DownloadEntity downloadEntity = DownloadManager
.getInstance()
.getDownloadEntitySnapshotByPackageName(packageName);
PackageInstaller.install(this, downloadEntity);
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;

View File

@ -83,19 +83,20 @@ class SplashAdActivity : BaseActivity() {
super.handleMessage(msg)
if (msg.what == MainActivity.COUNTDOWN_AD) {
mCountdownCount++
if (MainActivity.COUNTDOWN_MAX_COUNT < mCountdownCount) {
if (COUNTDOWN_MAX_COUNT < mCountdownCount) {
AdDelegateHelper.isShowingSplashAd = false
finishActivity()
} else {
val jumpBtn = findViewById<TextView>(R.id.jumpBtn)
jumpBtn.text =
String.format(Locale.CHINA, "跳过 %d", MainActivity.COUNTDOWN_MAX_COUNT - mCountdownCount)
jumpBtn.text = getString(R.string.splash_jump, COUNTDOWN_MAX_COUNT - mCountdownCount)
mBaseHandler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_AD, 1000)
}
}
}
companion object {
private const val COUNTDOWN_MAX_COUNT = 3
@JvmStatic
fun getIntent(context: Context): Intent {
return Intent(context, SplashAdActivity::class.java)

View File

@ -14,6 +14,7 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.DirectUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.ItemViewType;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.ImageUtils;
@ -178,7 +179,12 @@ public class CommentDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
holder.commentTimeTv.setText(holder.commentTimeTv.getText() + " · " + commentEntity.getSource().getRegion());
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.commentContentTv, commentEntity.getContent());
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.commentContentTv,
commentEntity.getContent(),
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(mContext, "评论详情")
);
ArticleCommentParent parent = commentEntity.getParent();
if (parent != null && !TextUtils.isEmpty(parent.getUser().getName())) {
holder.quoteContainer.setVisibility(View.VISIBLE);
@ -197,7 +203,12 @@ public class CommentDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
content = mContext.getString(R.string.comment_hide_hint);
holder.quoteContentTv.setTextColor(mContext.getResources().getColor(R.color.text_d5d5d5));
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.quoteContentTv, content);
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.quoteContentTv,
content,
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(mContext, "评论详情")
);
} else {
holder.quoteContainer.setVisibility(View.GONE);
}

View File

@ -25,6 +25,7 @@ import com.gh.gamecenter.ShareCardPicActivity;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.adapter.viewholder.CommentHeadViewHolder;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.common.retrofit.OkHttpCache;
@ -393,7 +394,12 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
return;
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.commentContentTv, commentEntity.getContent());
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.commentContentTv,
commentEntity.getContent(),
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(holder.commentContentTv.getContext(), "消息详情")
);
ArticleCommentParent parent = commentEntity.getParent();
if (parent != null && !TextUtils.isEmpty(parent.getUser().getName())) {
holder.quoteContainer.setVisibility(View.VISIBLE);
@ -412,7 +418,12 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
content = mContext.getString(R.string.comment_hide_hint);
holder.quoteContentTv.setTextColor(mContext.getResources().getColor(R.color.text_d5d5d5));
}
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.quoteContentTv, content);
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(
holder.quoteContentTv,
content,
Constants.DEFAULT_TEXT_WRAPPER,
new TextHelper.DirectToWebViewHighlightedTextClick(holder.quoteContentTv.getContext(), "消息详情")
);
} else {
holder.quoteContainer.setVisibility(View.GONE);
}

View File

@ -33,6 +33,7 @@ import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.core.utils.ToastUtils
@ -78,6 +79,9 @@ class DetailViewHolder(
// 额外的文字 (用于一些含图片的情况)
val overlayTv: TextView?
val overlayContainer: View?
val extraOverlayTv: TextView?
var downloadPb: DownloadButton
var downloadTips: LottieAnimationView
@ -90,6 +94,8 @@ class DetailViewHolder(
downloadPb = view.findViewById(R.id.detail_progressbar)
downloadTips = view.findViewById(R.id.downloadTipsLottie)
overlayTv = view.findViewById(R.id.overlayTv)
overlayContainer = view.findViewById(R.id.overlayContainer)
extraOverlayTv = view.findViewById(R.id.extraOverlayTv)
multiVersionDownloadTv = view.findViewById(R.id.multiVersionDownloadTv)
localDownloadContainer = view.findViewById(R.id.localDownloadContainer)
localDownloadSizeTv = view.findViewById(R.id.localDownloadSizeTv)
@ -102,7 +108,7 @@ class DetailViewHolder(
val localDownloadListener = OnDetailDownloadClickListener(
mViewHolder = this,
mEntrance = entrance,
mEntrance = entrance,
mName = name ?: "",
mTitle = title ?: "",
mAsVGame = false,
@ -152,6 +158,9 @@ class DetailViewHolder(
}
}
downloadPb.putWidgetBusinessName("游戏详情页")
// "DownLoadbuttonClick" 埋点需要上报traceEvent信息
gameEntity.exposureEvent = traceEvent
downloadPb.putObject(gameEntity)
restoreDialogFragment()
}
@ -175,6 +184,7 @@ class DetailViewHolder(
private val mGameEntity: GameEntity = mViewHolder.gameEntity
private var mDownloadEntity: DownloadEntity? = null
private val mPausedText = mViewHolder.context.getString(R.string.paused)
private fun showLandPageAddressDialogIfNeeded() {
if (mGameEntity.isLandPageAddressDialog() && !mGameEntity.isLandPageAddressDialogShowOnly()) {
@ -196,7 +206,11 @@ class DetailViewHolder(
mViewHolder.downloadPb
}
if (downloadButton.buttonStyle !== ButtonStyle.INSTALL_NORMAL && downloadButton.buttonStyle !== ButtonStyle.INSTALL_PLUGIN && downloadButton.buttonStyle !== ButtonStyle.LAUNCH_OR_OPEN && downloadButton.buttonStyle !== ButtonStyle.NONE && downloadButton.buttonStyle !== ButtonStyle.NONE_WITH_HINT) {
if (downloadButton.buttonStyle !== ButtonStyle.INSTALL_NORMAL
&& downloadButton.buttonStyle !== ButtonStyle.INSTALL_PLUGIN
&& downloadButton.buttonStyle !== ButtonStyle.LAUNCH_OR_OPEN
&& downloadButton.buttonStyle !== ButtonStyle.NONE
&& downloadButton.buttonStyle !== ButtonStyle.NONE_WITH_HINT) {
// 畅玩游戏的非真实点击下载按钮下载不需要滚动到特定地方
if (!mAsVGame || VHelper.shouldLaunchGameAfterInstallation()) {
EventBus.getDefault().post(EBScroll(Constants.EB_GAME_DETAIL, mGameEntity.id))
@ -526,11 +540,11 @@ class DetailViewHolder(
mDownloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(mGameEntity)
}
if (mDownloadEntity != null) {
if (downloadButton.text.contains("继续加载")) {
if (downloadButton.text.contains(mPausedText)) {
DownloadManager.getInstance().resume(mDownloadEntity, false)
} else {
DownloadManager.getInstance().pause(mDownloadEntity!!.url)
downloadButton.text = "继续加载 " + mDownloadEntity!!.percent + "%"
downloadButton.text = "${DetailDownloadUtils.getValidProgress(mDownloadEntity)}% $mPausedText"
}
}
}
@ -614,14 +628,18 @@ class DetailViewHolder(
// 由于不想执行上面的 builder 相关的判断,所以这里还是丑陋的修改 downloadEntity 实体并保存到数据库中
downloadEntity.setVGameDownloadModeInDualDownloadMode()
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
PackageInstaller.install(mViewHolder.context, downloadEntity)
runOnUiThread {
PackageInstaller.install(mViewHolder.context, downloadEntity)
}
}
return
} else if (!mAsVGame && downloadEntity.isVGameDownloadInDualDownloadMode()) {
runOnIoThread {
downloadEntity.setLocalDownloadModeInDualDownloadMode()
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
PackageInstaller.install(mViewHolder.context, downloadEntity)
runOnUiThread {
PackageInstaller.install(mViewHolder.context, downloadEntity)
}
}
return
}

View File

@ -1,7 +1,14 @@
package com.gh.gamecenter.adapter.viewholder
import android.graphics.Paint
import android.widget.TextView
import androidx.core.view.marginStart
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.home.custom.model.CustomPageData
class SearchGameFooterViewHolder(val binding: SearchGameFooterBinding) : BaseRecyclerViewHolder<Any>(binding.root)
class PersonalHomeRatingViewHolder(val binding: PersonalHomeRatingBinding) : BaseRecyclerViewHolder<Any>(binding.root)
@ -22,4 +29,62 @@ class CommonCollectionImageTextItemViewHolder(val binding: CommonCollectionImage
BaseRecyclerViewHolder<Any>(binding.root)
class CommonCollectionDetailTwoItemHorizontalViewHolder(val binding: CommonCollectionDetailTwoItemHorizontalCustomBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
BaseRecyclerViewHolder<Any>(binding.root)
class CustomCollectionDetailRecommendCardViewHolder(
val binding: RecyclerRecommendCardCommonContentCollectionDetailCustomBinding
) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bind(item: CustomPageData.RecommendCard) {
ImageUtils.display(binding.ivCover, item.image)
binding.tvTitle.text = item.title
binding.tvLabel.text = item.tag
binding.tvPrice.text = item.highlight.text
binding.tvOriginalPrice.text = if (item.deletion.isShowCurrencySymbol) {
itemView.context.getString(R.string.price_with_symbol, item.deletion.text)
} else {
item.deletion.text
}
binding.tvOriginalPrice.paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
binding.tvCopy.text = item.addedContent
binding.tvPriceSymbol.goneIf(!item.highlight.isShowCurrencySymbol)
binding.root.post {
val views = mutableListOf(
binding.tvPrice,
binding.tvOriginalPrice,
binding.tvCopy,
)
if (item.highlight.isShowCurrencySymbol) {
views.add(0, binding.tvPriceSymbol)
}
binding.tvLabel.goneIf(item.tag.isBlank()) {
views.add(binding.tvLabel)
}
views.forEach {
it.goneIf(false)
}
hideOutOfBoundViewsIfNeed(views)
}
}
/**
* 计算统一排的view能否完整显示在 itemView 内,如果显示不下,则根据优先级依次隐藏优先级较低的
* 数据中的View优先级由高到低排列最后一个优先级最低
*/
private fun hideOutOfBoundViewsIfNeed(views: MutableList<TextView>) {
if (views.isEmpty()) {
return
}
val totalWidth = views.sumOf {
it.width + it.marginStart
}
if (totalWidth > itemView.width) {
views.removeLast().goneIf(true)
hideOutOfBoundViewsIfNeed(views)
}
}
}

View File

@ -234,11 +234,14 @@ class AmwayAdapter(
if (m.find()) {
val contents =
TextHelper.getCommentLabelSpannableStringBuilder(amway.comment.content, R.color.text_theme)
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(contents, copyClickedText = true)
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(
contents,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(context, "安利墙")
)
} else {
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(
amway.comment.content,
copyClickedText = true
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(context, "安利墙")
)
}
@ -333,7 +336,11 @@ class AmwayAdapter(
binding.sdvUserBadge.setOnClickListener {
DialogUtils.showViewBadgeDialog(context, amway.comment.user.badge, object : ConfirmListener {
override fun onConfirm() {
MtaHelper.onEvent("进入徽章墙_用户记录", "安利墙", "${amway.comment.user.name}${amway.comment.user.id}")
MtaHelper.onEvent(
"进入徽章墙_用户记录",
"安利墙",
"${amway.comment.user.name}${amway.comment.user.id}"
)
MtaHelper.onEvent("徽章中心", "进入徽章中心", "安利墙")
DirectUtils.directToBadgeWall(
context,

View File

@ -1,43 +0,0 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.base.DownloadToolbarActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
class CatalogActivity : DownloadToolbarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, CatalogActivity::class.java, CatalogFragment::class.java)
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun isAutoResetViewBackgroundEnabled() = true
companion object {
fun getIntent(context: Context, catalogId: String, catalogTitle: String, entrance: String): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_CATALOG_ID, catalogId)
bundle.putString(EntranceConsts.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
return getTargetIntent(context, CatalogActivity::class.java, CatalogFragment::class.java, bundle)
}
}
}

View File

@ -1,53 +0,0 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.View
import android.view.ViewGroup
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.CatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class CatalogAdapter(
context: Context,
private val mFragment: CatalogFragment,
private val mViewModel: CatalogViewModel,
private val mList: List<CatalogEntity.SubCatalogEntity>
) : BaseRecyclerAdapter<CatalogAdapter.CatalogItemViewHolder>(context) {
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
CatalogItemViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: CatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
catalogName.text = catalogEntity.name
recommendTag.goneIf(!catalogEntity.recommended)
if (catalogEntity.name == mViewModel.selectedCatalogName) {
selectedTag.visibility = View.VISIBLE
catalogName.setTextColor(R.color.text_theme.toColor(mContext))
root.setBackgroundColor(R.color.ui_surface.toColor(mContext))
} else {
selectedTag.visibility = View.GONE
catalogName.setTextColor(R.color.text_primary.toColor(mContext))
root.background = null
}
root.setOnClickListener {
if (catalogEntity.name != mViewModel.selectedCatalogName) {
mViewModel.selectedCatalogName = catalogEntity.name
mViewModel.logSubCatalogClick(position)
mFragment.changeCatalog(position)
notifyDataSetChanged()
}
}
}
}
class CatalogItemViewHolder(val binding: CatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -1,240 +0,0 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.FragmentCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
class CatalogFragment : LazyFragment() {
private var mBinding: FragmentCatalogBinding? = null
private var mViewModel: CatalogViewModel? = null
private var mEntity: CatalogEntity? = null
private var mSpecialCatalogFragment: SpecialCatalogFragment? = null
private var mSubCatalogFragment: SubCatalogFragment? = null
private var mCatalogId: String = ""
private var mCatalogTitle: String = ""
private var mLastSelectedPosition = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedInstanceState?.run {
mLastSelectedPosition = getInt(EntranceConsts.KEY_LAST_SELECTED_POSITION)
}
}
override fun onSaveInstanceState(outState: Bundle) {
mViewModel?.run {
outState.putInt(EntranceConsts.KEY_LAST_SELECTED_POSITION, selectedCatalogPosition)
}
super.onSaveInstanceState(outState)
}
override fun getRealLayoutId() = R.layout.fragment_catalog
override fun onRealLayoutInflated(inflatedView: View) {
mBinding = FragmentCatalogBinding.bind(inflatedView)
}
override fun onFragmentFirstVisible() {
mCatalogId = arguments?.getString(EntranceConsts.KEY_CATALOG_ID) ?: ""
mCatalogTitle = arguments?.getString(EntranceConsts.KEY_CATALOG_TITLE) ?: ""
mViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle), mCatalogId)
mViewModel?.validEntranceName = if (mEntrance.contains("首页")) "首页" else "板块"
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
mViewModel?.validEntranceName = "首页Tab栏"
}
mViewModel?.logAppearance()
super.onFragmentFirstVisible()
}
override fun initRealView() {
super.initRealView()
setNavigationTitle(mCatalogTitle)
mViewModel?.catalogs?.observe(viewLifecycleOwner, Observer {
mBinding?.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
containerCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
if (mEntity!!.hasSpecial) {
val specialEntity = CatalogEntity.SubCatalogEntity(name = "精选")
(mEntity!!.subCatalog as ArrayList).add(0, specialEntity)
}
initView()
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
containerCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseNoConnection.root.visibility = View.GONE
reuseLoading.root.visibility = View.VISIBLE
mViewModel?.getCatalogs()
}
}
}
})
// 嵌入在首页时特殊处理
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
mBinding?.divider?.visibility = View.GONE
mBinding?.root?.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
mBinding?.root?.setPadding(0, 8F.dip2px(), 0, 0)
mBinding?.rvCatalog?.setBackgroundColor(R.color.ui_background.toColor(requireContext()))
}
}
private fun initView() {
mEntity?.run {
mViewModel?.run {
if (subCatalog.isNotEmpty()) {
if (mLastSelectedPosition != -1) {
selectedCatalogPosition = mLastSelectedPosition
selectedCatalogName = subCatalog[mLastSelectedPosition].name
} else {
selectedCatalogPosition = 0
selectedCatalogName = subCatalog[0].name
}
mBinding?.rvCatalog?.layoutManager = FixLinearLayoutManager(requireContext())
mBinding?.rvCatalog?.adapter =
CatalogAdapter(requireContext(), this@CatalogFragment, this, subCatalog)
if (hasSpecial && selectedCatalogPosition == 0) {
mSpecialCatalogFragment =
childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.name) as? SpecialCatalogFragment
?: SpecialCatalogFragment()
mSpecialCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_IS_CATEGORY_V2 to false,
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle,
EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(
EntranceConsts.KEY_EXPOSURE_SOURCE
)
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSpecialCatalogFragment!!,
SpecialCatalogFragment::class.java.name
).commitAllowingStateLoss()
} else {
mSubCatalogFragment =
childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.name) as? SubCatalogFragment
?: SubCatalogFragment()
mSubCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_PRIMARY_CATALOG_ID to subCatalog[selectedCatalogPosition].id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSubCatalogFragment!!,
SubCatalogFragment::class.java.name
).commitAllowingStateLoss()
}
}
}
}
}
fun changeCatalog(position: Int) {
mEntity?.run {
mViewModel?.run {
if (hasSpecial) {
changeCatalogIfHasSpecial(position)
} else {
changeSubCatalogInSubCatalogFragment(position)
}
selectedCatalogPosition = position
}
}
}
private fun changeCatalogIfHasSpecial(position: Int) {
mViewModel?.run {
when {
selectedCatalogPosition == 0 -> changeToSubCatalogFragment(position)
position == 0 -> changeToSpecialCatalogFragment()
else -> changeSubCatalogInSubCatalogFragment(position)
}
}
}
private fun changeToSubCatalogFragment(position: Int) {
mEntity?.run {
mSubCatalogFragment =
childFragmentManager.findFragmentByTag(SubCatalogFragment::class.java.name) as? SubCatalogFragment
?: SubCatalogFragment()
mSubCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSubCatalogFragment!!,
SubCatalogFragment::class.java.name
).commitAllowingStateLoss()
}
}
private fun changeToSpecialCatalogFragment() {
mEntity?.run {
mSpecialCatalogFragment =
childFragmentManager.findFragmentByTag(SpecialCatalogFragment::class.java.name) as? SpecialCatalogFragment
?: SpecialCatalogFragment()
mSpecialCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_IS_CATEGORY_V2 to false,
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle,
EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(
EntranceConsts.KEY_EXPOSURE_SOURCE
)
)
childFragmentManager.beginTransaction().replace(
R.id.container_sub_catalog,
mSpecialCatalogFragment!!,
SpecialCatalogFragment::class.java.name
).commitAllowingStateLoss()
}
}
private fun changeSubCatalogInSubCatalogFragment(position: Int) {
mEntity?.run {
if (mSubCatalogFragment?.isStateSaved == false) {
mSubCatalogFragment?.arguments = bundleOf(
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_PRIMARY_CATALOG_ID to subCatalog[position].id,
EntranceConsts.KEY_CATALOG_TITLE to mCatalogTitle
)
}
mSubCatalogFragment?.changeSubCatalog(subCatalog[position].id)
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mBinding?.rvCatalog?.adapter?.run {
notifyItemRangeChanged(0, itemCount)
}
}
}

View File

@ -1,72 +0,0 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.LogUtils
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class CatalogViewModel(application: Application, val catalogId: String, val catalogTitle: String) :
AndroidViewModel(application) {
private val api = RetrofitManager.getInstance().api
var catalogs = MutableLiveData<CatalogEntity>()
var selectedCatalogName: String = ""
var selectedCatalogPosition: Int = 0
var validEntranceName: String = ""
init {
getCatalogs()
}
@SuppressLint("CheckResult")
fun getCatalogs() {
api.getCatalogs(catalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
fun logAppearance() {
LogUtils.logNewCatalogAppearanceEvent(validEntranceName, catalogTitle)
}
fun logSubCatalogClick(position: Int) {
LogUtils.logSubCatalogClickEvent(validEntranceName, "${catalogTitle}_${selectedCatalogName}", position)
}
fun logSubCatalogContentClick(itemName: String, listPosition: Int) {
LogUtils.logSubCatalogContentClickEvent(
validEntranceName,
"${catalogTitle}_${selectedCatalogName}_${itemName}",
selectedCatalogPosition,
listPosition
)
}
class Factory(private val catalogId: String, private val catalogTitle: String) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CatalogViewModel(HaloApp.getInstance().application, catalogId, catalogTitle) as T
}
}
}

View File

@ -1,56 +0,0 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.base.DownloadToolbarActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.entity.CatalogEntity
class NewCatalogListActivity : DownloadToolbarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun isAutoResetViewBackgroundEnabled() = true
companion object {
fun getIntent(
context: Context,
primaryCatalogId: String, // 一级分类 id
primaryCatalogName: String, // 一级分类名
catalogTitle: String,
catalog: CatalogEntity,
initTitle: String
): Intent {
val bundle = Bundle()
bundle.putParcelable(EntranceConsts.KEY_DATA, catalog)
bundle.putString(EntranceConsts.KEY_PRIMARY_CATALOG_ID, primaryCatalogId)
bundle.putString(EntranceConsts.KEY_PRIMARY_CATALOG_NAME, primaryCatalogName)
bundle.putString(EntranceConsts.KEY_NAME, catalog.name)
bundle.putString(EntranceConsts.KEY_CATALOG_TITLE, catalogTitle)
bundle.putString(EntranceConsts.KEY_CATALOG_INIT_TITLE, initTitle)
return getTargetIntent(
context,
NewCatalogListActivity::class.java,
NewCatalogListFragment::class.java,
bundle
)
}
}
}

View File

@ -1,192 +0,0 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.util.SparseArray
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DownloadItemUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.lightgame.download.DownloadEntity
class NewCatalogListAdapter(
context: Context,
private val mBaseExposureSource: ExposureSource,
private val mViewModel: NewCatalogListViewModel,
private val mEntrance: String?
) : ListAdapter<GameEntity>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
val positionAndPackageMap = HashMap<String, Int>()
override fun setListData(updateData: MutableList<GameEntity>?) {
// 记录游戏位置
if (updateData != null) {
for (i in 0 until updateData.size) {
val gameEntity = updateData[i]
var packages = gameEntity.id
for (apkEntity in gameEntity.getApk()) {
packages += apkEntity.packageName
}
positionAndPackageMap[packages + i] = i
}
}
super.setListData(updateData)
}
fun clearPositionAndPackageMap() {
positionAndPackageMap.clear()
}
override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
return oldItem?.id == newItem?.id
}
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) {
return ItemViewType.ITEM_FOOTER
}
return ItemViewType.GAME_NORMAL
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.GAME_NORMAL -> {
GameItemViewHolder(parent.toBinding())
}
else -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
}
}
override fun getItemCount(): Int {
return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameItemViewHolder) {
val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px()
holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px())
val gameEntity = mEntityList[position]
holder.bindGameItem(gameEntity)
holder.initServerType(gameEntity)
val sortType = mViewModel.sortType.value
val sortSize = mViewModel.sortSize.text
val toolbarTitle = mViewModel.title
val selectedCatalogName = mViewModel.selectedCatalog.name
val exposureSources = ArrayList<ExposureSource>()
exposureSources.add(mBaseExposureSource)
exposureSources.add(ExposureSource(toolbarTitle))
exposureSources.add(ExposureSource("二级分类详情", "$selectedCatalogName+$sortType+$sortSize"))
val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
mExposureEventSparseArray.put(position, event)
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
StringUtils.buildString(
mEntrance,
"+(",
toolbarTitle,
":列表[",
selectedCatalogName,
"=",
sortType,
"=",
(position + 1).toString(),
"])"
),
traceEvent = event
)
}
DownloadItemUtils.setOnClickListener(
mContext,
holder.binding.downloadBtn,
gameEntity,
position,
this,
StringUtils.buildString(
StringUtils.buildString(
mEntrance,
"+(",
toolbarTitle,
":列表[",
selectedCatalogName,
"=",
sortType,
"=",
(position + 1).toString(),
"])"
)
),
location = StringUtils.buildString(selectedCatalogName, ":", gameEntity.name),
traceEvent = event
)
DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), "star&brief")
} else if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
}
}
fun notifyItemByDownload(download: DownloadEntity) {
for (key in positionAndPackageMap.keys) {
// sentry上报download.packageName可能为空
if (download.packageName != null
&& download.gameId != null
&& key.contains(download.packageName)
&& key.contains(download.gameId)
) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap()[download.platform] = download
notifyItemChanged(position)
}
}
}
}
fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
for (key in positionAndPackageMap.keys) {
if (key.contains(status.packageName) && key.contains(status.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap().remove(status.platform)
notifyItemChanged(position)
}
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return mExposureEventSparseArray.get(pos)
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}

View File

@ -1,209 +0,0 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import com.ethanhua.skeleton.Skeleton
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DialogUtils
import com.gh.common.view.CatalogFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.FragmentCatalogListBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class NewCatalogListFragment : ListFragment<GameEntity, NewCatalogListViewModel>() {
private var mPrimaryCatalogName: String = "" // 一级分类名
private var mPrimaryCatalogId: String = "" // 一级分类 id
private var mPrimeCatalog: CatalogEntity? = null
private var mSubCatalogList = arrayListOf<CatalogEntity.SubCatalogEntity>()
private var mInitCatalogName = ""
private var mAdapter: NewCatalogListAdapter? = null
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
showUnzipFailureDialog(downloadEntity)
}
}
override fun onDataInit(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
}
}
private var mBinding: FragmentCatalogListBinding? = null
private lateinit var mExposureListener: ExposureListener
private lateinit var mViewModel: NewCatalogListViewModel
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentCatalogListBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun provideListViewModel() = viewModelProvider<NewCatalogListViewModel>()
override fun provideListAdapter() = mAdapter
?: NewCatalogListAdapter(
requireContext(),
ExposureSource(mPrimaryCatalogName),
mViewModel,
mEntrance
).apply { mAdapter = this }
override fun getItemDecoration() = null
override fun onCreate(savedInstanceState: Bundle?) {
mViewModel = provideListViewModel()
mViewModel.title = arguments?.getString(EntranceConsts.KEY_NAME) ?: ""
mViewModel.categoryTitle = arguments?.getString(EntranceConsts.KEY_CATALOG_TITLE) ?: ""
mEntrance = arguments?.getString(EntranceConsts.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN
mPrimeCatalog = arguments?.getParcelable(EntranceConsts.KEY_DATA)
mSubCatalogList = mPrimeCatalog?.subCatalog as? ArrayList<CatalogEntity.SubCatalogEntity> ?: arrayListOf()
mInitCatalogName = arguments?.getString(EntranceConsts.KEY_CATALOG_INIT_TITLE) ?: ""
mPrimaryCatalogName = arguments?.getString(EntranceConsts.KEY_PRIMARY_CATALOG_NAME) ?: ""
mPrimaryCatalogId = arguments?.getString(EntranceConsts.KEY_PRIMARY_CATALOG_ID) ?: ""
mViewModel.selectedCatalog = mSubCatalogList.find { entity -> entity.name == mInitCatalogName }
?: CatalogEntity.SubCatalogEntity()
mViewModel.primaryCatalogId = mPrimaryCatalogId
initSortType()
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mViewModel.title)
initFilterView()
mViewModel.refresh.observeNonNull(this) { onRefresh() }
mExposureListener = ExposureListener(this, mAdapter!!)
mListRv.addOnScrollListener(mExposureListener)
mSkeletonScreen = Skeleton.bind(mBinding?.listSkeleton)
.shimmer(true)
.angle(Constants.SHIMMER_ANGLE)
.color(R.color.ui_skeleton_highlight)
.duration(Constants.SHIMMER_DURATION)
.maskWidth(Constants.MASK_WIDTH)
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
.load(R.layout.fragment_tags_skeleton)
.show()
}
private fun initSortType() {
mPrimeCatalog?.switch?.run {
if (hotSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RECOMMENDED
return@run
}
if (newSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.NEWEST
return@run
}
if (starSort == "on") {
mViewModel.sortType = CatalogFilterView.SortType.RATING
return@run
}
}
}
private fun initFilterView() {
mBinding?.filterContainer?.run {
visibility = View.VISIBLE
setTypeList(mPrimeCatalog?.switch ?: CatalogEntity.CatalogSwitch())
setCatalogList(mSubCatalogList, mInitCatalogName)
setOnConfigSetupListener(object : CatalogFilterView.OnCatalogFilterSetupListener {
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
mViewModel.updateSortConfig(sortSize = sortSize)
}
override fun onSetupSortType(sortType: CatalogFilterView.SortType) {
mViewModel.updateSortConfig(sortType = sortType)
}
override fun onSetupSortCatalog(sortCatalog: CatalogEntity.SubCatalogEntity) {
mViewModel.updateSortConfig(sortCatalog = sortCatalog)
}
})
}
}
override fun onResume() {
super.onResume()
DownloadManager.getInstance().addObserver(mDataWatcher)
}
override fun onPause() {
super.onPause()
DownloadManager.getInstance().removeObserver(mDataWatcher)
}
override fun onRefresh() {
mAdapter?.clearPositionAndPackageMap()
super.onRefresh()
}
// 下载被删除事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus) {
if ("delete" == status.status) {
mAdapter?.notifyItemAndRemoveDownload(status)
}
}
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}
fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
val data = mAdapter?.positionAndPackageMap ?: return
for (gameAndPosition in data) {
if (gameAndPosition.key.contains(downloadEntity.packageName)) {
val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
if (targetView != null) {
DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
return
}
}
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mBinding?.filterContainer?.run {
setRootBackgroundColor(R.color.ui_surface.toColor(requireContext()))
setItemTextColor(R.color.text_secondary.toColor(requireContext()))
updatePopupWindow()
}
}
}

View File

@ -1,98 +0,0 @@
package com.gh.gamecenter.catalog
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.common.exposure.ExposureUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.common.view.CatalogFilterView
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class NewCatalogListViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {
var title = "" // 显示在 Toolbar 的标题
var categoryTitle = "" // 跳转进来的分类的标题
val refresh = MutableLiveData<Boolean>()
var selectedCatalog = CatalogEntity.SubCatalogEntity()
var sortType = CatalogFilterView.SortType.RECOMMENDED
var sortSize = SubjectSettingEntity.Size()
var primaryCatalogId = "" // 一级分类 id
private val sensitiveApi = RetrofitManager.getInstance().api
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? = null
override fun provideDataSingle(page: Int): Single<List<GameEntity>> {
return if (selectedCatalog.link.type == "column") { // column(专题)/tag(标签)
sensitiveApi.getColumn(selectedCatalog.link.link, getSortType(), getSortSize(), page) // 专题
} else {
sensitiveApi.getGamesWithSpecificTag(getSortSize(), getSortType(), page) // 标签
}
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
it.forEach { game -> game.hideSizeInsideDes = true }
ExposureUtils.updateExposureInfo(
gameList = it,
containerId = primaryCatalogId,
containerType = ExposureEntity.CATEGORY_ID
)
mResultLiveData.postValue(it)
}
}
fun updateSortConfig(
sortSize: SubjectSettingEntity.Size? = null,
sortType: CatalogFilterView.SortType? = null,
sortCatalog: CatalogEntity.SubCatalogEntity? = null
) {
when {
sortSize != null && sortSize != this.sortSize -> {
this.sortSize = sortSize
refresh.postValue(true)
}
sortType != null && sortType != this.sortType -> {
this.sortType = sortType
refresh.postValue(true)
}
sortCatalog != null && sortCatalog != selectedCatalog -> {
selectedCatalog = sortCatalog
refresh.postValue(true)
}
}
}
private fun getSortSize(): String? {
return if (selectedCatalog.link.type == "column") {
UrlFilterUtils.getFilterQuery(
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString()
)
} else {
UrlFilterUtils.getFilterQuery(
"tag_id", selectedCatalog.link.link,
"min_size", sortSize.min.toString(),
"max_size", sortSize.max.toString()
)
}
}
private fun getSortType(): String? {
return when (sortType) {
CatalogFilterView.SortType.RECOMMENDED -> if (selectedCatalog.link.type == "column") "position:1" else "download:-1"
CatalogFilterView.SortType.NEWEST -> "publish:-1"
CatalogFilterView.SortType.RATING -> "star:-1"
}
}
}

View File

@ -1,54 +0,0 @@
package com.gh.gamecenter.catalog
import android.content.Context
import android.view.ViewGroup
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.SubCatalogItemBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class SubCatalogAdapter(
context: Context,
private val mCatalogViewModel: CatalogViewModel,
private val mPrimaryCatalog: CatalogEntity,
private var mList: List<CatalogEntity.SubCatalogEntity>
) : BaseRecyclerAdapter<SubCatalogAdapter.SubCatalogItemViewHolder>(context) {
private val mTypes = listOf("专题", "标签")
override fun getItemCount() = mList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
SubCatalogItemViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: SubCatalogItemViewHolder, position: Int) {
holder.binding.run {
val catalogEntity = mList[position]
ImageUtils.display(catalogIcon, catalogEntity.icon)
catalogName.text = catalogEntity.name
catalogName.setTextColor(R.color.text_primary.toColor(mContext))
recommendTag.goneIf(!catalogEntity.recommended)
root.setOnClickListener {
mCatalogViewModel.logSubCatalogContentClick(catalogEntity.name, position)
if (mTypes.contains(catalogEntity.type)) {
root.context.startActivity(
NewCatalogListActivity.getIntent(
mContext,
mCatalogViewModel.catalogId,
mCatalogViewModel.catalogTitle,
catalogEntity.name,
mPrimaryCatalog,
catalogEntity.name
)
)
} else {
DialogHelper.showUpgradeDialog(mContext)
}
}
}
}
class SubCatalogItemViewHolder(val binding: SubCatalogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -1,94 +0,0 @@
package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.databinding.FragmentSubCatalogBinding
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
class SubCatalogFragment : ToolbarFragment() {
private var mBinding: FragmentSubCatalogBinding? = null
private var mViewModel: SubCatalogViewModel? = null
private var mCatalogViewModel: CatalogViewModel? = null
private var mEntity: CatalogEntity? = null
private var mCatalogId: String = ""
private var mCatalogTitle: String = ""
private var mPrimaryCatalogId: String = ""
override fun getLayoutId() = 0
override fun getInflatedLayout() = FragmentSubCatalogBinding.inflate(layoutInflater).apply { mBinding = this }.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCatalogId = arguments?.getString(EntranceConsts.KEY_CATALOG_ID) ?: ""
mCatalogTitle = arguments?.getString(EntranceConsts.KEY_CATALOG_TITLE) ?: ""
mPrimaryCatalogId = arguments?.getString(EntranceConsts.KEY_PRIMARY_CATALOG_ID) ?: ""
mViewModel = viewModelProvider(SubCatalogViewModel.Factory(mCatalogId))
mCatalogViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle), mCatalogId)
mViewModel?.getSubCatalogs(mPrimaryCatalogId)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel?.catalogs?.observe(viewLifecycleOwner, Observer {
mBinding?.run {
reuseLoading.root.visibility = View.GONE
if (it != null) {
reuseNoConnection.root.visibility = View.GONE
if (it.subCatalog.isNotEmpty()) {
rvSubCatalog.visibility = View.VISIBLE
reuseNoneData.root.visibility = View.GONE
mEntity = it
initView()
} else {
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.VISIBLE
}
} else {
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.VISIBLE
reuseNoConnection.root.setOnClickListener {
reuseLoading.root.visibility = View.VISIBLE
mViewModel?.getSubCatalogs(mPrimaryCatalogId)
}
}
}
})
}
private fun initView() {
mEntity?.takeIf { mCatalogViewModel != null }?.run {
mBinding?.rvSubCatalog?.layoutManager = GridLayoutManager(requireContext(), 3)
mBinding?.rvSubCatalog?.adapter = SubCatalogAdapter(requireContext(), mCatalogViewModel!!, this, subCatalog)
}
}
fun changeSubCatalog(primaryCatalogId: String) {
mBinding?.run {
mPrimaryCatalogId = primaryCatalogId
rvSubCatalog.visibility = View.GONE
reuseNoneData.root.visibility = View.GONE
reuseNoConnection.root.visibility = View.GONE
reuseLoading.root.visibility = View.VISIBLE
mViewModel?.getSubCatalogs(mPrimaryCatalogId)
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mBinding?.rvSubCatalog?.adapter?.run {
mBinding?.rvSubCatalog?.recycledViewPool?.clear()
notifyItemRangeChanged(0, itemCount)
}
}
}

View File

@ -1,44 +0,0 @@
package com.gh.gamecenter.catalog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.entity.CatalogEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class SubCatalogViewModel(application: Application, private val catalogId: String) : AndroidViewModel(application) {
private val api = RetrofitManager.getInstance().api
var catalogs = MutableLiveData<CatalogEntity>()
@SuppressLint("CheckResult")
fun getSubCatalogs(primaryCatalogId: String) {
api.getSubCatalogs(catalogId, primaryCatalogId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<CatalogEntity>() {
override fun onSuccess(data: CatalogEntity) {
catalogs.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
catalogs.postValue(null)
}
})
}
class Factory(private val catalogId: String) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SubCatalogViewModel(HaloApp.getInstance().application, catalogId) as T
}
}
}

View File

@ -1,51 +0,0 @@
package com.gh.gamecenter.category
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.base.DownloadToolbarActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
class CategoryDirectoryActivity : DownloadToolbarActivity() {
companion object {
fun getIntent(context: Context, categoryId: String, categoryTitle: String): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_CATEGORY_ID, categoryId)
bundle.putString(EntranceConsts.KEY_CATEGORY_TITLE, categoryTitle)
return getTargetIntent(
context,
CategoryDirectoryActivity::class.java,
CategoryDirectoryFragment::class.java,
bundle
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun getActivityNameInChinese(): String {
return "游戏分类"
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, CategoryDirectoryActivity::class.java, CategoryDirectoryFragment::class.java)
}
override fun isAutoResetViewBackgroundEnabled() = true
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
}

View File

@ -1,157 +0,0 @@
package com.gh.gamecenter.category
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.view.SubCategoryView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.category.CategoryListActivity.Companion.getIntent
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ItemCategoryBinding
import com.gh.gamecenter.entity.CategoryEntity
import net.cachapa.expandablelayout.ExpandableLayout
class CategoryDirectoryAdapter(context: Context, var categoryTitle: String) : ListAdapter<CategoryEntity>(context) {
var recyclerView: RecyclerView? = null
var expandStatusMap: HashMap<Int, Boolean> = HashMap()
private var sixteenDp: Int = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (sixteenDp == 0) sixteenDp = DisplayUtils.dip2px(parent.context, 16f)
return CategoryViewHolder(parent.toBinding())
}
override fun getItemCount(): Int {
return mEntityList.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CategoryViewHolder -> {
val category = mEntityList[position]
holder.binding.run {
divider.setBackgroundColor(R.color.ui_background.toColor(mContext))
containerPrimaryCategory.setOnClickListener {
root.context.startActivity(getIntent(root.context, categoryTitle, category, "全部"))
}
ImageUtils.display(iconIv, category.icon)
categoryName.text = category.name
}
holder.bindCategory(
category = mEntityList[position],
expandableStatusMap = expandStatusMap,
isExpended = expandStatusMap[position] != null && expandStatusMap[position] == true,
marginTop = sixteenDp,
categoryTitle = categoryTitle,
expandedAction = { recyclerView?.smoothScrollToPosition(position) })
}
}
}
internal class CategoryViewHolder(var binding: ItemCategoryBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindCategory(
category: CategoryEntity,
expandableStatusMap: HashMap<Int, Boolean>,
isExpended: Boolean,
marginTop: Int,
categoryTitle: String,
expandedAction: () -> Unit
) {
category.data?.let {
var subCategoryView: SubCategoryView? = null
binding.containerUnexpandable.removeAllViews()
val unexpandableSize = if (it.size > 6) 6 else it.size
val unexpandableCategoryList = it.subList(0, unexpandableSize)
unexpandableCategoryList.forEachIndexed { index, c ->
when (index % 3) {
0 -> {
val params = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
if (subCategoryView != null) params.setMargins(0, marginTop, 0, 0)
subCategoryView = SubCategoryView(binding.root.context)
subCategoryView?.categoryTitle = categoryTitle
subCategoryView?.primeCategory = category
subCategoryView?.layoutParams = params
binding.containerUnexpandable.addView(subCategoryView)
subCategoryView?.setLeftCategory(c)
}
1 -> subCategoryView?.setCenterCategory(c)
2 -> subCategoryView?.setRightCategory(c)
}
}
if (it.size >= 7) {
val extraCategoryList = it.subList(6, it.size)
binding.ivToggle.visibility = View.VISIBLE
binding.ivToggle.setOnClickListener { binding.containerExpandable.toggle() }
when {
isExpended -> binding.ivToggle.setImageResource(R.drawable.ic_category_arrow_up)
else -> binding.ivToggle.setImageResource(R.drawable.ic_category_arrow_down)
}
val subCategoryViewLinearLayout = LinearLayout(binding.root.context)
subCategoryViewLinearLayout.orientation = LinearLayout.VERTICAL
subCategoryView = SubCategoryView(binding.root.context)
binding.containerExpandable.removeAllViews()
binding.containerExpandable.addView(subCategoryViewLinearLayout)
binding.containerExpandable.setExpanded(isExpended, false)
binding.containerExpandable.setOnExpansionUpdateListener { _, state ->
when (state) {
ExpandableLayout.State.COLLAPSED -> {
binding.ivToggle.setImageResource(R.drawable.ic_category_arrow_down)
expandableStatusMap[adapterPosition] = false
}
ExpandableLayout.State.EXPANDED -> {
binding.ivToggle.setImageResource(R.drawable.ic_category_arrow_up)
expandableStatusMap[adapterPosition] = true
expandedAction.invoke()
}
}
}
extraCategoryList.forEachIndexed { index, c ->
when (index % 3) {
0 -> {
subCategoryView = SubCategoryView(binding.root.context)
val params = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
params.setMargins(0, marginTop, 0, 0)
subCategoryView?.categoryTitle = categoryTitle
subCategoryView?.primeCategory = category
subCategoryView?.layoutParams = params
subCategoryViewLinearLayout.addView(subCategoryView)
subCategoryView?.setLeftCategory(c)
}
1 -> subCategoryView?.setCenterCategory(c)
2 -> subCategoryView?.setRightCategory(c)
}
}
} else {
binding.ivToggle.visibility = View.GONE
binding.containerExpandable.removeAllViews()
}
}
}
}
}

View File

@ -1,104 +0,0 @@
package com.gh.gamecenter.category
import android.graphics.Color
import android.view.View
import androidx.lifecycle.ViewModelProviders
import com.ethanhua.skeleton.Skeleton
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.databinding.FragmentListBaseSkeletonBinding
import com.gh.gamecenter.entity.CategoryEntity
class CategoryDirectoryFragment : LazyListFragment<CategoryEntity, CategoryDirectoryListViewModel>() {
private lateinit var mViewModel: CategoryDirectoryListViewModel
private lateinit var mAdapter: CategoryDirectoryAdapter
private var mBinding: FragmentListBaseSkeletonBinding? = null
override fun getRealLayoutId() = R.layout.fragment_list_base_skeleton
override fun onRealLayoutInflated(inflatedView: View) {
super.onRealLayoutInflated(inflatedView)
mBinding = FragmentListBaseSkeletonBinding.bind(inflatedView)
}
override fun onFragmentFirstVisible() {
mViewModel = ViewModelProviders.of(this).get(CategoryDirectoryListViewModel::class.java)
mViewModel.categoryId = arguments?.getString(EntranceConsts.KEY_CATEGORY_ID) ?: ""
mAdapter =
CategoryDirectoryAdapter(requireContext(), arguments?.getString(EntranceConsts.KEY_CATEGORY_TITLE) ?: "")
super.onFragmentFirstVisible()
}
override fun initRealView() {
super.initRealView()
setNavigationTitle(arguments?.getString(EntranceConsts.KEY_CATEGORY_TITLE))
mSkeletonScreen = Skeleton.bind(mBinding?.listSkeleton)
.shimmer(true)
.angle(Constants.SHIMMER_ANGLE)
.color(R.color.ui_skeleton_highlight)
.duration(Constants.SHIMMER_DURATION)
.maskWidth(Constants.MASK_WIDTH)
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
.load(R.layout.fragment_category_skeleton)
.show()
onLoadRefresh()
if (arguments?.getBoolean(EntranceConsts.KEY_IS_HOME) == true) {
mListRv?.setPadding(
0,
context?.resources?.getDimension(R.dimen.home_recyclerview_padding_top)?.toInt() ?: 0,
0,
0
)
mListRv?.clipToPadding = false
}
mListRv?.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
mAdapter.recyclerView = mListRv
mListRefresh?.isEnabled = false
}
override fun isAutomaticLoad() = false
override fun provideListAdapter() = mAdapter
override fun provideListViewModel() = mViewModel
override fun getItemDecoration() = VerticalItemDecoration(context, 0F, false)
override fun onLoadRefresh() {
mCachedView?.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
super.onLoadRefresh()
}
override fun onLoadDone() {
mCachedView?.setBackgroundColor(Color.TRANSPARENT)
super.onLoadDone()
}
override fun onLoadEmpty() {
mCachedView?.setBackgroundColor(Color.TRANSPARENT)
super.onLoadEmpty()
}
override fun onLoadError() {
mCachedView?.setBackgroundColor(Color.TRANSPARENT)
super.onLoadError()
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mListRv?.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
mListRv?.adapter?.run {
mListRv?.recycledViewPool?.clear()
notifyItemRangeChanged(0, itemCount)
}
}
}

View File

@ -1,21 +0,0 @@
package com.gh.gamecenter.category
import android.app.Application
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.entity.CategoryEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
class CategoryDirectoryListViewModel(application: Application) :
ListViewModel<CategoryEntity, CategoryEntity>(application) {
var categoryId = ""
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData, mResultLiveData::postValue)
}
override fun provideDataObservable(page: Int): Observable<MutableList<CategoryEntity>> {
return RetrofitManager.getInstance().api.getCategories(categoryId, page)
}
}

View File

@ -1,53 +0,0 @@
package com.gh.gamecenter.category
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.base.DownloadToolbarActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.entity.CategoryEntity
class CategoryListActivity : DownloadToolbarActivity() {
companion object {
fun getIntent(context: Context, categoryTitle: String, category: CategoryEntity, initTitle: String): Intent {
val bundle = Bundle()
if (category.data!!.isEmpty() || category.data!![0].name != "全部") {
val plainCategory = CategoryEntity(id = category.id, name = "全部")
((category.data) as ArrayList).add(0, plainCategory)
}
bundle.putParcelable(EntranceConsts.KEY_DATA, category)
bundle.putString(EntranceConsts.KEY_NAME, category.name)
bundle.putString(EntranceConsts.KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(EntranceConsts.KEY_CATEGORY_INIT_TITLE, initTitle)
return getTargetIntent(
context,
CategoryListActivity::class.java,
NewCategoryListFragment::class.java,
bundle
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun showDownloadMenu(): Boolean {
return true
}
override fun getActivityNameInChinese(): String {
return "游戏分类详情"
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
}

View File

@ -1,51 +0,0 @@
package com.gh.gamecenter.category
import android.content.Context
import android.view.ViewGroup
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toDrawable
import com.gh.gamecenter.databinding.ItemTagBinding
import com.gh.gamecenter.entity.CategoryEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class NewCategoryHorizontalAdapter(
context: Context,
private val mViewModel: NewCategoryListViewModel,
private val mCategoryList: List<CategoryEntity>,
private val mSmoothScrollAction: (position: Int) -> Unit
) : BaseRecyclerAdapter<TagsViewHolder>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TagsViewHolder {
return TagsViewHolder(parent.toBinding())
}
override fun onBindViewHolder(holder: TagsViewHolder, position: Int) {
val categoryEntity = mCategoryList[position]
if (mViewModel.selectedCategory.name == categoryEntity.name) {
holder.binding.tagTv.background = R.drawable.bg_tag_text.toDrawable()
holder.binding.tagTv.setTextColor(R.color.text_white.toColor(mContext))
} else {
holder.binding.tagTv.background = null
holder.binding.tagTv.setTextColor(R.color.text_757575.toColor(mContext))
}
holder.binding.tagTv.text = categoryEntity.name
holder.binding.tagTv.setOnClickListener {
mViewModel.changeSelectedCategory(categoryEntity)
notifyDataSetChanged()
mSmoothScrollAction.invoke(position)
}
}
override fun getItemCount(): Int {
return mCategoryList.size
}
}
class TagsViewHolder(val binding: ItemTagBinding) : BaseRecyclerViewHolder<Any>(binding.root)

View File

@ -1,185 +0,0 @@
package com.gh.gamecenter.category
import android.content.Context
import android.util.SparseArray
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DownloadItemUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.viewholder.FooterViewHolder
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.lightgame.download.DownloadEntity
class NewCategoryListAdapter(
context: Context,
private val mViewModel: NewCategoryListViewModel,
private val mEntrance: String?
) : ListAdapter<GameEntity>(context), IExposable {
private val mExposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
val positionAndPackageMap = HashMap<String, Int>()
override fun setListData(updateData: MutableList<GameEntity>?) {
// 记录游戏位置
if (updateData != null) {
for (i in 0 until updateData.size) {
val gameEntity = updateData[i]
var packages = gameEntity.id
for (apkEntity in gameEntity.getApk()) {
packages += apkEntity.packageName
}
positionAndPackageMap[packages + i] = i
}
}
super.setListData(updateData)
}
fun clearPositionAndPackageMap() {
positionAndPackageMap.clear()
}
override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
return oldItem?.id == newItem?.id
}
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) {
return ItemViewType.ITEM_FOOTER
}
return ItemViewType.GAME_NORMAL
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ItemViewType.GAME_NORMAL -> {
GameItemViewHolder(parent.toBinding())
}
else -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
}
}
override fun getItemCount(): Int {
return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameItemViewHolder) {
val gameEntity = mEntityList[position]
holder.bindGameItem(gameEntity)
holder.initServerType(gameEntity)
val padTop = if (position == 0) 16F.dip2px() else 8F.dip2px()
holder.itemView.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 8F.dip2px())
val sortType = if ("download:-1" == mViewModel.getSortType()) "最热" else "最新"
val toolbarTitle = mViewModel.title
val categoryTitle = mViewModel.categoryTitle
val selectedCategoryName = mViewModel.selectedCategory.name ?: ""
val exposureSources = ArrayList<ExposureSource>()
exposureSources.add(ExposureSource(categoryTitle, selectedCategoryName))
exposureSources.add(ExposureSource("二级分类", "$selectedCategoryName+$sortType"))
val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
mExposureEventSparseArray.put(position, event)
holder.itemView.setOnClickListener {
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
StringUtils.buildString(
mEntrance,
"+(",
toolbarTitle,
":列表[",
selectedCategoryName,
"=",
sortType,
"=",
(position + 1).toString(),
"])"
),
traceEvent = event
)
}
DownloadItemUtils.setOnClickListener(
mContext,
holder.binding.downloadBtn,
gameEntity,
position,
this,
StringUtils.buildString(
StringUtils.buildString(
mEntrance,
"+(",
toolbarTitle,
":列表[",
selectedCategoryName,
"=",
sortType,
"=",
(position + 1).toString(),
"])"
)
),
location = StringUtils.buildString(selectedCategoryName, ":", gameEntity.name),
traceEvent = event
)
DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding))
} else if (holder is FooterViewHolder) {
holder.initItemPadding()
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
}
}
fun notifyItemByDownload(download: DownloadEntity) {
for (key in positionAndPackageMap.keys) {
if (key.contains(download.packageName) && key.contains(download.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap()[download.platform] = download
notifyItemChanged(position)
}
}
}
}
fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
for (key in positionAndPackageMap.keys) {
if (key.contains(status.packageName) && key.contains(status.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size) {
mEntityList[position].getEntryMap().remove(status.platform)
notifyItemChanged(position)
}
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return mExposureEventSparseArray.get(pos)
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? {
return null
}
}

View File

@ -1,198 +0,0 @@
package com.gh.gamecenter.category
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.ethanhua.skeleton.Skeleton
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DialogUtils
import com.gh.common.view.ConfigFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.FragmentTagsBinding
import com.gh.gamecenter.entity.CategoryEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class NewCategoryListFragment : ListFragment<GameEntity, NewCategoryListViewModel>() {
private var mPrimeCategory: CategoryEntity? = null
private var mSubCategoryList = arrayListOf<CategoryEntity>()
private val mBinding by lazy { FragmentTagsBinding.inflate(layoutInflater) }
private var mAdapter: NewCategoryListAdapter? = null
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
showUnzipFailureDialog(downloadEntity)
}
}
override fun onDataInit(downloadEntity: DownloadEntity) {
mAdapter?.notifyItemByDownload(downloadEntity)
}
}
private lateinit var mExposureListener: ExposureListener
private lateinit var mViewModel: NewCategoryListViewModel
override fun onCreate(savedInstanceState: Bundle?) {
mViewModel = provideListViewModel()
mViewModel.title = arguments?.getString(EntranceConsts.KEY_NAME) ?: ""
mViewModel.categoryTitle = arguments?.getString(EntranceConsts.KEY_CATEGORY_TITLE) ?: ""
mEntrance = arguments?.getString(EntranceConsts.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN
mPrimeCategory = arguments?.getParcelable(EntranceConsts.KEY_DATA)
mSubCategoryList = mPrimeCategory?.data as? ArrayList<CategoryEntity> ?: arrayListOf()
val initSelectedCategory = arguments?.getString(EntranceConsts.KEY_CATEGORY_INIT_TITLE)
mViewModel.selectedCategory =
mSubCategoryList.find { categoryEntity -> categoryEntity.name == initSelectedCategory }
?: CategoryEntity()
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setNavigationTitle(mViewModel.title)
mViewModel.refresh.observeNonNull(this) { onRefresh() }
mBinding.configContainer.visibility = View.VISIBLE
mBinding.configContainer.updateAllTextView(mViewModel.sortType)
mBinding.configContainer.setOnConfigSetupListener(object : ConfigFilterView.OnConfigFilterSetupListener {
override fun onShowSortSize() {}
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
mViewModel.updateSortConfig(sortSize = sortSize)
}
override fun onSetupSortType(sortType: ConfigFilterView.SortType) {
mViewModel.updateSortConfig(sortType = sortType)
}
})
mExposureListener = ExposureListener(this, mAdapter!!)
mListRv.addOnScrollListener(mExposureListener)
updateCategoriesView(mSubCategoryList)
mSkeletonScreen =
Skeleton.bind(mBinding.listSkeleton).shimmer(false).load(R.layout.fragment_subject_skeleton).show()
}
override fun onResume() {
super.onResume()
DownloadManager.getInstance().addObserver(mDataWatcher)
}
override fun onPause() {
super.onPause()
DownloadManager.getInstance().removeObserver(mDataWatcher)
}
override fun getItemDecoration() = null
override fun getLayoutId() = 0
override fun getInflatedLayout() = mBinding.root
override fun provideListViewModel(): NewCategoryListViewModel {
return viewModelProvider()
}
override fun provideListAdapter(): ListAdapter<GameEntity> {
return mAdapter
?: NewCategoryListAdapter(requireContext(), mViewModel, mEntrance).apply { mAdapter = this }
}
private fun updateCategoriesView(categoryList: ArrayList<CategoryEntity>) {
mBinding.tagsRecyclerView.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
mBinding.tagsRecyclerView.adapter = NewCategoryHorizontalAdapter(requireContext(), mViewModel, categoryList) {
mBinding.tagsRecyclerView.smoothScrollToPosition(it)
}
// 调整选中标签位置
for (index in 0 until categoryList.size) {
if (categoryList[index].name == mViewModel.selectedCategory.name) {
mBinding.tagsRecyclerView.postDelayed({
tryCatchInRelease { mBinding.tagsRecyclerView.smoothScrollToPosition(index) }
}, 200)
break
}
}
}
override fun onRefresh() {
mAdapter?.clearPositionAndPackageMap()
super.onRefresh()
}
// 下载被删除事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus) {
if ("delete" == status.status) {
mAdapter?.notifyItemAndRemoveDownload(status)
}
}
// 安装/卸载 事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAdapter?.notifyDataSetChanged()
}
}
fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
val data = mAdapter?.positionAndPackageMap ?: return
for (gameAndPosition in data) {
if (gameAndPosition.key.contains(downloadEntity.packageName)) {
val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
if (targetView != null) {
DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
return
}
}
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mBinding.run {
divider.setBackgroundColor(R.color.ui_background.toColor(requireContext()))
tagsRecyclerView.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
tagsRecyclerView.adapter?.run {
notifyItemRangeChanged(0, itemCount)
}
configContainer.run {
container.setBackgroundColor(R.color.ui_surface.toColor(requireContext()))
updateAllTextView(mViewModel.sortType)
updatePopupWindow()
}
}
}
}

View File

@ -1,81 +0,0 @@
package com.gh.gamecenter.category
import android.app.Application
import androidx.lifecycle.MutableLiveData
import com.gh.common.exposure.ExposureUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.common.view.ConfigFilterView
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.entity.CategoryEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class NewCategoryListViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {
var title = "" // 显示在 Toolbar 的标题
var categoryTitle = "" // 跳转进来的分类的标题
val refresh = MutableLiveData<Boolean>()
var selectedCategory = CategoryEntity()
var sortType = ConfigFilterView.SortType.RECOMMENDED
private var mSortSize = SubjectSettingEntity.Size()
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? {
return null
}
override fun provideDataSingle(page: Int): Single<List<GameEntity>> {
return RetrofitManager.getInstance()
.api
.getGamesInCategory(selectedCategory.id, getSortType(), getSortSize(), page)
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
ExposureUtils.updateExposureInfo(it)
mResultLiveData.postValue(it)
}
}
fun changeSelectedCategory(category: CategoryEntity) {
if (selectedCategory != category) {
selectedCategory = category
refresh.postValue(true)
}
}
fun updateSortConfig(
sortSize: SubjectSettingEntity.Size? = null,
sortType: ConfigFilterView.SortType? = null
) {
if (sortSize != null && sortSize != mSortSize) {
mSortSize = sortSize
refresh.postValue(true)
} else if (sortType != null && sortType != this.sortType) {
this.sortType = sortType
refresh.postValue(true)
}
}
private fun getSortSize(): String? {
return UrlFilterUtils.getFilterQuery(
"min_size", mSortSize.min.toString(),
"max_size", mSortSize.max.toString()
)
}
fun getSortType(): String? {
return if (sortType == ConfigFilterView.SortType.RECOMMENDED) {
"download:-1"
} else {
"publish:-1"
}
}
}

View File

@ -63,9 +63,11 @@ class DiscoveryAdapter(
itemData.interestCardLabels != null -> {
ITEM_RECOMMEND_INTEREST
}
itemData.interestImageCardLabel != null -> {
ITEM_RECOMMEND_INTEREST_IMAGE
}
else -> {
ItemViewType.GAME_NORMAL
}
@ -90,18 +92,23 @@ class DiscoveryAdapter(
ItemViewType.GAME_NORMAL -> {
DiscoveryGameViewHolder(parent.toBinding())
}
ItemViewType.ITEM_FOOTER -> {
FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
}
ITEM_DIRECT_GAME_BLOCK -> {
DirectGameBlockViewHolder(parent.toBinding())
}
ITEM_RECOMMEND_INTEREST -> {
RecommendInterestViewHolder(parent.toBinding())
}
ITEM_RECOMMEND_INTEREST_IMAGE -> {
RecommendInterestImageViewHolder(parent.toBinding())
}
else -> {
throw NullPointerException()
}
@ -139,6 +146,12 @@ class DiscoveryAdapter(
mExposureEventSparseArray.put(position, event)
holder.itemView.setOnClickListener {
SensorsBridge.trackGameExploreClick(
"游戏",
"详情页",
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
)
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
@ -159,8 +172,16 @@ class DiscoveryAdapter(
StringUtils.buildString("(${mEntrance}", "-列表[", (position).toString(), "])"),
location = StringUtils.buildString(mEntrance, ":", gameEntity.name),
traceEvent = event
)
) {
SensorsBridge.trackGameExploreClick(
"按钮",
"详情页",
gameId = gameEntity.id,
gameName = gameEntity.name ?: "",
)
}
}
is RecommendInterestViewHolder -> {
holder.binding.root.setBackgroundColor(R.color.ui_surface.toColor(mContext))
holder.binding.backgroundView.background = R.drawable.bg_shape_space_radius_8.toDrawable(mContext)
@ -175,24 +196,42 @@ class DiscoveryAdapter(
labels[index].text = labels[index].linkText
labelTv.text = labels[index].title
labelTv.setOnClickListener {
DirectUtils.directToLinkPage(holder.binding.root.context, labels[index], mEntrance, "")
val link = labels[index]
SensorsBridge.trackGameExploreClick(
"内容标签",
"详情页",
linkType = link.type ?: "",
linkId = link.link ?: "",
linkText = link.text ?: "",
buttonType = link.title ?: ""
)
DirectUtils.directToLinkPage(holder.binding.root.context, link, mEntrance, "")
logDiscoverPageRecommendedInterestCardClick(
mEntityList[position].cardPosition,
labels[index]
link
)
}
}
}
}
is RecommendInterestImageViewHolder -> {
holder.binding.root.setBackgroundColor(R.color.ui_surface.toColor(mContext))
val label = mEntityList[position].interestImageCardLabel ?: return
label.text = label.linkText
holder.binding.root.setOnClickListener {
SensorsBridge.trackGameExploreClick(
"内容标签",
"详情页",
linkType = label.type ?: "",
linkId = label.link ?: "",
linkText = label.text ?: "",
)
DirectUtils.directToLinkPage(holder.binding.root.context, label, mEntrance, "")
logDiscoverPageRecommendedInterestCardClick(mEntityList[position].cardPosition, label)
}
}
is DirectGameBlockViewHolder -> {
holder.binding.run {
val userInterestedGame = Config.getUserInterestedGame()
@ -202,6 +241,10 @@ class DiscoveryAdapter(
interestedGameTv.goneIf(!userInterestedGame) {
interestedGameTv.text = mContext.getString(R.string.interested_game_footer_hint).fromHtml()
interestedGameTv.setOnClickListener {
SensorsBridge.trackGameExploreClick(
"偏好设置",
"详情页",
)
mContext.ifLogin("发现页-底部") {
mFragment.startActivityForResult(
InterestedGameActivity.getIntent(
@ -215,8 +258,23 @@ class DiscoveryAdapter(
}
}
recommendIv.setOnClickListener {
val blockData = HomeBottomBarHelper.getDefaultGameBarData()
mContext.startActivity(BlockActivity.getIntent(mContext, blockData, mBaseExposureSource, mEntrance))
SensorsBridge.trackGameExploreClick(
"内容标签",
"详情页",
linkType = blockData.type ?: "",
linkId = blockData.link ?: "",
linkText = blockData.text ?: ""
)
mContext.startActivity(
BlockActivity.getIntent(
mContext,
blockData,
mBaseExposureSource,
mEntrance
)
)
NewFlatLogUtils.logDiscoverPageJumpGamesLibraries()
}
}

View File

@ -161,6 +161,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
val showOnFailed = downloadManagerAd?.displayRule?.onFailedAction == "show"
if ((showThirdPartyAd && thirdPartyAd != null) || (!showThirdPartyAd && thirdPartyAd != null && ownerAd == null)) {
initThirdPartyAd(thirdPartyAd) { isSuccess ->
if (!isAdded) return@initThirdPartyAd
mBinding.maskView.goneIf(!isSuccess)
if (!isSuccess && ownerAd != null && showOnFailed) {
mSlideInterval = ownerAd.adSource?.sliderInterval ?: -1
@ -193,7 +194,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
}
private fun initOwnerAd(adConfig: AdConfig) {
if (adConfig.id.isEmpty()) return
if (!isAdded || adConfig.id.isEmpty()) return
mAdGameViewModel = viewModelProvider(AdGameViewModel.Factory(adConfig))
initAdGameBanner(adConfig)
mBinding.closeAdIv.setOnClickListener {
@ -227,6 +228,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
adConfig.displayRule.onFailedAction == "show" && adConfig.thirdPartyAd != null) {
// 自有广告游戏为空时,显示第三方广告
initThirdPartyAd(adConfig.thirdPartyAd) { isSuccess ->
if (!isAdded) return@initThirdPartyAd
mBinding.maskView.goneIf(!isSuccess)
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, System.currentTimeMillis())
@ -273,7 +275,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
mDownloadManager.markDownloadedTaskAsRead()
updateDownloadHint()
}
DownloadManager.getInstance().checkAndRetryDownload()
DownloadManager.getInstance().checkAndRetryDownload(false)
if (mBinding.adGameItemContainer.isVisible) {
DownloadManager.getInstance().addObserver(mDataWatcher)
}

View File

@ -19,12 +19,13 @@ data class BottomTab(
@DrawableRes
val iconSelector: Int = 0, // 本地字段
@SerializedName("js_code")
val jsCode: String = "", // js代码
var jsCode: String = "", // js代码
val link: LinkEntity? = null, // 通用链接
@SerializedName("search_style")
val searchStyle: SearchStyle = SearchStyle(), // 搜索样式
@SerializedName("is_default_page")
var default: Boolean = false, // 是否为默认显示页
var guide: Guide? = null, // 引导文案
var isTransparentStyle: Boolean = false // 本地字段透明底部Tab
) : Parcelable {
@Parcelize
@ -43,6 +44,13 @@ data class BottomTab(
}
}
@Parcelize
data class Guide(
var bottomTabId: String = "", // 底部tab id
var multiTabId: String = "", // 多tab导航页id
var text: String = "",
): Parcelable
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

View File

@ -6,40 +6,6 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class CatalogEntity(
@SerializedName("_id")
var id: String = "",
var name: String = "",
var switch: CatalogSwitch = CatalogSwitch(),
@SerializedName("has_special")
var hasSpecial: Boolean = false,
@SerializedName("sub_catalogs")
var subCatalog: List<SubCatalogEntity> = emptyList()
) : Parcelable {
@Parcelize
data class SubCatalogEntity(
@SerializedName("_id")
var id: String = "",
var name: String = "",
var icon: String = "",
var type: String = "",
var link: LinkEntity = LinkEntity(),
var recommended: Boolean = false
) : Parcelable
@Parcelize
data class CatalogSwitch(
@SerializedName("sort_hot")
var hotSort: String = "",
@SerializedName("sort_new")
var newSort: String = "",
@SerializedName("sort_star")
var starSort: String = ""
) : Parcelable
}
@Parcelize
class SpecialCatalogEntity(

View File

@ -1,6 +1,7 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.gamecenter.home.custom.model.CustomPageData
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@ -17,8 +18,14 @@ data class CommonCollectionEntity(
@SerializedName("vertical_line")
val verticalLine: String = "", // 竖排时才有数据,代表竖排行数控制
@SerializedName("common_collection_content")
val collectionList: MutableList<CommonCollectionContentEntity> = mutableListOf()
val collectionList: MutableList<CommonCollectionContentEntity> = mutableListOf(),
@SerializedName("common_collection_recommend_cards")
private val _commonCollectionRecommendCards: List<CustomPageData.RecommendCard>? = null
) {
val commonCollectionRecommendCards: List<CustomPageData.RecommendCard>
get() = _commonCollectionRecommendCards ?: emptyList()
val layoutChinese: String
get() = when (layout) {
0 -> "轮播banner"
@ -30,6 +37,10 @@ data class CommonCollectionEntity(
6 -> "双列竖式卡片"
7 -> "竖式图文列表"
8 -> "横排图文列表"
9 -> "内容标签泳道"
10 -> "通知栏目"
11 -> "公告横幅"
12 -> "推荐卡片"
else -> ""
}
}

View File

@ -1,5 +1,6 @@
package com.gh.gamecenter.entity
import android.graphics.Color
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.feature.entity.Time
import com.google.gson.annotations.SerializedName
@ -22,5 +23,87 @@ data class GameNavigationEntity(
var hintStartTime: Long = 0,
@SerializedName("hint_end_time")
var hintEndTime: Long = 0,
var time: Time? = null
)
var time: Time? = null,
@SerializedName("entry_name_status")
private val _entryNameStatus: String? = null,
@SerializedName("guide")
private val _guide: Guide? = null
) {
val isShowEntryName: Boolean
get() = ENTRY_NAME_STATUS_HIDE != _entryNameStatus
val isShowBubble: Boolean
get() = _guide != null
val guide: Guide
get() = _guide ?: Guide()
data class Guide(
@SerializedName("text")
private val _text: String? = null,
@SerializedName("color")
private val _color: String? = null
) {
val text: String
get() = _text ?: ""
val color: String
get() = _color ?: ""
/**
* 文字颜色 不透明度为 70%
* 十六进制: B2
* 十进制: 178
*/
val textColorInt: Int
get() = parseColorWithAlpha(TEXT_ALPHA, color)
/**
* 边框颜色 不透明度为 10%
* 十六进制: 4D
* 十进制: 77
*/
val borderColorInt: Int
get() = parseColorWithAlpha(BORDER_ALPHA, color)
/**
* 背景颜色 不透明度为 30%
* 十六进制: 1A
* 十进制: 26
*/
val backgroundColorInt: Int
get() = parseColorWithAlpha(BACKGROUND_ALPHA, color)
private fun parseColorWithAlpha(alpha: Int, color: String): Int {
val colorInt = try {
Color.parseColor(color)
} catch (e: IllegalArgumentException) {
// 解析失败,默认使用红色
Color.RED
}
val hsv = FloatArray(3)
Color.colorToHSV(colorInt, hsv)
return Color.HSVToColor(alpha, hsv)
}
companion object {
private const val COLOR_BLUE = "blue"
private const val COLOR_PURPLE = "purple"
private const val COLOR_RED = "red"
private const val COLOR_ORANGE = "orange"
private const val COLOR_YELLOW = "yellow"
private const val COLOR_GREEN = "green"
private const val TEXT_ALPHA = 178
private const val BORDER_ALPHA = 77
private const val BACKGROUND_ALPHA = 26
}
}
companion object {
private const val ENTRY_NAME_STATUS_HIDE = "hide"
}
}

View File

@ -33,9 +33,9 @@ data class HomeItemTestV2Entity(
val rightTop: RightTop = RightTop(),
@SerializedName("start_id")
val startId: String = "",
@SerializedName("start_point")
@SerializedName("recommend_data_point")
private val _startPoint: Map<String, String> = mapOf(), // key 时间轴名称value 当前时间轴第一个游戏id
@SerializedName("data_count")
@SerializedName("recommend_data_count")
private val _dataCount: Map<String, Int> = mapOf(), //key 时间轴名称value 当前时间轴所包含的游戏数量
@SerializedName("time_type")
val timeType: String = "",
@ -51,13 +51,8 @@ data class HomeItemTestV2Entity(
val dataCount: List<DataCount>
get() {
val dataCountList = arrayListOf<DataCount>()
// 需要将 推荐 类型的数据放在第一位
_dataCount.forEach { (key, value) ->
if (timeType == TIME_TYPE_RECOMMEND && key == TIME_TYPE_RECOMMEND) {
dataCountList.add(0, DataCount(key, value))
} else {
dataCountList.add(DataCount(key, value))
}
dataCountList.add(DataCount(key, value))
}
return dataCountList
}
@ -66,18 +61,10 @@ data class HomeItemTestV2Entity(
get() {
val startPointList = arrayListOf<StartPoint>()
_startPoint.forEach { (key, value) ->
if (timeType == TIME_TYPE_RECOMMEND && key == TIME_TYPE_RECOMMEND) {
startPointList.add(0, StartPoint(key, value))
} else {
startPointList.add(StartPoint(key, value))
}
startPointList.add(StartPoint(key, value))
}
return startPointList
}
companion object {
private const val TIME_TYPE_RECOMMEND = "recommend"
}
}
@Keep

View File

@ -20,7 +20,8 @@ data class HomeRecommend(
private val _image: String? = null,
@SerializedName("link_community")
private val community: CommunityEntity? = null,
@SerializedName("guide")
private val _guide: Guide? = null,
// 绑定的曝光实体
var exposureEvent: ExposureEvent? = null,
) {
@ -28,6 +29,12 @@ data class HomeRecommend(
val image: String
get() = _image ?: ""
val isShowGuide: Boolean
get() = _guide != null
val guide: Guide
get() = _guide ?: Guide()
fun transformLinkEntity(): LinkEntity {
return LinkEntity(
name = name,
@ -38,4 +45,12 @@ data class HomeRecommend(
community = community
)
}
data class Guide(
@SerializedName("text")
private val _text: String? = null
) {
val text: String
get() = _text ?: ""
}
}

View File

@ -44,9 +44,12 @@ data class HomeSubSlide(
data class CardData(
var games: List<GameEntity> = arrayListOf(),
@SerializedName("game_total")
val gameTotal: GameTotal = GameTotal(),
private val _gameTotal: GameTotal? = null,
val stamp: String = ""
)
) {
val gameTotal: GameTotal
get() = _gameTotal ?: GameTotal()
}
data class GameTotal(
val vote: Int = 0,

View File

@ -10,8 +10,12 @@ data class MultiTabNav(
val id: String = "",
val title: String = "",
@SerializedName("link_multi_tab_nav")
val linkMultiTabNav: List<LinkMultiTabNav> = ArrayList()
private val _linkMultiTabNav: List<LinkMultiTabNav>?
) {
val linkMultiTabNav:List<LinkMultiTabNav>
get() = _linkMultiTabNav?: emptyList()
data class LinkMultiTabNav(
@SerializedName("_id")
val id: String = "",
@ -22,6 +26,7 @@ data class MultiTabNav(
@SerializedName("is_default_page")
var default: Boolean = false, // 是否为默认显示页
val link: LinkEntity? = null, // 通用链接
var guide: BottomTab.Guide? = null, // 引导文案
// 本地字段
var style: TabStyle = TabStyle(),

View File

@ -21,8 +21,14 @@ class NewApiSettingsEntity(
var install: Install, // 安装相关的
@SerializedName("game_shield_contents")
var gameShieldContents: List<String>? = listOf(),//游戏屏蔽内容
var search: SettingsEntity.Search? = null// 游戏搜索配置
var search: SettingsEntity.Search? = null,// 游戏搜索配置
@SerializedName("jiguang_switch")
private val _jiguangSwitch: Boolean? = null
) {
val jiguangSwitch: Boolean
get() = _jiguangSwitch ?: false
/**
*
* "icon": false, // 是否显示切换true显示
@ -37,7 +43,9 @@ class NewApiSettingsEntity(
class Install(
@SerializedName("guides")
val guides: List<Guide>? = null
val guides: List<Guide>? = null,
@SerializedName("question_tip")
var questionTip: QuestionTip? = null // 厂商安装问题提示
)
/**
@ -82,4 +90,9 @@ class NewApiSettingsEntity(
@SerializedName("REP")
val rep: String
)
class QuestionTip(
@SerializedName("link")
val linkEntity: LinkEntity? = null,
)
}

View File

@ -39,6 +39,8 @@ class ServerTestEntity(
@SerializedName("time_type")
val timeType: String,
@SerializedName("games")
var gameList: ArrayList<GameEntity> = arrayListOf()
var gameList: ArrayList<GameEntity> = arrayListOf(),
@SerializedName("put_away_games")
var collapsedGameList: ArrayList<GameEntity> = arrayListOf(),
)
}

View File

@ -13,7 +13,32 @@ class StartupAdEntity(
val img: String = "",
// 显示规则: none无, each每一次打开, everyday每一天一次, once一次
val rule: String = "",
val time: TimeEntity? = null
val time: TimeEntity? = null,
@SerializedName("type")
private val _type: String? = null,
@SerializedName("video")
private val _video: VideoEntity? = null,
@SerializedName("display_interval")
private val _displayInterval: Int? = null
) {
// 默认为图片
val type: String
get() = _type ?: AD_TYPE_IMG
val isImageType: Boolean
get() = type == AD_TYPE_IMG
val video: VideoEntity
get() = _video ?: VideoEntity()
// 默认时长为 5s
val displayInterval: Int
get() = _displayInterval ?: 5
class TimeEntity(val start: Long = 0, val end: Long = 0)
companion object {
private const val AD_TYPE_IMG = "img"
}
}

View File

@ -19,6 +19,8 @@ class SubjectData(
var briefStyle: String = "",
var subjectType: SubjectType = SubjectType.NORMAL,
var subjectStyle: String = "",
var showDetailSubtitle: Boolean = false,
var showDetailIconSubscript: Boolean = false,
var requireUpdateSetting: Boolean = false, // 多专题页面需要专题页面自行获取专题配置
var isAdData: Boolean = false,

View File

@ -4,6 +4,7 @@ import android.os.Parcelable
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.WelfareInfo
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@ -106,7 +107,15 @@ data class SubjectEntity(
var explain: String = "", // 游戏单合集说明
@SerializedName("show_star")
private val _showStar: Boolean? = null
private val _showStar: Boolean? = null,
@SerializedName("home_text")
val homeText: String? = null,
@SerializedName("show_index_subtitle")
val showIndexSubtitle: Boolean = false,
@SerializedName("show_index_icon_subscript")
val showIndexIconSubscript: Boolean = false,
@SerializedName("welfare_info")
val welfareInfo: WelfareInfo? = null
) : Parcelable {
@IgnoredOnParcel

View File

@ -73,8 +73,6 @@ data class SubjectRecommendEntity(
"column" -> "专题"
"column_collection" -> "专题合集"
"block" -> "版块"
"category" -> "分类"
"catalog" -> "新分类"
"category_v2" -> "新分类2.0"
"column_test" -> "开测表"
"server" -> "开服表"

View File

@ -28,7 +28,18 @@ class SubjectSettingEntity(
var adIconActive: Boolean = false,
@SerializedName("column_style")
var columnStyle: String = "", // 对应自定义页面的专题样式
@SerializedName("show_detail_subtitle")
private val _showDetailSubtitle: Boolean? = null,
@SerializedName("show_detail_icon_subscript")
private val _showDetailIconSubscript: Boolean? = null
) : Parcelable {
val showDetailSubtitle: Boolean
get() = _showDetailSubtitle ?: false
val showDetailIconSubscript: Boolean
get() = _showDetailIconSubscript ?: false
@Parcelize
class TypeEntity(
var content: MutableList<String> = ArrayList(), // top/tile

View File

@ -63,6 +63,7 @@ class FollowHomeSlideListViewHolder(
val slideList = data.linkCommonCollection.slides.slide
slideListUi.bind(slideList, bindingAdapterPosition + 1)
slideListUi.updateWhenTopVisibleItemCountChanged(false)
itemView.setBackgroundColor(R.color.ui_surface.toColor(itemView.context))

View File

@ -74,6 +74,7 @@ class FollowHomeSlideWithCardsViewHolder(
fun bindView(data: FollowCommonContentCollection) {
this.data = data
slideWithCardsUi.bind(data.linkCommonCollection, bindingAdapterPosition + 1)
slideWithCardsUi.updateWhenTopVisibleItemCountChanged(false)
itemView.setBackgroundColor(R.color.ui_surface.toColor(itemView.context))
}

View File

@ -11,8 +11,6 @@ import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import com.gh.gamecenter.R
import com.gh.gamecenter.amway.AmwayFragment
import com.gh.gamecenter.catalog.CatalogFragment
import com.gh.gamecenter.category.CategoryDirectoryFragment
import com.gh.gamecenter.category2.CategoryV2Fragment
import com.gh.gamecenter.common.base.adapter.FragmentAdapter
import com.gh.gamecenter.common.constant.EntranceConsts
@ -159,16 +157,6 @@ abstract class HomeTabWrapperFragment : SearchToolWrapperFragment() {
putString(GameServersTestFragment.TEST_COLUMN_ID, tabEntity.link)
})
"category" -> CategoryDirectoryFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_CATEGORY_ID, tabEntity.link)
putString(EntranceConsts.KEY_CATEGORY_TITLE, tabEntity.text)
})
"catalog" -> CatalogFragment().with(Bundle().apply {
putString(EntranceConsts.KEY_CATALOG_ID, tabEntity.link)
putString(EntranceConsts.KEY_CATALOG_TITLE, tabEntity.text)
})
"category_v2" -> CategoryV2Fragment().with(Bundle().apply {
putString(EntranceConsts.KEY_CATEGORY_ID, tabEntity.link)
putString(EntranceConsts.KEY_CATEGORY_TITLE, tabEntity.text)
@ -224,6 +212,7 @@ abstract class HomeTabWrapperFragment : SearchToolWrapperFragment() {
})
"column_test_v2" -> GameServerTestV2Fragment().with(Bundle().apply {
putString(EntranceConsts.KEY_ID, tabEntity.link)
putString(EntranceConsts.KEY_ENTRANCE, entrance)
putInt(EntranceConsts.KEY_POSITION, index)
putParcelable(

View File

@ -26,7 +26,6 @@ import com.gh.gamecenter.adapter.viewholder.GameHeadViewHolder
import com.gh.gamecenter.adapter.viewholder.GameImageViewHolder
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.adapter.viewholder.GameViewPagerViewHolder
import com.gh.gamecenter.category.CategoryDirectoryActivity
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.callback.OnViewClickListener
import com.gh.gamecenter.common.constant.EntranceConsts
@ -54,6 +53,7 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.game.bigimagerecommend.BigImageRecommendViewHolder
import com.gh.gamecenter.game.columncollection.GameColumnCollectionViewHolder
import com.gh.gamecenter.game.commoncollection.CommonCollection12ViewHolder
@ -90,7 +90,6 @@ import com.gh.gamecenter.home.test_v2.HomeGameTestV2GameListRvAdapter
import com.gh.gamecenter.home.test_v2.HomeGameTestV2ViewModel
import com.gh.gamecenter.home.test_v2.HomeItemGameTestV2ViewHolder
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.minigame.qq.QGameRecentlyPlayViewHolder
import com.gh.gamecenter.servers.gametest2.GameServerTestV2Activity
import com.gh.gamecenter.subject.SubjectActivity
@ -177,6 +176,20 @@ class GameFragmentAdapter(
return ItemViewType.LOADING
}
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is QGameRecentlyPlayViewHolder) {
holder.onAttached()
}
}
override fun onViewDetachedFromWindow(holder: ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is QGameRecentlyPlayViewHolder) {
holder.onDetached()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return when (viewType) {
// 轮播图+导航栏+专题入口
@ -195,7 +208,7 @@ class GameFragmentAdapter(
ItemViewType.GAME_SUBJECT -> GameHorizontalListViewHolder(parent.toBinding())
// 游戏专题-横屏滑动
ItemViewType.GAME_SUBJECT_SLIDE -> GameHorizontalSlideListViewHolder(parent.toBinding())
ItemViewType.QQ_GAME_SUBJECT_SLIDE -> QGameRecentlyPlayViewHolder(parent.toBinding())
ItemViewType.QQ_GAME_SUBJECT_SLIDE -> QGameRecentlyPlayViewHolder(mLifecycleOwner, parent.toBinding())
// 正常游戏
ItemViewType.GAME_NORMAL -> GameItemViewHolder(parent.toBinding())
// 游戏专题-大图-显示/只显示
@ -966,14 +979,6 @@ class GameFragmentAdapter(
)
)
"category" -> mContext.startActivity(
CategoryDirectoryActivity.getIntent(
mContext,
entity.link!!,
entity.text!!
)
)
"column" -> {
SubjectActivity.startSubjectActivity(
mContext,
@ -1515,7 +1520,7 @@ class GameFragmentAdapter(
if (text == "全部") {
NewFlatLogUtils.logGameTestV2MoreClick(text, location)
//点击进入[新游开测]详情页面
mContext.startActivity(GameServerTestV2Activity.getIntent(mContext, "新游开测"))
mContext.startActivity(GameServerTestV2Activity.getIntent(mContext, "none", "新游开测"))
} else {
//点击跳转通用链接
if (link != null) {

View File

@ -2,8 +2,8 @@ package com.gh.gamecenter.game.columncollection.detail
import android.content.Intent
import android.os.Bundle
import com.gh.gamecenter.common.base.activity.ToolBarActivity
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
@ -34,8 +34,8 @@ class ColumnCollectionDetailActivity : ToolBarActivity() {
}
override fun getBusinessId(): Pair<String, String> {
val fragment = targetFragment as ColumnCollectionDetailFragment
return if (fragment.arguments != null) {
val fragment = targetFragment as? ColumnCollectionDetailFragment?
return if (fragment?.arguments != null) {
Pair(fragment.requireArguments().getString(EntranceConsts.KEY_COLLECTION_ID) ?: "", "")
} else {
super.getBusinessId()

View File

@ -14,6 +14,11 @@ import com.gh.gamecenter.common.utils.updateStatusBarColor
*/
class CommonCollectionDetailActivity : ToolBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
@ -31,8 +36,8 @@ class CommonCollectionDetailActivity : ToolBarActivity() {
}
override fun getBusinessId(): Pair<String, String> {
val fragment = targetFragment as CommonCollectionDetailFragment
return if (fragment.arguments != null) {
val fragment = targetFragment as? CommonCollectionDetailFragment?
return if (fragment?.arguments != null) {
Pair(
fragment.requireArguments().getString(EntranceConsts.KEY_COLLECTION_ID) ?: "",
fragment.requireArguments().getString(EntranceConsts.KEY_BLOCK_ID) ?: ""

View File

@ -14,6 +14,11 @@ import com.gh.gamecenter.common.utils.updateStatusBarColor
*/
class CustomCommonCollectionDetailActivity : ToolBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
@ -31,8 +36,8 @@ class CustomCommonCollectionDetailActivity : ToolBarActivity() {
}
override fun getBusinessId(): Pair<String, String> {
val fragment = targetFragment as CustomCommonCollectionDetailFragment
return if (fragment.arguments != null) {
val fragment = targetFragment as? CustomCommonCollectionDetailFragment?
return if (fragment?.arguments != null) {
Pair(
fragment.requireArguments().getString(EntranceConsts.KEY_COLLECTION_ID) ?: "",
fragment.requireArguments().getString(EntranceConsts.KEY_BLOCK_ID) ?: ""

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