Compare commits

..

164 Commits

Author SHA1 Message Date
e1fc23a1bb tinker_base-4.0.1_bugfix 2020-06-17 17:51:22 +08:00
2d551a3f73 VersionCode 改为171 2020-06-17 17:42:37 +08:00
9b205366f7 1.修改视频流广告gif不播放 2.添加网页跳转支付宝微信支付 2020-06-16 18:29:20 +08:00
4727f22b0f tinker_base-4.0.1 2020-06-05 10:05:57 +08:00
a3d693ddc1 更改自定义栏目浮窗消失逻辑 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/878 2020-06-03 17:25:03 +08:00
79cbb44d51 更改自定义栏目浮窗消失逻辑 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/878 2020-06-03 16:36:38 +08:00
dcde3db33a 修复 ExpandTextView 使用渐隐展开样式时在部分设备上会换行显示的问题 2020-06-03 16:03:46 +08:00
44fbc7a182 游戏详情评论回复用户姓名加粗 2020-06-03 15:13:24 +08:00
d7a85edb76 完成游戏详情自定义栏目显示三秒自动隐藏的提示展开浮窗 2020-06-03 11:50:26 +08:00
ceb9dc6707 完成游戏详情自定义栏目显示三秒自动隐藏的提示展开浮窗 2020-06-03 11:39:02 +08:00
b0f20ee017 去掉梦工厂SDK 2020-06-03 10:13:47 +08:00
cdf78f2bc5 游戏详情UI优化 2020-06-02 18:40:28 +08:00
d3f0a8fe4a Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-02 15:39:41 +08:00
17acf1bd86 优化游戏详情UI 2020-06-02 15:39:36 +08:00
31a0bb24c7 修复 ExpandTextView 尾部空隙太大的问题 2020-06-02 15:29:50 +08:00
13ff1f4343 微调游戏详情UI 2020-06-02 10:50:14 +08:00
ec76be9d5e 处理点击web页面闪退 2020-06-02 09:22:59 +08:00
84d53616a0 完成游戏详情UI优化 2020-06-01 18:38:44 +08:00
2758216ae2 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-01 18:12:38 +08:00
c492f066ca 游戏详情UI优化(未完) 2020-06-01 18:12:33 +08:00
897478e30e 完成游戏详情UI优化(0601自定义栏目部分) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/878 2020-06-01 18:01:16 +08:00
a94d825ead 修复历史版本在下载数据(旧)的终点问题 2020-06-01 11:45:42 +08:00
ba05e6137e 去掉 ExpandTextView 同时应用 lineSpacingExtra, maxLines, movementMethod 时底部出现的额外内边距 2020-06-01 11:39:27 +08:00
dc55342343 修复详情页页面回收重建时重复创建 tab 的问题 2020-06-01 11:37:21 +08:00
3ea96d27db 修复评论详情徽章显示问题 2020-06-01 11:06:44 +08:00
48842c099b Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-01 10:27:39 +08:00
4f87cac46a 优化h5小游戏全屏展示 2020-06-01 10:27:35 +08:00
52680b63b9 正式环境Api 切换至v4d0d1 2020-06-01 09:54:48 +08:00
f89defc78f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-01 09:38:15 +08:00
46e9a161a4 光环前端优化汇总(2020年5月第2周)(0529测试) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/858 2020-06-01 09:38:07 +08:00
8e602e8169 h5小游戏全屏展示 2020-06-01 09:36:07 +08:00
c60df98577 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-29 16:05:08 +08:00
ad7db50336 删除文章/回答/视频评论页面临时草稿功能 2020-05-29 16:05:03 +08:00
e40ef5292e 调整游戏详情自定义栏目间距 2020-05-29 15:38:19 +08:00
94b844788c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-29 15:29:42 +08:00
9c222baf91 修改h5游戏顶部按钮不能点击 2020-05-29 15:29:37 +08:00
0794606e57 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-29 14:30:43 +08:00
be34c486bf 开服日历表版主对开测信息改为不可编辑 2020-05-29 14:30:35 +08:00
fa7a5fef9b 修改UI间距 2020-05-29 14:10:47 +08:00
9e518d5414 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-29 10:52:13 +08:00
2d17ecd438 社区优化汇总(2020年5月)(0528测试6)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-29 10:52:07 +08:00
56d6c28811 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-29 10:33:33 +08:00
86b77e29e2 修改资讯文章-评论详情-查看对话评论框UI 2020-05-29 10:33:28 +08:00
23b8b09834 恢复 startForegroundService 的后台限制 2020-05-29 10:17:53 +08:00
30eb397c66 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 19:55:34 +08:00
05bcc0f818 社区优化汇总(2020年5月)(1,2,3,5,7)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-28 19:55:29 +08:00
3f9434239f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 18:24:02 +08:00
4caf7eabc0 光环助手V4.0.1-H5游戏功能优化(接入梦工厂H5小游戏)20200528补充1,2 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/856 2020-05-28 18:23:58 +08:00
0aee08bbb0 调整游戏详情自定义栏目UI https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/878 2020-05-28 18:07:37 +08:00
602dbff3c8 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 18:06:37 +08:00
d52cfd475f 修改玩家评论UI 2020-05-28 18:06:33 +08:00
4512accb37 调整游戏详情自定义栏目UI https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/878 2020-05-28 18:03:39 +08:00
2d57c00149 调整游戏详情自定义栏目UI https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/878 2020-05-28 17:59:55 +08:00
cae908da6a 修复历史版本下载的下载数据显示问题 2020-05-28 17:31:20 +08:00
38f97673b8 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2020-05-28 16:52:24 +08:00
ed2bf89413 多平台下载弹窗增加存储大小判断 2020-05-28 16:51:53 +08:00
259d343e31 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 16:42:58 +08:00
8e9dbafb4d 游戏大事件弹窗自适应宽度 2020-05-28 16:42:53 +08:00
7e737d7a46 游戏列表去除默认标签(没有数据时,直接不显示) 2020-05-28 16:06:28 +08:00
50fd30d173 去除消息中心第一页的加载动画 2020-05-28 15:27:40 +08:00
4c7310f71e Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 11:21:01 +08:00
b3e7168922 修改开服日历表UI 2020-05-28 11:20:55 +08:00
261cc5b0eb Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 11:16:54 +08:00
60218eea97 修改查看对话输入框UI 2020-05-28 11:16:48 +08:00
bc1945326a 修改查看对话输入框UI 2020-05-28 11:16:12 +08:00
2fd12d56ed 修改回答/文章草稿发布后的跳转逻辑 2020-05-28 11:07:29 +08:00
cb28838b40 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-28 10:32:03 +08:00
4cfd6952c0 社区优化汇总(2020年5月)(0527测试7,8) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-28 10:31:58 +08:00
f5761e378e 避免 broadcast receiver 被多次调用 2020-05-28 10:31:37 +08:00
314144c384 调整文案 2020-05-28 10:30:35 +08:00
81debc1cd8 修改收起评论框数据丢失 2020-05-28 09:40:56 +08:00
9a2baf1d8c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-27 20:34:24 +08:00
55ec26bd3d 社区优化汇总(2020年5月)(0527测试1,2,3,4,6) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-27 20:34:19 +08:00
4c372eeb2b 光环助手V4.0.1-内容间距优化20200527测试 1,2 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/855 2020-05-27 16:52:09 +08:00
c2f9e28edd Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-27 15:45:39 +08:00
65a8297fe0 保存顶部视频进度重启恢复 2020-05-27 15:45:35 +08:00
1a48cca197 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-27 15:39:37 +08:00
24984b5d67 光环前端优化汇总(2020年5月第2周)(20200526测试1,2)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/858 2020-05-27 15:39:33 +08:00
619660e5e5 新多版本弹窗补充曝光路径 2020-05-27 10:57:49 +08:00
c9c4a996dc 粗暴修复因为多线程下载同一任务造成的解析包错误问题 2020-05-27 10:32:03 +08:00
b8ae8b68dc 修改我的评论点击两次才能进入评论详情问题 2020-05-27 10:03:21 +08:00
a9f4620d8b 处理专区事件拦截 2020-05-26 17:21:43 +08:00
66abdb1eed Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-26 17:08:31 +08:00
1dc4be2d54 增加NestedScrollWebView2,处理CoordinatorLayout嵌套webview滑动卡顿 2020-05-26 17:08:25 +08:00
a286f51801 完成下载管理优化与下载异常修复的(1,2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/873 2020-05-26 16:33:13 +08:00
27708da1bf Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-26 16:13:45 +08:00
3aa0e19b0f 社区优化汇总(2020年5月)(3)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-26 16:13:38 +08:00
4d5627348a 光环助手V4.0.1-评论内容网络错误排查与交互优化20200525测试1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/869 2020-05-26 15:55:48 +08:00
2aefeb5e53 1.开始玩设置全屏 2.梦工厂集成防沉迷库 2020-05-26 15:26:56 +08:00
728b663c7a Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-26 14:27:09 +08:00
36156cddc4 光环助手V4.0.1-评论复制功能优化20200525 1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/861 2020-05-26 14:27:04 +08:00
2b98702ceb Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-26 14:15:42 +08:00
2c2ab02398 光环助手V4.0.1-下拉刷新loading优化(20200525测试) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/850 2020-05-26 14:15:36 +08:00
8ae8c6d6fb Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-26 11:53:58 +08:00
1171424f19 修改资讯文章评论详情评论框UI 2020-05-26 11:53:53 +08:00
3444922861 光环助手V4.0.1-视频相关优化汇总(6,7)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/866 2020-05-26 11:13:20 +08:00
5821a519ee Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-25 18:15:40 +08:00
439a2353b0 重复增加登录异常MTA事件 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/863 (3) 2020-05-25 18:15:28 +08:00
8f8f3193dd Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-25 18:12:07 +08:00
5907b8b1a5 修改评论框UI(除资讯评论) 2020-05-25 18:12:01 +08:00
ba5783417e 光环助手V4.0.0补充需求:游戏列表优化(5) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/862 2020-05-25 18:02:04 +08:00
56573deea1 修复回答/文章草稿无法删除问题 2020-05-25 17:31:11 +08:00
892933888c dev api 升为 v4d0d1
删除comment host
2020-05-25 17:14:48 +08:00
b3725baad0 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-25 17:05:47 +08:00
cf79735780 回答/文章编辑增加草稿功能 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 (5,6) 2020-05-25 17:05:36 +08:00
ad059fe18d 修复因改版造成的下载数据(新)下载事件缺失的问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/877 2020-05-25 17:03:57 +08:00
03fa2052da Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-25 10:28:38 +08:00
d7d55b7341 回答/文章评论增加评论草稿功能 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 (7) 2020-05-25 10:28:30 +08:00
6ea9a7de90 处理视频流切换全屏马上又退出全屏问题 2020-05-25 09:39:51 +08:00
3bc65f42c7 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-22 17:12:04 +08:00
854227304f 微调UI 2020-05-22 17:11:58 +08:00
62d34c6c06 调整游戏详情横向滑动列表边距 2020-05-22 16:34:25 +08:00
69f0beff9c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-22 16:22:16 +08:00
2a32859c48 修改文章/回答草稿UI 2020-05-22 16:22:09 +08:00
c6bdb4ee8d Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-22 15:54:27 +08:00
cf5e981758 修改状态栏颜色,去掉immersionbar 2020-05-22 15:54:23 +08:00
2bf246562b Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-22 11:57:21 +08:00
c1cd25b89b 光环前端优化汇总(2020年5月第2周)(11,12)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/858 2020-05-22 11:57:11 +08:00
2eb259055a 移除BlockCanary库 2020-05-22 10:48:41 +08:00
fe743590c9 修改注释 2020-05-21 18:19:53 +08:00
d3de1c238c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-21 18:17:01 +08:00
931593d726 光环助手V4.0.1-多版本下载-包名过滤异常修复 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/876 2020-05-21 18:16:53 +08:00
8f002fc804 完成新首页轮播图曝光数据 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/877 2020-05-21 18:02:23 +08:00
10e0d0123e Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-21 16:58:42 +08:00
b93cb06662 修改历史版本下载按钮mta事件 2020-05-21 16:58:36 +08:00
5471099e7b 修改网络状态变动后下载重试的时机(防止退出app后无法触发重试机制) 2020-05-21 16:27:27 +08:00
5a2f86be87 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-21 16:14:06 +08:00
3d7ce17b07 下载增加下载服务外的重试机制 2020-05-21 16:13:46 +08:00
cf0e237529 修复历史版本的下载路径上报异常问题 2020-05-21 14:48:10 +08:00
60c84153e5 修改游戏设备弹窗类型转换错误 2020-05-21 14:26:28 +08:00
f9a8efe084 修改h5游戏状态栏颜色 2020-05-21 11:52:25 +08:00
6b48c546c4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-21 10:31:57 +08:00
b1893718f6 光环助手V4.0.1-顶部状态栏统一改为全透明样式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/871 2020-05-21 10:31:52 +08:00
7ad95d5f26 社区优化汇总(2020年5月)(4)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-21 10:22:25 +08:00
778b0e8f16 版本号升级到 4.0.1 2020-05-20 17:58:09 +08:00
ad847f6113 Merge branch 'dev_4.0.1' into 'dev'
Dev 4.0.1

See merge request halo/assistant-android!15
2020-05-20 17:51:19 +08:00
27778c2b31 Merge branch 'dev' into 'dev_4.0.1'
# Conflicts:
#   app/src/main/java/com/gh/common/util/TimeUtils.kt
#   app/src/main/java/com/gh/download/DownloadManager.java
2020-05-20 17:50:59 +08:00
484694cbdb 完成4.0.1点赞功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/853 2020-05-20 17:48:31 +08:00
969680a7ad Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-20 17:46:43 +08:00
6357e008dc 社区优化汇总(2020年5月)(1,2)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/872 2020-05-20 17:46:31 +08:00
a570cfe32b 优化视频流页面UI 2020-05-20 17:44:50 +08:00
ccba561d47 光环助手V4.0.1-评论内容网络错误排查与交互优化(2,3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/869 2020-05-20 16:52:05 +08:00
f5abd7e075 光环助手V4.0.1-评论内容网络错误排查与交互优化1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/869 2020-05-20 09:20:34 +08:00
35cd97c751 Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-19 17:41:57 +08:00
147bc150f5 光环前端优化汇总(2020年5月第2周)(问答相关)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/858 2020-05-19 17:41:45 +08:00
7f0e59aba5 预加载广告图片、延迟0.1s视频预加载 2020-05-19 17:03:28 +08:00
6986bd9a57 光环助手V4.0.1-视频加载机制优化(1) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/870 2020-05-19 11:42:27 +08:00
a6feb57f85 Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-19 09:54:34 +08:00
50fee01249 光环助手V4.0.1-视频相关优化汇总(1,3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/866 2020-05-19 09:54:28 +08:00
4ff12e91aa Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-18 16:17:13 +08:00
24b196f216 光环助手V4.0.1-内容发表后与Toast优化(二)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/857 2020-05-18 16:16:57 +08:00
d36b2f99ee 升级gsyVideo版本至7.1.4 2020-05-18 11:52:33 +08:00
704b73aef7 完成光环助手V4.0.1-H5游戏功能优化(接入梦工厂H5小游戏)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/856 2020-05-18 11:20:32 +08:00
72cfcd66b1 Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-15 18:35:05 +08:00
0cb65ab216 光环助手V4.0.1-下拉刷新loading优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/850 2020-05-15 18:34:30 +08:00
d18731ccfe 完成光环助手V4.0.1-时间显示规则优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/865 2020-05-15 18:11:52 +08:00
91f79a5ff1 光环助手V4.0.1-时间显示规则优化(未完)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/865 2020-05-15 15:15:25 +08:00
d37929548e Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-14 18:36:15 +08:00
663891dd54 光环助手V4.0.1-评论复制功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/861 2020-05-14 18:36:11 +08:00
79d1c4fed4 完成4.0.1历史浏览记录优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/852 2020-05-14 18:21:02 +08:00
ecc8196701 光环前端优化汇总(2020年5月第2周)(4(关注问题、我的问题),7,9) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/858 2020-05-14 17:15:26 +08:00
83e44808cb Merge branch 'dev_4.0.1' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.1 2020-05-14 14:35:36 +08:00
bfbc9900ed 光环前端优化汇总(2020年5月第2周) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/858 2020-05-14 14:35:19 +08:00
1735ba3312 1.对接梦工厂小游戏 2.导入穿山甲 2020-05-14 14:23:14 +08:00
268 changed files with 6385 additions and 3248 deletions

View File

@ -65,6 +65,8 @@ android {
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
buildConfigField "String", "MTA_APPKEY", "\"${MTA_APPKEY}\""
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\""
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
/**
* Build Time 供区分 jenkins 打包时间用
@ -121,7 +123,6 @@ android {
publish {
dimension "nonsense"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${COMMENT_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
@ -138,7 +139,6 @@ android {
versionNameSuffix "-debug"
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
@ -171,7 +171,7 @@ rebuildChannel {
repositories {
flatDir {
dirs 'libs/aars'
dirs 'libs','libs/aars'
}
}
@ -195,9 +195,6 @@ dependencies {
implementation "androidx.annotation:annotation:${annotation}"
implementation "androidx.constraintlayout:constraintlayout:${constraintLayout}"
implementation "androidx.recyclerview:recyclerview:${recyclerView}"
// implementation "androidx.lifecycle:lifecycle-runtime:${lifeCycle}"
// implementation "androidx.lifecycle:lifecycle-extensions:${lifeCycle}"
// kapt "androidx.lifecycle:lifecycle-compiler:${lifeCycle}"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifeCycle"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifeCycle"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifeCycle"
@ -206,7 +203,6 @@ dependencies {
implementation "androidx.core:core-ktx:${ktx}"
implementation "androidx.viewpager2:viewpager2:${viewpager2}"
kapt "androidx.room:room-compiler:${room}"
// kapt "androidx.databinding:databinding-compiler:${databinding}"
implementation "com.google.android.material:material:${material}"
@ -297,9 +293,6 @@ dependencies {
exclude group: 'com.squareup.okhttp3'
})
debugImplementation "com.github.markzhai:blockcanary-android:$blockcanary"
releaseImplementation "com.github.markzhai:blockcanary-no-op:$blockcanary"
implementation project(':libraries:LGLibrary')
implementation project(':libraries:MTA')
implementation project(':libraries:QQShare')

View File

@ -240,4 +240,12 @@
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-dontwarn tv.danmaku.ijk.**
-dontwarn tv.danmaku.ijk.**
#穿山甲
-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}
-keep class com.gyf.immersionbar.* {*;}
-dontwarn com.gyf.immersionbar.**

View File

@ -36,6 +36,15 @@
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
com.shuyu.gsyvideoplayer.armv7a,
@ -44,7 +53,13 @@
com.google.android.exoplayer2,
tv.danmaku.ijk.media.exo2,
shuyu.com.androidvideocache,
pl.droidsonroids.gif" />
pl.droidsonroids.gif,
com.ledong.lib.minigame,
com.ledong.lib.leto,
com.leto.game.base.glide4,
com.leto.game.ad.gdt,
com.leto.game.fcm,
com.leto.game.ad.toutiao" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -161,6 +176,7 @@
android:screenOrientation="portrait" />
<activity
android:theme="@style/TransparentStatusBarAndNavigationBar"
android:name="com.gh.gamecenter.MessageDetailActivity"
android:screenOrientation="portrait" />
@ -191,6 +207,7 @@
<activity
android:name="com.gh.gamecenter.CommentDetailActivity"
android:theme="@style/TransparentStatusBarAndNavigationBar"
android:screenOrientation="portrait" />
<activity
@ -401,6 +418,7 @@
android:screenOrientation="portrait" />
<activity
android:theme="@style/TransparentStatusBarAndNavigationBar"
android:name="com.gh.gamecenter.gamedetail.rating.RatingReplyActivity"
android:screenOrientation="portrait" />
@ -492,6 +510,10 @@
android:name="com.gh.gamecenter.QaActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.answer.draft.AnswerDraftActivity"
android:screenOrientation="portrait" />
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
<activity
android:name="com.gh.gamecenter.PushProxyActivity"
@ -587,6 +609,39 @@
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
<!-- 梦工厂配置 开始 -->
<!--<meta-data
android:name="MGC_APPID"
android:value="1001276" />
<provider
android:name="com.leto.game.base.provider.LetoFileProvider"
android:authorities="${applicationId}.leto.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/leto_file_path"
tools:replace="android:resource" />
</provider>-->
<!-- 梦工厂配置 结束 -->
<!-- 穿山甲配置 开始 -->
<!--<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />-->
<!-- 穿山甲配置 结束 -->
</application>
</manifest>

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,7 @@ import android.text.TextUtils;
import android.view.Window;
import android.view.WindowManager;
import com.gh.base.fragment.BaseFragment;
import com.gh.common.constant.Constants;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.MtaHelper;
@ -36,6 +37,7 @@ import java.lang.ref.WeakReference;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import butterknife.ButterKnife;
import pub.devrel.easypermissions.EasyPermissions;
@ -182,6 +184,11 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
super.onPause();
if (isFinishing()) {
onFinish();
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
if (fragment.isAdded() && fragment instanceof BaseFragment) {
((BaseFragment) fragment).onParentActivityFinish();
}
}
}
}

View File

@ -9,6 +9,7 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.webkit.JavascriptInterface
import android.widget.TextView
import butterknife.OnClick
import com.gh.common.util.DialogUtils
import com.gh.common.util.MtaHelper
@ -16,6 +17,7 @@ import com.gh.common.view.RichEditor
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity
import com.gh.gamecenter.qa.editor.GameActivity
import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity
import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity
@ -31,6 +33,7 @@ import kotterknife.bindView
abstract class BaseRichEditorActivity : ToolBarActivity() {
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
val mDraftBtn by bindView<TextView>(R.id.draft_btn)
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
@ -87,6 +90,10 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
mRichEditor.setInputEnabled(true)
mDraftBtn.text = if (this is AnswerEditActivity) {
"回答草稿"
} else "文章草稿"
}
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,

View File

@ -12,11 +12,9 @@ import android.preference.PreferenceManager
import android.text.TextUtils
import android.view.View
import androidx.core.app.NotificationCompat
import androidx.core.text.htmlEncode
import com.gh.common.notifier.Notifier
import com.gh.common.util.EntranceUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.StringUtils
import com.gh.common.util.toObject
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.PushEntity
import com.gh.gamecenter.entity.PushMessageEntity
@ -132,7 +130,7 @@ class GHUmengNotificationService : UmengMessageService() {
.setSmallIcon(R.drawable.ic_notification)
.setTicker(pushData.body?.ticker)
.setContentTitle(pushData.body?.title)
.setContentText(pushData.body?.text)
.setContentText(pushData.body?.text?.fromHtml())
.setContentIntent(clickPendingIntent)
.setDeleteIntent(deletePendingIntent)
.build()

View File

@ -3,7 +3,6 @@ package com.gh.base;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
@ -12,7 +11,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
@ -52,6 +50,8 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
@Nullable
private PackageViewModel mPackageViewModel;
protected RelativeLayout mToolbarContainer;
protected Toolbar mToolbar;
protected TextView mTitleTv;
@ -62,7 +62,6 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStatusBarDarkMode(true, this);
initToolbar();
@ -88,6 +87,7 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
}
private void initToolbar() {
mToolbarContainer = findViewById(R.id.normal_toolbar_container);
mToolbar = findViewById(R.id.normal_toolbar);
mTitleTv = findViewById(R.id.normal_title);
if (mToolbar != null) {
@ -253,4 +253,11 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
protected boolean showDownloadMenu() {
return false;
}
@Override
public void hideToolbar(boolean isHide) {
if (mToolbarContainer != null) {
mToolbarContainer.setVisibility(isHide ? View.GONE : View.VISIBLE);
}
}
}

View File

@ -9,14 +9,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.base.OnListClickListener;
import com.gh.base.OnRequestCallBackListener;
import com.gh.common.constant.Constants;
@ -37,6 +29,13 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.ButterKnife;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -304,6 +303,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
return this;
}
public void onParentActivityFinish() {
}
@Nullable
protected RecyclerView.Adapter provideSyncAdapter() {
return null;

View File

@ -4,20 +4,18 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.text.TextUtils
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.LibaoDetailActivity
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.WebActivity
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
import com.gh.common.util.DirectUtils.directToGameVideo
import com.gh.common.util.DirectUtils.directToVideoDetail
import com.gh.gamecenter.*
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.VideoLinkEntity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.lightgame.utils.Utils
object DefaultWebViewUrlHandler {
@JvmStatic
@ -135,19 +133,78 @@ object DefaultWebViewUrlHandler {
val position = uri.getQueryParameter("position")
DirectUtils.directToHomeActivity(context, id, if (position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
}
EntranceUtils.HOST_VIDEO_MORE -> {
val referer = uri.getQueryParameter("referer") ?: ""
val type = uri.getQueryParameter("type") ?: ""
val act = uri.getQueryParameter("act") ?: ""
val loaction = if (TextUtils.isEmpty(act)) id else VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.value
DirectUtils.directToVideoDetail(context, id, loaction, false, "", entrance, "", referer, type, act)
directToVideoDetail(context, id, loaction, false, "", entrance, "", referer, type, act)
}
EntranceUtils.HOST_VIDEO_SINGLE -> {
val referer = uri.getQueryParameter("referer") ?: ""
directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer)
}
EntranceUtils.HOST_VIDEO_STREAMING_HOME -> {
intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true)
context.startActivity(intent)
}
EntranceUtils.HOST_VIDEO_STREAMING_DESC -> {
directToGameDetailVideoStreaming(context, id, entrance)
}
EntranceUtils.HOST_VIDEO_COLLECTION -> {
directToGameVideo(context, id, entrance, "")
}
EntranceUtils.HOST_CATEGORY -> {
val title = uri.getQueryParameter("title")
DirectUtils.directCategoryDirectory(context, id, title ?: "", entrance, "")
}
EntranceUtils.HOST_COLUMN_COLLECTION -> {
val name = uri.getQueryParameter("name")
DirectUtils.directToColumnCollection(context, id, -1, entrance, name ?: "")
}
EntranceUtils.HOST_COLUMN -> {
DirectUtils.directToSubject(context, id, uri.getQueryParameter(EntranceUtils.KEY_NAME), entrance)
}
EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL -> {
val community = CommunityEntity()
community.id = uri.getQueryParameter("community_id") ?: ""
community.name = uri.getQueryParameter("community_name") ?: ""
val tag = uri.getQueryParameter("tag") ?: ""
DirectUtils.directAskColumnLabelDetail(context, tag, community, entrance, "")
}
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL -> {
val community = CommunityEntity()
community.id = uri.getQueryParameter("community_id") ?: ""
community.name = uri.getQueryParameter("community_name") ?: ""
val columnId = uri.getQueryParameter("column_id") ?: ""
DirectUtils.directAskColumnDetail(context, columnId, community, entrance, "")
}
else -> DialogUtils.showLowVersionDialog(context)
}
return true
}
if (url.startsWith("alipays:") || url.startsWith("alipay")) {
try {
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
} catch (e: java.lang.Exception) {
ToastUtils.showToast("请安装支付宝客户端")
}
return true
} else if (url.startsWith("weixin")) {
try {
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
} catch (e: java.lang.Exception) {
ToastUtils.showToast("请安装微信客户端")
}
return true
}
if ("http" != uri.scheme && "https" != uri.scheme) return true
return false
}

View File

@ -31,7 +31,6 @@ import io.reactivex.schedulers.Schedulers;
public class Config {
public static final String API_HOST = BuildConfig.API_HOST;
public static final String COMMENT_HOST = BuildConfig.COMMENT_HOST;
/**
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
@ -49,6 +48,8 @@ public class Config {
public static final String UMENG_APPKEY = BuildConfig.UMENG_APPKEY;
public static final String UMENG_MESSAGE_SECRET = BuildConfig.UMENG_MESSAGE_SECRET;
public static final String BUGLY_APPID = BuildConfig.BUGLY_APPID;
public static final String LETO_APPID = BuildConfig.LETO_APPID;
public static final String TTAD_APPID = BuildConfig.TTAD_APPID;
// http://www.ghzs666.com/article/${articleId}.html
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
public static final String PATCHES = "patches";

View File

@ -28,8 +28,16 @@ public class Constants {
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
public static final String EB_QUIT_LOGIN = "quit_login";
public static final String GAME_ID_DIVIDER = ":"; // 用于避免历史下载掺和到普通下载状态的 ID 修饰符
// 用于避免历史下载掺和到普通下载状态的 ID 修饰符
public static final String GAME_ID_DIVIDER = ":";
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
public static final String GAME_NAME_DECORATOR = " ";
// 游戏详情进入时的自定义栏目标签是否已经默认展开过一次的标记
public static final String SP_HAS_EXPANDED_GAME_DETAIL_TAGS = "has_expanded_game_detail_tags";
// 游戏详情进入时的自定义栏目标签是否已经显示过一次展开更多的浮窗提示
public static final String SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT = "has_shown_expanded_game_detail_tags_hint";
// 最近显示的弹窗信息
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
@ -73,9 +81,11 @@ public class Constants {
//游戏设备弹窗不再提示
public static final String SP_NO_REMIND_AGAIN = "no_remind_again";
//游戏详情过滤标签数据
public static final String SP_FILTER_TAGS= "filter_tags";
public static final String SP_FILTER_TAGS = "filter_tags";
//实名认证弹窗分类数据
public static final String SP_AUTH_DIALOG= "auth_dialog";
public static final String SP_AUTH_DIALOG = "auth_dialog";
//顶部视频进度保存,重启恢复
public static final String SP_TOP_VIDEO_SCHEDULE = "top_video_schedule";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
@ -112,13 +122,16 @@ public class Constants {
public static final int ADDONS_CD = 10 * 60 * 1000;
//已收录包名更新 cd间隔
public static final int PACKAGES_CD = 60 * 1000;
public static final String[] REPORT_LIST = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它"};
public static final String ENTRANCE_UNKNOWN = "(unknown)";
public static final String DEFAULT_TEXT_WRAPPER = "###";
// 触发了安装事件的标记
public static final String MARK_ALREADY_TRIGGERED_INSTALLATION = "triggered_installation";
// 标记下载重试标记(值为任务已下载大小,为空表示需要重试)
public static final String MARK_RETRY_DOWNLOAD = "retry_download";
}

View File

@ -13,19 +13,13 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.base.OnViewClickListener;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.history.HistoryHelper;
import com.gh.common.repository.ReservationRepository;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DataUtils;
@ -59,6 +53,7 @@ import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.entity.ServerCalendarEntity;
import com.gh.gamecenter.entity.TagStyleEntity;
import com.gh.gamecenter.entity.TestEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
@ -69,9 +64,16 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Created by khy on 12/02/18.
*/
@ -236,6 +238,14 @@ public class BindingAdapters {
view.setPadding(view.getPaddingLeft(), DisplayUtils.dip2px(paddingTopInDp), view.getPaddingRight(), view.getPaddingBottom());
}
/**
* lazy 的 paddingBottom
*/
@BindingAdapter("lazyPaddingBottom")
public static void lazyPaddingBottom(View view, int paddingBottomInDp) {
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), DisplayUtils.dip2px(paddingBottomInDp));
}
@BindingAdapter("visibleInvisible")
public static void visibleInvisible(View view, Boolean show) {
if (show != null && show) {
@ -411,6 +421,7 @@ public class BindingAdapters {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location + ":" + gameEntity.getName());
});
@ -425,6 +436,7 @@ public class BindingAdapters {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location + ":" + gameEntity.getName());
}
@ -465,9 +477,15 @@ public class BindingAdapters {
}
break;
case H5_GAME:
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
LinkEntity linkEntity = gameEntity.getH5Link();
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), "play".equals(linkEntity.getType())));
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay));
progressBar.getContext().startActivity(i);
break;
}
@ -613,9 +631,6 @@ public class BindingAdapters {
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), entrance, "下载开始", method);
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, method);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
DownloadManager.createDownload(progressBar.getContext(),
apkEntity,
gameEntity,
@ -623,7 +638,7 @@ public class BindingAdapters {
entrance,
location + gameEntity.getName(),
isSubscribe,
downloadExposureEvent);
traceEvent);
progressBar.setProgress(0);
progressBar.setDownloadType("插件化".equals(method) ?
@ -638,6 +653,33 @@ public class BindingAdapters {
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
}
// 包含测试开服标签
@BindingAdapter("setGameTags")
public static void setGameTags(LinearLayout layout, GameEntity gameEntity) {
try {
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
TestEntity test = gameEntity.getTest();
if (test != null) {
TagStyleEntity typeTag = new TagStyleEntity();
typeTag.setName(test.getType() != null ? test.getType() : "");
typeTag.setBackground("FFF3E0");
typeTag.setColor("FA8500");
tagStyle.add(typeTag);
TagStyleEntity timeTag = new TagStyleEntity();
timeTag.setName(GameViewUtils.getGameTestDate(test.getStart()));
timeTag.setBackground("E0FFF9");
timeTag.setColor("00A887");
tagStyle.add(timeTag);
} else {
tagStyle = gameEntity.getTagStyle();
}
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
} catch (Exception e) {
e.printStackTrace();
}
}
@BindingAdapter("isRefreshing")
public static void isRefreshing(SwipeRefreshLayout layout, LoadStatus status) {
if (status != LoadStatus.INIT_LOADING && status != LoadStatus.LIST_LOADING) {

View File

@ -30,7 +30,6 @@ import com.halo.assistant.fragment.SettingsFragment.AUTO_INSTALL_SP_KEY
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.utils.Utils
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.dialog_device_remind.view.*
import java.lang.ref.WeakReference
@ -179,7 +178,7 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
inner class BannerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_ad_banner, parent, false)) {}
return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_device_remind_banner, parent, false)) {}
}
override fun getItemCount(): Int = if (mDatas.size == 1) mDatas.size else Int.MAX_VALUE

View File

@ -15,6 +15,7 @@ import butterknife.BindView
import butterknife.ButterKnife
import butterknife.OnClick
import com.gh.common.constant.Config
import com.gh.common.history.HistoryHelper
import com.gh.common.repository.ReservationRepository
import com.gh.common.util.*
import com.gh.gamecenter.R
@ -49,6 +50,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
private var mSuccessCallback: SuccessCallback? = null
private var mGame: GameEntity? = null
private var mGameId: String = ""
private var mGameName: String = ""
@ -86,6 +88,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
if (it.success) {
showSuccessDialog(it.withMobile, it.boundWechat)
mSuccessCallback?.onSuccess()
HistoryHelper.insertGameEntity(mGame!!)
}
}
dialog?.setCanceledOnTouchOutside(true)
@ -149,6 +152,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
companion object {
@JvmStatic
fun getInstance(gameEntity: GameEntity, successCallback: SuccessCallback) = ReserveDialogFragment().apply {
this.mGame = gameEntity
this.mGameId = gameEntity.id
this.mGameName = gameEntity.name ?: ""
this.mSuccessCallback = successCallback

View File

@ -4,6 +4,7 @@ import android.os.Parcelable
import androidx.annotation.Keep
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.gh.common.constant.Constants
import com.gh.common.exposure.meta.Meta
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.time.TimeUtil
@ -28,7 +29,7 @@ data class ExposureEvent(
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
return ExposureEvent(
payload = ExposureEntity(gameId = gameEntity?.id,
gameName = gameEntity?.name,
gameName = gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
sequence = gameEntity?.sequence,
platform = gameEntity?.platform,
downloadType = gameEntity?.downloadType,

View File

@ -1,5 +1,7 @@
package com.gh.common.exposure
import com.g00fy2.versioncompare.Version
import com.gh.common.constant.Constants
import com.gh.common.util.PackageUtils
import com.gh.common.util.toObject
import com.gh.gamecenter.entity.ApkEntity
@ -15,6 +17,11 @@ object ExposureUtils {
traceEvent: ExposureEvent?,
downloadType: DownloadType): ExposureEvent {
val gameEntity = entity.clone()
gameEntity.id = if (entity.id.contains(Constants.GAME_ID_DIVIDER)) {
entity.id.split(Constants.GAME_ID_DIVIDER).toTypedArray()[0]
} else {
entity.id
}
gameEntity.platform = platform
gameEntity.downloadType = downloadType.toString()
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
@ -43,29 +50,26 @@ object ExposureUtils {
}
@JvmStatic
fun getDownloadType(apkEntity: ApkEntity, method: String) : DownloadType {
return if ("更新" == method) {
if (PackageUtils.isSignature(HaloApp.getInstance().application, apkEntity.packageName)) {
DownloadType.PLUGIN_UPDATE
fun getDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
return if (PackageUtils.isInstalled(HaloApp.getInstance().application, apkEntity.packageName)) {
if (PackageUtils.isSignedByGh(HaloApp.getInstance().application, apkEntity.packageName)) {
if (PackageUtils.isCanUpdate(apkEntity, gameId)) {
DownloadType.PLUGIN_UPDATE
} else {
if (Version(apkEntity.version).isHigherThan(PackageUtils.getVersionByPackage(apkEntity.packageName))) {
DownloadType.UPDATE
} else {
DownloadType.DOWNLOAD
}
}
} else {
DownloadType.UPDATE
DownloadType.PLUGIN_DOWNLOAD
}
} else if ("插件化" == method) {
DownloadType.PLUGIN_DOWNLOAD
} else {
DownloadType.DOWNLOAD
}
}
@JvmStatic
fun getUpdateType(apkEntity: ApkEntity) : DownloadType {
return if (PackageUtils.isSignature(HaloApp.getInstance().application, apkEntity.packageName)) {
DownloadType.PLUGIN_UPDATE
} else {
DownloadType.UPDATE
}
}
enum class DownloadType {
DOWNLOAD,

View File

@ -4,9 +4,7 @@ import com.gh.common.runOnIoThread
import com.gh.common.util.clearHtmlFormatCompletely
import com.gh.common.util.removeInsertedContent
import com.gh.common.util.removeVideoContent
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.HistoryGameEntity
import com.gh.gamecenter.entity.NewsEntity
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
@ -24,11 +22,32 @@ object HistoryHelper {
runOnIoThread { HistoryDatabase.instance.articleDao().addArticle(articleEntity) }
}
@JvmStatic
fun insertGameEntity(gameEntity: GameEntity) {
val historyGameEntity = convertGameEntityToHistoryGameEntity(gameEntity)
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
}
@JvmStatic
fun insertGameEntity(updateEntity: GameUpdateEntity) {
val historyGameEntity = convertGameUpdateEntityToHistoryGameEntity(updateEntity)
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
}
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity{
val historyGame = HistoryGameEntity()
historyGame.orderTag = System.currentTimeMillis()
historyGame.id = updateEntity.id
historyGame.brief = updateEntity.brief
historyGame.des = ""
historyGame.icon = updateEntity.icon
historyGame.name = updateEntity.name
historyGame.tagStyle = updateEntity.tagStyle
historyGame.tag = updateEntity.tag
return historyGame
}
private fun convertGameEntityToHistoryGameEntity(gameEntity: GameEntity): HistoryGameEntity {
val historyGame = HistoryGameEntity()
@ -70,6 +89,11 @@ object HistoryHelper {
runOnIoThread { HistoryDatabase.instance.answerDao().deleteAnswer(AnswerEntity().apply { primaryKey = answerId }) }
}
@JvmStatic
fun deleteVideoEntity(videoId: String) {
runOnIoThread { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) }
}
@JvmStatic
fun emptyDatabase() {
runOnIoThread { HistoryDatabase.instance.clearAllTables() }

View File

@ -10,6 +10,7 @@ import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import com.gh.base.CurrentActivityHolder
import com.gh.common.util.doOnMainProcessOnly
import com.gh.gamecenter.R
import com.m7.imkfsdk.chat.ChatActivity
import com.m7.imkfsdk.utils.Utils
@ -25,51 +26,53 @@ class ImReceiver : BroadcastReceiver() {
var notificationManager: NotificationManager? = null
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
if (intent.action == IMChatManager.NEW_MSG_ACTION) {
notificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 判断 ImActivity 是否在最顶端
if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
ImManager.showFloatingWindow()
ImManager.updateShouldShowFloatingWindowDot(false)
} else {
val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
contentIntent.putExtra("PeerId", "")
contentIntent.putExtra("type", "peedId")
contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val resultPendingIntent = PendingIntent.getActivity(
Utils.getApp(),
0,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
// 新的通知
val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
val notification = builder.setTicker("您有新的消息")
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.drawable.ic_notification)
.setWhen(System.currentTimeMillis())
.setContentIntent(resultPendingIntent)
.setContentTitle("光环助手客服回复")
.setContentText("您有新的消息")
.setAutoCancel(true)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager?.createNotificationChannel(channel)
}
if (notification != null) {
notificationManager?.notify(NOTIFICATION_ID, notification)
context?.doOnMainProcessOnly {
intent?.let {
if (intent.action == IMChatManager.NEW_MSG_ACTION) {
notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 判断 ImActivity 是否在最顶端
if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
ImManager.showFloatingWindow()
ImManager.updateShouldShowFloatingWindowDot(false)
} else {
val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
contentIntent.putExtra("PeerId", "")
contentIntent.putExtra("type", "peedId")
contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val resultPendingIntent = PendingIntent.getActivity(
Utils.getApp(),
0,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
// 新的通知
val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
val notification = builder.setTicker("您有新的消息")
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.drawable.ic_notification)
.setWhen(System.currentTimeMillis())
.setContentIntent(resultPendingIntent)
.setContentTitle("光环助手客服回复")
.setContentText("您有新的消息")
.setAutoCancel(true)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager?.createNotificationChannel(channel)
}
if (notification != null) {
notificationManager?.notify(NOTIFICATION_ID, notification)
ImManager.showFloatingWindow()
}
}
} else if (intent.action == IMChatManager.FINISH_ACTION) {
ImManager.dismissFloatingWindow()
}
} else if (intent.action == IMChatManager.FINISH_ACTION) {
ImManager.dismissFloatingWindow()
}
}
}

View File

@ -33,6 +33,7 @@ import java.lang.ref.WeakReference;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@ -51,8 +52,12 @@ public class CommentUtils {
public static void setCommentTime(TextView textView, long time) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
long day = time * 1000;
String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
format.applyPattern("yyyy");
String currentYear = format.format(day);
format.applyPattern("yyyyMMdd");
long today = format.parse(format.format(new Date())).getTime();
if (day >= today && day < today + 86400 * 1000) {
long min = new Date().getTime() / 1000 - day / 1000;
int hour = (int) (min / (60 * 60));
@ -68,6 +73,13 @@ public class CommentUtils {
} else if (day >= today - 86400 * 1000 && day < today) {
format.applyPattern("HH:mm");
textView.setText("昨天 ");
} else if (day >= today - 86400 * 1000 * 7 && day < today - 86400 * 1000) {
format.applyPattern("HH:mm");
long days = (today - day) / 86400000 + 1;
textView.setText(String.format(Locale.getDefault(), "%d天前 ", days));
} else if (day < today - 86400 * 1000 * 7 && year.equals(currentYear)) {
format.applyPattern("MM-dd");
textView.setText(format.format(day));
} else {
format.applyPattern("yyyy-MM-dd");
textView.setText(format.format(day));
@ -199,7 +211,7 @@ public class CommentUtils {
final TextView commentLikeCountTv, final ImageView commentLikeIv,
final OnVoteListener listener) {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
Utils.toast(context, "已经点过赞啦!");
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
@ -236,7 +248,7 @@ public class CommentUtils {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if ("voted".equals(detail)) {
Utils.toast(context, "已经点过赞啦!");
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
}
} catch (Exception ex) {
ex.printStackTrace();
@ -265,7 +277,7 @@ public class CommentUtils {
}
CheckLoginUtils.checkLogin(context, entrance, () -> {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
Utils.toast(context, "已经点过赞啦!");
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
@ -301,7 +313,7 @@ public class CommentUtils {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if ("voted".equals(detail)) {
Utils.toast(context, "已经点过赞啦!");
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
}
} catch (Exception ex) {
ex.printStackTrace();
@ -421,7 +433,7 @@ public class CommentUtils {
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
Utils.toast(context, "复制成功");
ToastUtils.INSTANCE.showToast("复制成功");
}

View File

@ -3,6 +3,7 @@ package com.gh.common.util;
import android.content.Context;
import android.os.Build;
import com.gh.common.constant.Constants;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.NewsDetailEntity;
import com.gh.gamecenter.manager.DataCollectionManager;
@ -12,6 +13,8 @@ import com.lightgame.download.DownloadEntity;
import java.util.HashMap;
import java.util.Map;
import kotlin.text.StringsKt;
/**
* Created by LGT on 2016/12/9.
* 数据收集 工具类data.ghzs666.com
@ -31,8 +34,8 @@ public class DataCollectionUtils {
// 上传下载数据(开始、完成)
public static void uploadDownload(Context context, DownloadEntity downloadEntity, String status) {
Map<String, Object> map = new HashMap<>();
map.put("game", downloadEntity.getName());
map.put("game_id", downloadEntity.getGameId());
map.put("game", StringsKt.removeSuffix(downloadEntity.getName(), Constants.GAME_NAME_DECORATOR));
map.put("game_id", downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER));
if (downloadEntity.isPluggable()) {
map.put("method", "插件化");
map.put("btn_status", "插件化");

View File

@ -215,6 +215,8 @@ object DirectUtils {
"anliwall" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
//"h5_game_center" -> directLetoGameCenter(context)
"" -> {
// do nothing
}
@ -245,6 +247,7 @@ object DirectUtils {
/**
* 跳转至专题合集
*/
@JvmStatic
fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String, columnName: String = "") {
context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance, columnName))
}
@ -647,4 +650,70 @@ object DirectUtils {
context.startActivity(intent)
}
}
/**
* 跳转梦工厂小游戏
*/
/*@JvmStatic
fun directLetoGameCenter(context: Context) {
if (UserManager.getInstance().isLoggedIn) {
UserManager.getInstance().userInfoEntity?.run {
MgcAccountManager.syncAccount(context, if (idCard != null) idCard!!.name else name, mobile, name, icon, true,
object : SyncUserInfoListener {
override fun onSuccess(data: LoginResultBean?) {}
override fun onFail(code: String?, message: String?) {}
})
}
} else {
MgcAccountManager.exitAccount(context, object : SyncUserInfoListener {
override fun onSuccess(data: LoginResultBean?) {}
override fun onFail(code: String?, message: String?) {}
})
}
Leto.getInstance().startGameCenter(context)
}*/
/**
* 跳转分类
*/
@JvmStatic
fun directCategoryDirectory(context: Context, categoryId: String, categoryTitle: String, entrance: String? = null, path: String? = "") {
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 directAskColumnLabelDetail(context: Context, tag: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
val bundle = Bundle()
bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
bundle.putString(KEY_ASK_TAG, tag)
bundle.putParcelable(KEY_COMMUNITY_DATA, community)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
/**
* 跳转到专栏详情
*/
@JvmStatic
fun directAskColumnDetail(context: Context, columnId: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
val bundle = Bundle()
bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
bundle.putString(KEY_COLUMN_ID, columnId)
bundle.putParcelable(KEY_COMMUNITY_DATA, community)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
}

View File

@ -206,6 +206,13 @@ public class DisplayUtils {
public static void setStatusBarColor(Activity activity, int color, boolean lightStatusBar) {
Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (!isMiuiOs()) {
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
}
window.setStatusBarColor(ContextCompat.getColor(activity, color));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@ -250,6 +257,20 @@ public class DisplayUtils {
return false;
}
public static int getScreenWidth() {
WindowManager manager = (WindowManager) HaloApp.getInstance().getApplication().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
return metrics.widthPixels;
}
public static int getScreenHeight() {
WindowManager manager = (WindowManager) HaloApp.getInstance().getApplication().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
return metrics.heightPixels;
}
public static boolean hasSoftKeys(Context context) {
if (!(context instanceof Activity)) return false;

View File

@ -8,18 +8,12 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.history.HistoryHelper;
import com.gh.common.repository.ReservationRepository;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
@ -40,6 +34,12 @@ import com.lightgame.utils.Utils;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
/**
* todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
*/
@ -426,7 +426,15 @@ public class DownloadItemUtils {
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), "play".equals(gameEntity.getH5Link().getType()));
LinkEntity linkEntity = gameEntity.getH5Link();
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity);
}
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay);
context.startActivity(i);
});
} else if (gameEntity.getApk().size() == 1) {
@ -456,6 +464,7 @@ public class DownloadItemUtils {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
traceEvent,
entrance,
location);
});
@ -513,7 +522,7 @@ public class DownloadItemUtils {
MtaHelper.onEvent("我的游戏_启动", "插件化", gameEntity.getName());
}
if (gameEntity.getPluggableCollection() != null) {
DownloadDialog.showDownloadDialog(context, gameEntity, entrance, location);
DownloadDialog.showDownloadDialog(context, gameEntity, traceEvent, entrance, location);
} else {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
@ -557,9 +566,7 @@ public class DownloadItemUtils {
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "下载");
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, isSubscribe, downloadExposureEvent);
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, isSubscribe, traceEvent);
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
downloadBtn.setText(R.string.downloading);
@ -578,9 +585,7 @@ public class DownloadItemUtils {
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "插件化");
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.PLUGIN_DOWNLOAD);
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, downloadExposureEvent);
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent);
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
downloadBtn.setText(R.string.downloading);
@ -617,12 +622,8 @@ public class DownloadItemUtils {
private static void update(Context context, GameEntity gameEntity, String entrance, String location, boolean isSubscribe, @Nullable ExposureEvent traceEvent) {
ApkEntity apkEntity = gameEntity.getApk().get(0);
ExposureUtils.DownloadType downloadType = ExposureUtils.getUpdateType(apkEntity);
DataUtils.onGameUpdateEvent(context, gameEntity.getName(), apkEntity.getPlatform(), "下载开始");
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity
.getPlatform(), traceEvent, downloadType);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, downloadExposureEvent);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, traceEvent);
}
}

View File

@ -38,11 +38,13 @@ object DownloadObserver {
private val mApplication = HaloApp.getInstance().application
// 如果在WIFI状态下,下载自动暂停,则再重试一遍
@JvmStatic
fun initObserver() {
val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
val gameId = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
val downloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
if (downloadEntity.status != DownloadStatus.downloading) {
LogUtils.uploadDownloadEvent(downloadEntity)
@ -61,7 +63,7 @@ object DownloadObserver {
// 404 Not Found
// 删除任务
downloadEntity.status = DownloadStatus.cancel
DownloadManager.getInstance(mApplication).cancel(downloadEntity.url)
downloadManager.cancel(downloadEntity.url)
Utils.toast(mApplication, "该链接已失效!请联系管理员。")
MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
@ -76,13 +78,25 @@ object DownloadObserver {
}, null)
return
} else if (DownloadStatus.neterror == downloadEntity.status || DownloadStatus.timeout == downloadEntity.status) {
if (downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD].isNullOrEmpty()
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD] = downloadEntity.progress.toString()
downloadManager.updateDownloadEntity(downloadEntity)
downloadManager.startDownload(downloadEntity.url)
debugOnly {
Utils.log("DownloadObserver", "下载重试->" + downloadEntity.toJson())
}
} else {
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
"游戏", downloadEntity.name,
"平台", downloadEntity.platform)
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
"游戏", downloadEntity.name,
"平台", downloadEntity.platform)
debugOnly {
Utils.log("DownloadObserver", "下载自动暂停->" + downloadEntity.toJson())
}
}
}
if (DownloadStatus.done == downloadEntity.status) {
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
@ -112,7 +126,7 @@ object DownloadObserver {
if (PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(SettingsFragment.AUTO_INSTALL_SP_KEY, true)) {
if (FileUtils.isEmptyFile(downloadEntity.path)) {
Utils.toast(mApplication, R.string.install_failure_hint)
DownloadManager.getInstance(mApplication).cancel(downloadEntity.url)
downloadManager.cancel(downloadEntity.url)
} else {
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
@ -148,6 +162,13 @@ object DownloadObserver {
}
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
// 如果已下载大小发生变化,表示成功恢复下载,则重置重试标记
if (downloadEntity.status == DownloadStatus.downloading &&
downloadEntity.progress.toString() != downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD]) {
downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD] = ""
downloadManager.updateDownloadEntity(downloadEntity)
}
}
}
@ -203,7 +224,7 @@ object DownloadObserver {
}
ExposureUtils.logADownloadCompleteExposureEvent(
GameEntity(downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), downloadEntity.name),
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR)),
downloadEntity.platform,
downloadEntity.exposureTrace,
type)

View File

@ -4,6 +4,8 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.gh.common.avoidcallback.AvoidOnResultManager;
import com.gh.common.avoidcallback.Callback;
import com.gh.gamecenter.MainActivity;
@ -11,8 +13,6 @@ import com.gh.gamecenter.NormalActivity;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.normal.NormalFragment;
import androidx.appcompat.app.AppCompatActivity;
/**
* @author CsHeng
* @Date 2017/4/25
@ -37,6 +37,10 @@ public class EntranceUtils {
public static final String HOST_VIDEO_COLLECTION = "video_collection";//视频合集
public static final String HOST_USERHOME = "userhome";//个人主页
public static final String HOST_VIDEO = "video";
public static final String HOST_CATEGORY = "category";//分类
public static final String HOST_COLUMN_COLLECTION = "column_collection";//专题合集
public static final String HOST_COMMUNITY_QUESTION_LABEL_DETAIL = "community_question_label_detail";//问题标签详情
public static final String HOST_COMMUNITY_COLUMN_DETAIL = "community_column_detail";//专栏详情
public static final String HOST_COMMUNITY_ARTICLE = "community_article";
public static final String HOST_COMMUNITY_COLUMN = "community_column";
public static final String HOST_GAME = "game";
@ -154,6 +158,9 @@ public class EntranceUtils {
public static final String KEY_COLUMNNAME = "columnName";
public static final String KEY_QA_ID = "qaId";
public static final String KEY_QA_COLLECTION_ID = "qaCollectionId";
public static final String KEY_SHOW_EDIT_DRAFT = "showEditDraft";
public static final String KEY_ARTICLE_OPEN_IN_NEW_PAGE = "openArticleInNewPage";
public static final String KEY_ONLY_CREATE_DRAFT = "onlyCreateDraft";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -289,7 +289,7 @@ fun String.copyTextAndToast(toastText: String = "复制成功") {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cmb.text = this
Utils.toast(application, toastText)
ToastUtils.showToast(toastText)
}
fun Map<String, String>.createRequestBody(): RequestBody {
@ -461,6 +461,22 @@ fun SimpleDraweeView.display(url: String) {
ImageUtils.display(this, url)
}
/**
* Process related
*/
fun Context.doOnMainProcessOnly(callback: EmptyCallback) {
doOnMainProcessOnly { callback.onCallback() }
}
inline fun Context.doOnMainProcessOnly(f: () -> Unit) {
val processName = PackageUtils.obtainProcessName(this)
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
f.invoke()
} else {
Utils.log("Block one useless sub process method call.")
}
}
/**
* 测试用包裹
*/
@ -480,15 +496,15 @@ inline fun testChannelOnly(f: () -> Unit) {
* 倒计时单位s
*/
inline fun countDownTimer(
millisUntilFinish: Long,
crossinline block: (finish: Boolean, millisUntilFinished: Long) -> Unit
timeInSeconds: Long,
crossinline block: (finish: Boolean, remainingTime: Long) -> Unit
): Disposable {
var subscribe: Disposable? = null
subscribe = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it < millisUntilFinish) {
block.invoke(false, millisUntilFinish - it)
if (it < timeInSeconds) {
block.invoke(false, timeInSeconds - it)
} else {
block.invoke(true, 0)
if (subscribe != null && !subscribe!!.isDisposed) {

View File

@ -110,7 +110,7 @@ public class GameUtils {
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(context, apkEntity.getPackageName())
&& !PackageUtils.isSignedByGh(context, apkEntity.getPackageName())
&& apkEntity.isShowPlugin(pluginLocation)) {
pluginCount++;
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {

View File

@ -36,9 +36,10 @@ public class GameViewUtils {
public static void setLabelList(Context context, LinearLayout labelLayout, List<TagStyleEntity> tagStyle) {
labelLayout.removeAllViews();
if (tagStyle == null || tagStyle.isEmpty()) {
TagStyleEntity tagEntity = new TagStyleEntity();
tagEntity.setName("官方版");
labelLayout.addView(getNewGameTagView(context, tagEntity, 0));
// 没有数据的话默认不显示
// TagStyleEntity tagEntity = new TagStyleEntity();
// tagEntity.setName("官方版");
// labelLayout.addView(getNewGameTagView(context, tagEntity, 0));
} else {
for (int i = 0, size = tagStyle.size(); i < size; i++) {
View view = getNewGameTagView(context, tagStyle.get(i), i == size - 1 ? 0 : DisplayUtils.dip2px(context, 8));

View File

@ -67,7 +67,7 @@ public class InstallUtils {
String installVersion = PackageUtils.getVersionByPackage(packageName);
if (!TextUtils.isEmpty(installVersion) && downloadEntity != null &&
installVersion.equals(downloadEntity.getVersionName())) {
if (!downloadEntity.isPluggable() || PackageUtils.isSignature(context, packageName)) {
if (!downloadEntity.isPluggable() || PackageUtils.isSignedByGh(context, packageName)) {
EventBus.getDefault().post(new EBPackage("安装", packageName, installVersion));
}
}

View File

@ -1,6 +1,13 @@
package com.gh.common.util;
import android.text.TextUtils;
import com.lightgame.utils.Utils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
@ -75,4 +82,61 @@ public class MD5Utils {
return bigInt.toString(16);
}
public static boolean checkMD5(String md5, File updateFile) {
if (TextUtils.isEmpty(md5) || updateFile == null) {
Utils.log("MD5 string empty or updateFile null");
return false;
}
String calculatedDigest = calculateMD5(updateFile);
if (calculatedDigest == null) {
Utils.log("calculatedDigest null");
return false;
}
Utils.log("Calculated digest: " + calculatedDigest);
Utils.log("Provided digest: " + md5);
return calculatedDigest.equalsIgnoreCase(md5);
}
public static String calculateMD5(File updateFile) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (Exception e) {
Utils.log("Exception while getting digest", e);
return null;
}
InputStream is;
try {
is = new FileInputStream(updateFile);
} catch (Exception e) {
Utils.log("Exception while getting FileInputStream", e);
return null;
}
byte[] buffer = new byte[8192];
int read;
try {
while ((read = is.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String output = bigInt.toString(16);
// Fill to 32 chars
output = String.format("%32s", output).replace(' ', '0');
return output;
} catch (Exception e) {
throw new RuntimeException("Unable to process file for MD5", e);
} finally {
try {
is.close();
} catch (Exception e) {
Utils.log("Exception on closing MD5 input stream", e);
}
}
}
}

View File

@ -146,6 +146,8 @@ public class NetworkUtils {
return "3G";
case TelephonyManager.NETWORK_TYPE_LTE:
return "4G";
case 20://暂未适配AndroidQ这里粗暴设置为20
return "5G";
default:
return "unknown";
}

View File

@ -11,6 +11,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@ -117,64 +118,23 @@ public class NewsUtils {
* 设置新闻发布时间
*/
public static void setNewsPublishOn(TextView textView, long time) {
time = time * 1000;
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
if (time >= today && time < today + 86400 * 1000) {
format.applyPattern("HH:mm");
textView.setText(format.format(time));
} else if (time >= today - 86400 * 1000 && time < today) {
format.applyPattern("HH:mm");
textView.setText(String.format("昨天 %s", format.format(time)));
} else {
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("yyyy年MM月dd日 HH:mm");
textView.setText(format.format(time));
}
CommentUtils.setCommentTime(textView, time);
}
public static void setNewsDetailTime(TextView textView, long time) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
long day = time * 1000;
if (day >= today && day < today + 86400 * 1000) {
long min = new Date().getTime() / 1000 - day / 1000;
int hour = (int) (min / (60 * 60));
if (hour == 0) {
if (min < 60) {
textView.setText("刚刚");
} else {
textView.setText(String.format(Locale.getDefault(), "%d分钟前", (int) (min / 60)));
}
} else {
textView.setText(String.format(Locale.getDefault(), "%d小时前", hour));
}
} else if (day >= today - 86400 * 1000 * 100 && day < today) {
format.applyPattern("HH:mm");
textView.setText("昨天 ");
} else {
format.applyPattern("yyyy-MM-dd");
textView.setText(format.format(day));
}
} catch (ParseException e) {
e.printStackTrace();
format.applyPattern("yyyy-MM-dd");
textView.setText(format.format(time * 1000));
}
CommentUtils.setCommentTime(textView, time);
}
public static String getFormattedTime(long time) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
try {
long today = format.parse(format.format(new Date())).getTime();
long day = time * 1000;
String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
format.applyPattern("yyyy");
String currentYear = format.format(day);
format.applyPattern("yyyyMMdd");
long today = format.parse(format.format(new Date())).getTime();
if (day >= today && day < today + 86400 * 1000) {
long min = new Date().getTime() / 1000 - day / 1000;
int hour = (int) (min / (60 * 60));
@ -190,6 +150,13 @@ public class NewsUtils {
} else if (day >= today - 86400 * 1000 && day < today) {
format.applyPattern("HH:mm");
return ("昨天 ");
} else if (day >= today - 86400 * 1000 * 7 && day < today - 86400 * 1000) {
format.applyPattern("HH:mm");
long days = (today - day) / 86400000 + 1;
return String.format(Locale.getDefault(), "%d天前 ", days);
} else if (day < today - 86400 * 1000 * 7 && year.equals(currentYear)) {
format.applyPattern("MM-dd");
return (format.format(day));
} else {
format.applyPattern("yyyy-MM-dd");
return (format.format(day));

View File

@ -1,5 +1,6 @@
package com.gh.common.util;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
@ -51,7 +52,7 @@ public class PackageUtils {
/*
* 判断是否可以更新只判断gh_version的大小
*/
public static List<GameUpdateEntity> getUpdateData(Context context, GameEntity gameEntity) {
public static List<GameUpdateEntity> getUpdateData(GameEntity gameEntity) {
List<GameUpdateEntity> updateList = new ArrayList<>();
@ -88,14 +89,14 @@ public class PackageUtils {
String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName());
// 是否需要显示更新
boolean shouldShouldUpdate = apkEntity.getForce();
boolean shouldShowUpdate = apkEntity.getForce();
if (shouldShouldUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
// 根据版本判断是否需要更新
shouldShouldUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
if (shouldShouldUpdate) {
if (shouldShowUpdate) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
@ -153,7 +154,7 @@ public class PackageUtils {
/*
* 判断是否是插件包
*/
public static boolean isSignature(Context context, String packageName) {
public static boolean isSignedByGh(Context context, String packageName) {
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
@ -349,6 +350,8 @@ public class PackageUtils {
/*
* 根据包名,判断是否已安装该游戏
*
* 注意目测只对能启动的app有效(有桌面图标),对一些没有桌面图标的应用无效(参考应用:魅族游戏框架)
*/
public static boolean isInstalled(Context context, String packageName) {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
@ -502,7 +505,7 @@ public class PackageUtils {
/**
* todo 统一判断
* <p>
* 判断游戏包是否可以更新
* 判断游戏包(插件包) 是否可以更新
*
* @param apkEntity apkEntity 必须是已安装的游戏
* @param gameId 游戏id
@ -547,6 +550,26 @@ public class PackageUtils {
return PackageUtils.isInstalled(HaloApp.getInstance().getApplication(), apkEntity.getPackageName())
&& gh_id == null
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
&& !PackageUtils.isSignedByGh(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
}
/**
* 获取调用者的进程名
* @param context 调用者的上下文
* @return 进程名
*/
public static String obtainProcessName(Context context) {
final int pid = android.os.Process.myPid();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
if (info != null && info.pid == pid) {
return info.processName;
}
}
}
return null;
}
}

View File

@ -20,6 +20,8 @@ import org.json.JSONObject
import java.io.File
import java.net.URLEncoder
import java.util.*
import kotlin.collections.HashMap
import java.lang.Exception
object UploadImageUtils {
@ -109,6 +111,7 @@ object UploadImageUtils {
fun compressAndUploadImageList(type: UploadType, imgs: List<String>, compressGif: Boolean, listener: OnUploadImageListListener): Disposable? {
var subscription: Disposable? = null
val postImageList = LinkedHashMap<String, String>()
val errorMap = HashMap<String, Exception>()
Observable.create(ObservableOnSubscribe<Map<String, String>> {
val compressList = compressImageList(imgs, compressGif)
@ -145,11 +148,13 @@ object UploadImageUtils {
onFailure(IllegalAccessException("HeHe"))
}
override fun onFailure(exception: Exception) {
// 若遇到错误且 subscription?.isDisposed 为 true 时会抛出 io.reactivex.exceptions.UndeliverableException 异常
// if (subscription?.isDisposed == true) return
// it.onError(exception) // fuck
it.onNext(Collections.emptyMap())
// it.onNext(Collections.emptyMap())
errorMap[img.path] = exception
}
})
listProgress += img.length()
@ -165,18 +170,18 @@ object UploadImageUtils {
override fun onComplete() {
if (postImageList.size == 0) {
listener.onError()
listener.onError(errorMap)
} else {
listener.onSuccess(postImageList)
listener.onSuccess(postImageList, errorMap)
}
}
override fun onNext(t: Map<String, String>) {
if (!t.isEmpty()) postImageList.putAll(t)
if (t.isNotEmpty()) postImageList.putAll(t)
}
override fun onError(e: Throwable) {
e.printStackTrace()
override fun onError(ignore: Throwable) {
}
})
return subscription
@ -285,8 +290,8 @@ object UploadImageUtils {
}
interface OnUploadImageListListener {
fun onSuccess(imageUrl: LinkedHashMap<String, String>) // key:sourceImage value:compressImage
fun onError() // 全部上传失败时回调
fun onSuccess(imageUrl: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) // key:sourceImage value:compressImage
fun onError(errorMap: Map<String, Exception>) // 全部上传失败时回调
fun onProgress(total: Long, progress: Long)
}

View File

@ -3,17 +3,18 @@ package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.*
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
import com.gh.common.util.DisplayUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.rxTimer
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SettingsEntity
import com.squareup.picasso.Picasso
import io.reactivex.disposables.Disposable
import kotlin.math.abs
@ -190,7 +191,7 @@ class AdBannerView : LinearLayout {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val ad = mDatas[position % mDatas.size]
val view = holder.itemView as SimpleDraweeView
ImageUtils.display(view, ad.image)
ImageUtils.display(view,ad.image)
holder.itemView.setOnClickListener {
onItemClick?.invoke(position % mDatas.size)
}

View File

@ -2,6 +2,7 @@ package com.gh.common.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Build;
import android.text.Layout;
import android.text.SpannableStringBuilder;
@ -11,45 +12,59 @@ import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import com.gh.common.util.DisplayUtils;
import com.gh.gamecenter.R;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
public class ExpandTextView extends AppCompatTextView {
private CharSequence mSnapshotText;
private String mEndText = "...";
private String mExpandText = mEndText + "全文";
private boolean mUseGradientAlphaEndText = false;
private int mMaxLines = 3; // 由于sdk版本限制(getMaxLines) 这里设置默认值
private static int DEFAULT_ADDITIONAL_END_TEXT_COUNT = 2;
private boolean mInitLayout = false;
private boolean mIsExpanded = false; // 位于 recyclerView 时需要自行在外层管理是否已展开
private ExpandCallback mExpandCallback;
private Rect mLastVisibleLineRect;
private Rect mLastActualLineRect;
public ExpandTextView(Context context) {
super(context);
}
public ExpandTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mMaxLines = getMaxLines();
}
mLastVisibleLineRect = new Rect();
mLastActualLineRect = new Rect();
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandTextView);
mUseGradientAlphaEndText = ta.getBoolean(R.styleable.ExpandTextView_useGradientAlphaEndText, false);
mEndText = ta.getString(R.styleable.ExpandTextView_endText) == null ? mEndText : ta.getString(R.styleable.ExpandTextView_endText);
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta.getString(R.styleable.ExpandTextView_expandText);
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta
.getString(R.styleable.ExpandTextView_expandText);
ta.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() - getExtraBottomPadding());
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@ -59,123 +74,162 @@ public class ExpandTextView extends AppCompatTextView {
showExpandButton();
}
}
public void setExpendText(String text) {
this.mExpandText = text;
}
public void setExpandCallback(ExpandCallback callback) {
this.mExpandCallback = callback;
}
@Override
public void setText(CharSequence text, BufferType type) {
mInitLayout = true;
super.setText(text, type);
}
private void showExpandButton() {
String finalEndText = "";
TextPaint paint = getPaint();
Layout layout = getLayout();
int start = layout.getLineStart(0);
int lastLineEnd = layout.getLineEnd(mMaxLines - 1);
int lastLineStart = layout.getLineStart(mMaxLines - 1);
float lastLineRight = layout.getLineRight(mMaxLines - 1);
int viewWidth = getWidth() - getPaddingRight() - getPaddingLeft();
int additionalEndTextCount = 0;
TextPaint paint = getPaint();
float expandTextWidth;
if (mUseGradientAlphaEndText) {
additionalEndTextCount = DEFAULT_ADDITIONAL_END_TEXT_COUNT;
// 如果不加多个括号的话有可能算不对,惊了,明明是同样的 paint 同样的文字,长度却会略有不同
expandTextWidth = paint.measureText(mEndText + mExpandText + " ");
expandTextWidth = paint.measureText(mEndText + mExpandText);
} else {
expandTextWidth = paint.measureText(mExpandText);
}
CharSequence content = mSnapshotText.subSequence(start, lastLineEnd);
if (viewWidth - lastLineRight > expandTextWidth) {
if (mUseGradientAlphaEndText) {
finalEndText = content.toString().substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
finalEndText = content.toString()
.substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
finalEndText = finalEndText.replace("\n", "");
content = content.subSequence(0, content.length() - additionalEndTextCount) + finalEndText + mExpandText;
} else {
content = content.toString().trim() + mExpandText;
}
} else {
CharSequence lastText = mSnapshotText.subSequence(lastLineStart, lastLineEnd);
for (int i = lastText.length() - 1; i > 0; i--) {
CharSequence sequence = lastText.subSequence(0, i);
float w = paint.measureText(sequence.toString());
if (viewWidth - w - DisplayUtils.dip2px(5) > expandTextWidth) {
if (mUseGradientAlphaEndText) {
finalEndText = lastText.subSequence(i - additionalEndTextCount, i) + mEndText;
CharSequence lastLineText = mSnapshotText.subSequence(lastLineStart, lastLineEnd);
CharSequence subSequence;
float subSequenceWidth;
for (int i = lastLineText.length() - 1; i > 0; i--) {
if (mUseGradientAlphaEndText) {
subSequence = lastLineText.subSequence(0, i - additionalEndTextCount);
subSequenceWidth = paint.measureText(subSequence.toString());
finalEndText = lastLineText.subSequence(i - additionalEndTextCount, i) + mEndText;
expandTextWidth = paint.measureText(finalEndText + mExpandText);
if (viewWidth - subSequenceWidth > expandTextWidth) {
finalEndText = finalEndText.replace("\n", "");
content = mSnapshotText.subSequence(start, lastLineStart + i - additionalEndTextCount) + finalEndText + mExpandText;
} else {
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
break;
}
} else {
subSequence = lastLineText.subSequence(0, i);
subSequenceWidth = paint.measureText(subSequence.toString());
if (viewWidth - subSequenceWidth > expandTextWidth) {
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
break;
}
break;
}
}
}
SpannableStringBuilder msp = new SpannableStringBuilder(mSnapshotText);
int length = msp.length();
int startPosition = 0;
int startPosition;
startPosition = content.length() - finalEndText.length() - mExpandText.length();
startPosition = Math.max(startPosition, 0);
// 避免越界
if (startPosition >= length) return;
msp.replace(startPosition, length, finalEndText + mExpandText);
msp.setSpan(new ClickableSpan() {
@Override
public void updateDrawState(TextPaint ds) {
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(ContextCompat.getColor(getContext(), R.color.theme_font));
ds.setUnderlineText(false);
}
@Override
public void onClick(View widget) {
public void onClick(@NonNull View widget) {
mIsExpanded = true;
setMaxLines(Integer.MAX_VALUE);
setText(mSnapshotText);
if (mExpandCallback != null) {
mExpandCallback.onExpand();
}
}
}, startPosition + mEndText.length(), msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
msp.setSpan(new GradientAlphaTextSpan(), startPosition, startPosition + finalEndText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(msp);
setMovementMethod(CustomLinkMovementMethod.getInstance());
}
/**
* 获取 maxLines + lineSpacingExtra + movementMethod 一起使用时产生的大小与 lineSpacingExtra 一样的底部空间
*/
private int getExtraBottomPadding() {
int result = 0;
// 界面上显示的最后一行的 index
int lastVisibleLineIndex = Math.min(getMaxLines(), getLineCount()) - 1;
// 获取实际文字的最后一行的 index
int lastActualLineIndex = getLineCount() - 1;
if (lastVisibleLineIndex >= 0) {
Layout layout = getLayout();
int lastVisibleLineBaseline = getLineBounds(lastVisibleLineIndex, mLastVisibleLineRect);
getLineBounds(lastActualLineIndex, mLastActualLineRect);
int heightBetweenLastVisibleLineRectAndLastActualLineRect = (mLastActualLineRect.bottom - mLastVisibleLineRect.bottom);
if (getMeasuredHeight() == getLayout().getHeight() - heightBetweenLastVisibleLineRectAndLastActualLineRect) {
result = mLastVisibleLineRect.bottom - (lastVisibleLineBaseline + layout.getPaint()
.getFontMetricsInt().descent + getPaddingBottom());
if (getLineSpacingExtra() > result) {
result = 0;
} else {
result = (int) getLineSpacingExtra();
}
}
}
return result;
}
/**
* 此方法仅更改标记,不做实际展开的操作
*/
public void setIsExpanded(boolean isExpanded) {
mIsExpanded = isExpanded;
}
public void setExpandMaxLines(int maxLines) {
mMaxLines = maxLines;
setMaxLines(maxLines);
}
public interface ExpandCallback {
void onExpand();
}
}

View File

@ -0,0 +1,790 @@
package com.gh.common.view;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.webkit.WebView;
import android.widget.OverScroller;
import android.widget.ScrollView;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.InputDeviceCompat;
import androidx.core.view.NestedScrollingChild2;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.NestedScrollingParent;
import androidx.core.view.NestedScrollingParentHelper;
import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import wendu.dsbridge.DWebView;
/**
* Copyright (c) Tuenti Technologies. All rights reserved.
* <p>
* WebView compatible with CoordinatorLayout.
* The implementation based on NestedScrollView of design library
*/
public class NestedScrollWebView2 extends DWebView implements NestedScrollingChild2, NestedScrollingParent {
private static final int INVALID_POINTER = -1;
private static final String TAG = "NestedWebView";
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private int mLastMotionY;
private NestedScrollingParentHelper mParentHelper;
private NestedScrollingChildHelper mChildHelper;
private boolean mIsBeingDragged = false;
private VelocityTracker mVelocityTracker;
private int mTouchSlop;
private int mActivePointerId = INVALID_POINTER;
private int mNestedYOffset;
private OverScroller mScroller;
private int mMinimumVelocity;
private int mMaximumVelocity;
private static final AccessibilityDelegate ACCESSIBILITY_DELEGATE = new AccessibilityDelegate();
public NestedScrollWebView2(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public NestedScrollWebView2(Context context) {
super(context);
init();
}
private void init(){
setOverScrollMode(WebView.OVER_SCROLL_NEVER);
initScrollView();
mChildHelper = new NestedScrollingChildHelper(this);
mParentHelper = new NestedScrollingParentHelper(this);
setNestedScrollingEnabled(true);
ViewCompat.setAccessibilityDelegate(this, ACCESSIBILITY_DELEGATE);
}
private void initScrollView() {
mScroller = new OverScroller(getContext());
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (disallowIntercept) {
recycleVelocityTracker();
}
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
return true;
}
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
break;
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + activePointerId
+ " in onInterceptTouchEvent");
break;
}
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop
&& (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0) {
mIsBeingDragged = true;
mLastMotionY = y;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
mNestedYOffset = 0;
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
mLastMotionY = y;
mActivePointerId = ev.getPointerId(0);
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
mScroller.computeScrollOffset();
mIsBeingDragged = !mScroller.isFinished();
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0, getScrollRange())) {
ViewCompat.postInvalidateOnAnimation(this);
}
stopNestedScroll();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
return mIsBeingDragged;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean returnValue = false;
initVelocityTrackerIfNotExists();
MotionEvent vtev = MotionEvent.obtain(ev);
final int actionMasked = ev.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
mNestedYOffset = 0;
}
vtev.offsetLocation(0, mNestedYOffset);
switch (actionMasked) {
case MotionEvent.ACTION_DOWN: {
returnValue = super.onTouchEvent(ev);
if (mIsBeingDragged = !mScroller.isFinished()) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionY = (int) ev.getY();
mActivePointerId = ev.getPointerId(0);
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
break;
}
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
if (activePointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
break;
}
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset,
ViewCompat.TYPE_TOUCH)) {
deltaY -= mScrollConsumed[1];
ev.offsetLocation(0, -mScrollOffset[1]);
vtev.offsetLocation(0, -mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
}
boolean notMove = mScrollOffset[1] == 0;
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
mIsBeingDragged = true;
if (deltaY > 0) {
deltaY -= mTouchSlop;
} else {
deltaY += mTouchSlop;
}
}
if (mIsBeingDragged) {
mLastMotionY = y - mScrollOffset[1];
final int oldY = getScrollY();
final int range = getScrollRange();
int unconsumedY = 0;
int scrolledDeltaY = deltaY;
int expectScroll = oldY + deltaY;
if (expectScroll < 0) {
unconsumedY = expectScroll;
scrolledDeltaY = oldY;
} else if (expectScroll > range) {
unconsumedY = range - expectScroll;
scrolledDeltaY = expectScroll - range;
}
if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset,
ViewCompat.TYPE_TOUCH)) {
vtev.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
mLastMotionY -= mScrollOffset[1];
}
}
notMove &= (mScrollOffset[1] == 0);
if (notMove) {
returnValue = super.onTouchEvent(ev);
} else {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
break;
case MotionEvent.ACTION_UP:
if (Math.abs(mNestedYOffset) < mTouchSlop) {
returnValue = super.onTouchEvent(ev);
} else {
ev.setAction(MotionEvent.ACTION_CANCEL);
returnValue = super.onTouchEvent(ev);
}
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
flingWithNestedDispatch(-initialVelocity);
} else if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
getScrollRange())) {
ViewCompat.postInvalidateOnAnimation(this);
}
mActivePointerId = INVALID_POINTER;
endDrag();
break;
case MotionEvent.ACTION_CANCEL:
returnValue = true;
if (mIsBeingDragged && getChildCount() > 0) {
if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
getScrollRange())) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
mActivePointerId = INVALID_POINTER;
endDrag();
break;
case MotionEvent.ACTION_POINTER_DOWN: {
final int index = ev.getActionIndex();
mLastMotionY = (int) ev.getY(index);
mActivePointerId = ev.getPointerId(index);
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(vtev);
}
vtev.recycle();
return returnValue;
}
int getScrollRange() {
//Using scroll range of webview instead of childs as NestedScrollView does.
return computeVerticalScrollRange();
}
@Override
protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
super.scrollTo(scrollX, scrollY);
}
boolean overScrollByCompat(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
final int overScrollMode = getOverScrollMode();
final boolean canScrollHorizontal =
computeHorizontalScrollRange() > computeHorizontalScrollExtent();
final boolean canScrollVertical =
computeVerticalScrollRange() > computeVerticalScrollExtent();
final boolean overScrollHorizontal = overScrollMode == View.OVER_SCROLL_ALWAYS
|| (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
final boolean overScrollVertical = overScrollMode == View.OVER_SCROLL_ALWAYS
|| (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
int newScrollX = scrollX + deltaX;
if (!overScrollHorizontal) {
maxOverScrollX = 0;
}
int newScrollY = scrollY + deltaY;
if (!overScrollVertical) {
maxOverScrollY = 0;
}
// Clamp values if at the limits and record
final int left = -maxOverScrollX;
final int right = maxOverScrollX + scrollRangeX;
final int top = -maxOverScrollY;
final int bottom = maxOverScrollY + scrollRangeY;
boolean clampedX = false;
if (newScrollX > right) {
newScrollX = right;
clampedX = true;
} else if (newScrollX < left) {
newScrollX = left;
clampedX = true;
}
boolean clampedY = false;
if (newScrollY > bottom) {
newScrollY = bottom;
clampedY = true;
} else if (newScrollY < top) {
newScrollY = top;
clampedY = true;
}
if (clampedY && !hasNestedScrollingParent(ViewCompat.TYPE_NON_TOUCH)) {
mScroller.springBack(newScrollX, newScrollY, 0, 0, 0, getScrollRange());
}
onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
return clampedX || clampedY;
}
private float mVerticalScrollFactor;
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL: {
if (!mIsBeingDragged) {
final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
if (vscroll != 0) {
final int delta = (int) (vscroll * getVerticalScrollFactorCompat());
final int range = getScrollRange();
int oldScrollY = getScrollY();
int newScrollY = oldScrollY - delta;
if (newScrollY < 0) {
newScrollY = 0;
} else if (newScrollY > range) {
newScrollY = range;
}
if (newScrollY != oldScrollY) {
super.scrollTo(getScrollX(), newScrollY);
return true;
}
}
}
}
}
}
return false;
}
private float getVerticalScrollFactorCompat() {
if (mVerticalScrollFactor == 0) {
TypedValue outValue = new TypedValue();
final Context context = getContext();
if (!context.getTheme().resolveAttribute(
android.R.attr.listPreferredItemHeight, outValue, true)) {
throw new IllegalStateException(
"Expected theme to define listPreferredItemHeight.");
}
mVerticalScrollFactor = outValue.getDimension(
context.getResources().getDisplayMetrics());
}
return mVerticalScrollFactor;
}
private void endDrag() {
mIsBeingDragged = false;
recycleVelocityTracker();
stopNestedScroll();
}
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = ev.getActionIndex();
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
// TODO: Make this decision more intelligent.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastMotionY = (int) ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
}
}
private void initOrResetVelocityTracker() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
}
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
}
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
private void flingWithNestedDispatch(int velocityY) {
final int scrollY = getScrollY();
final boolean canFling = (scrollY > 0 || velocityY > 0)
&& (scrollY < getScrollRange() || velocityY < 0);
if (!dispatchNestedPreFling(0, velocityY)) {
dispatchNestedFling(0, velocityY, canFling);
fling(velocityY);
}
}
public void fling(int velocityY) {
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
mScroller.fling(getScrollX(), getScrollY(), // start
0, velocityY, // velocities
0, 0, // x
Integer.MIN_VALUE, Integer.MAX_VALUE, // y
0, 0); // overscroll
mLastScrollerY = getScrollY();
ViewCompat.postInvalidateOnAnimation(this);
}
private int mLastScrollerY;
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
final int x = mScroller.getCurrX();
final int y = mScroller.getCurrY();
int dy = y - mLastScrollerY;
// Dispatch up to parent
if (dispatchNestedPreScroll(0, dy, mScrollConsumed, null, ViewCompat.TYPE_NON_TOUCH)) {
dy -= mScrollConsumed[1];
}
if (dy != 0) {
final int range = getScrollRange();
final int oldScrollY = getScrollY();
overScrollByCompat(0, dy, getScrollX(), oldScrollY, 0, range, 0, 0, false);
final int scrolledDeltaY = getScrollY() - oldScrollY;
final int unconsumedY = dy - scrolledDeltaY;
if (!dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, null,
ViewCompat.TYPE_NON_TOUCH)) {
final int mode = getOverScrollMode();
final boolean canOverscroll = mode == OVER_SCROLL_ALWAYS
|| (mode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
if (canOverscroll) {
// ensureGlows();
// if (y <= 0 && oldScrollY > 0) {
// mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
// } else if (y >= range && oldScrollY < range) {
// mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
// }
}
}
}
// Finally update the scroll positions and post an invalidation
mLastScrollerY = y;
ViewCompat.postInvalidateOnAnimation(this);
} else {
// We can't scroll any more, so stop any indirect scrolling
if (hasNestedScrollingParent(ViewCompat.TYPE_NON_TOUCH)) {
stopNestedScroll(ViewCompat.TYPE_NON_TOUCH);
}
// and reset the scroller y
mLastScrollerY = 0;
}
}
@Override
public boolean isNestedScrollingEnabled() {
return mChildHelper.isNestedScrollingEnabled();
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean startNestedScroll(int axes) {
return mChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
int[] offsetInWindow) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
@Override
public int getNestedScrollAxes() {
return mParentHelper.getNestedScrollAxes();
}
@Override
public boolean startNestedScroll(int axes, int type) {
return mChildHelper.startNestedScroll(axes, type);
}
@Override
public void stopNestedScroll(int type) {
mChildHelper.stopNestedScroll(type);
}
@Override
public boolean hasNestedScrollingParent(int type) {
return mChildHelper.hasNestedScrollingParent(type);
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow, int type) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow, type);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow,
int type) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
}
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed) {
final int oldScrollY = getScrollY();
scrollBy(0, dyUnconsumed);
final int myConsumed = getScrollY() - oldScrollY;
final int myUnconsumed = dyUnconsumed - myConsumed;
dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
}
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
dispatchNestedPreScroll(dx, dy, consumed, null);
}
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
if (!consumed) {
flingWithNestedDispatch((int) velocityY);
return true;
}
return false;
}
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
return dispatchNestedPreFling(velocityX, velocityY);
}
// nested scroll parent
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
@Override
public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
mParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
}
@Override
public void onStopNestedScroll(View target) {
mParentHelper.onStopNestedScroll(target);
stopNestedScroll();
}
/**
* Like {@link #scrollTo}, but scroll smoothly instead of immediately.
*
* @param x the position where to scroll on the X axis
* @param y the position where to scroll on the Y axis
*/
public final void smoothScrollTo(int x, int y) {
smoothScrollBy(x - getScrollX(), y - getScrollY());
}
/**
* Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
*
* @param dx the number of pixels to scroll by on the X axis
* @param dy the number of pixels to scroll by on the Y axis
*/
private long mLastScroll;
static final int ANIMATED_SCROLL_GAP = 250;
public final void smoothScrollBy(int dx, int dy) {
long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
if (duration > ANIMATED_SCROLL_GAP) {
final int height = getHeight() - getPaddingBottom() - getPaddingTop();
final int bottom = getHeight();
final int maxY = Math.max(0, bottom - height);
final int scrollY = getScrollY();
dy = Math.max(0, Math.min(scrollY + dy, maxY)) - scrollY;
mScroller.startScroll(getScrollX(), scrollY, 0, dy);
ViewCompat.postInvalidateOnAnimation(this);
} else {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
scrollBy(dx, dy);
}
mLastScroll = AnimationUtils.currentAnimationTimeMillis();
}
static class AccessibilityDelegate extends AccessibilityDelegateCompat {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
if (super.performAccessibilityAction(host, action, arguments)) {
return true;
}
final NestedScrollWebView2 nsvHost = (NestedScrollWebView2) host;
if (!nsvHost.isEnabled()) {
return false;
}
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
final int viewportHeight = nsvHost.getHeight() - nsvHost.getPaddingBottom()
- nsvHost.getPaddingTop();
final int targetScrollY = Math.min(nsvHost.getScrollY() + viewportHeight,
nsvHost.getScrollRange());
if (targetScrollY != nsvHost.getScrollY()) {
nsvHost.smoothScrollTo(0, targetScrollY);
return true;
}
}
return false;
case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
final int viewportHeight = nsvHost.getHeight() - nsvHost.getPaddingBottom()
- nsvHost.getPaddingTop();
final int targetScrollY = Math.max(nsvHost.getScrollY() - viewportHeight, 0);
if (targetScrollY != nsvHost.getScrollY()) {
nsvHost.smoothScrollTo(0, targetScrollY);
return true;
}
}
return false;
}
return false;
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
final NestedScrollWebView2 nsvHost = (NestedScrollWebView2) host;
info.setClassName(ScrollView.class.getName());
if (nsvHost.isEnabled()) {
final int scrollRange = nsvHost.getScrollRange();
if (scrollRange > 0) {
info.setScrollable(true);
if (nsvHost.getScrollY() > 0) {
info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
}
if (nsvHost.getScrollY() < scrollRange) {
info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
}
}
}
}
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
final NestedScrollWebView2 nsvHost = (NestedScrollWebView2) host;
event.setClassName(ScrollView.class.getName());
final boolean scrollable = nsvHost.getScrollRange() > 0;
event.setScrollable(scrollable);
event.setScrollX(nsvHost.getScrollX());
event.setScrollY(nsvHost.getScrollY());
AccessibilityRecordCompat.setMaxScrollX(event, nsvHost.getScrollX());
AccessibilityRecordCompat.setMaxScrollY(event, nsvHost.getScrollRange());
}
}
/**
* Stop any current scroll
* #fling(int, int)} or a touch-initiated fling.
*/
public void stopScroll() {
if (mScroller != null) {
mScroller.forceFinished(true);
}
}
}

View File

@ -8,11 +8,10 @@ import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import com.gh.common.AppExecutor;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.history.HistoryHelper;
import com.gh.common.util.AppDebugConfig;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DeviceUtils;
@ -31,7 +30,6 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.packagehelper.PackageRepository;
import com.google.gson.Gson;
import com.halo.assistant.HaloApp;
import com.lightgame.config.CommonDebug;
import com.lightgame.download.ConnectionUtils;
import com.lightgame.download.DataChanger;
@ -56,11 +54,18 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.ProcessLifecycleOwner;
public class DownloadManager implements DownloadStatusListener {
private static DownloadManager mInstance;
private static Gson gson = new Gson();
private static final String HINT_MARK = "hint_mark";
private static final String UPDATE_IS_READ_MARK = "update_is_read";
private static final String DOWNLOADING_IS_READ_MARK = "downloading_is_read";
private static final String DOWNLOADED_IS_READ_MARK = "downloaded_is_read";
private Context mContext;
private Handler mHandler;
@ -131,7 +136,7 @@ public class DownloadManager implements DownloadStatusListener {
mContext = context.getApplicationContext();
mDownloadDao = DownloadDao.getInstance(mContext);
mUpdateMarks = SPUtils.getStringSet(HINT_MARK);
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
//TODO unregister this
DownloadStatusManager.getInstance().registerTaskStatusListener(this);
@ -147,6 +152,7 @@ public class DownloadManager implements DownloadStatusListener {
statusMap = new ArrayMap<>();
downloadingMap = new ArrayMap<>();
// TODO 这里的 handler 类的 case 可能会被多次调用,原因未知
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
@ -187,7 +193,6 @@ public class DownloadManager implements DownloadStatusListener {
downloadingMap.put(downloadEntity.getUrl(), downloadEntity);
}
}
}
public ArrayMap<String, DownloadEntity> getDownloadingMap() {
@ -224,21 +229,6 @@ public class DownloadManager implements DownloadStatusListener {
boolean isSubscribe,
@Nullable ExposureEvent traceEvent) {
// 安装指引
/*if ("Huawei".equalsIgnoreCase(MANUFACTURER) || "Oppo".equalsIgnoreCase(MANUFACTURER)) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor edit = sp.edit();
if (sp.getBoolean("InstallHint" + PackageUtils.getVersionName(), true)) {
try {
DialogUtils.showInstallHintDialog(context,
() -> edit.putBoolean("InstallHint" + PackageUtils.getVersionName(), false).apply());
} catch (Exception exception) {
exception.printStackTrace();
edit.putBoolean("InstallHint" + PackageUtils.getVersionName(), false).apply();
}
}
}*/
// 插件版本下载互斥弹窗
List<String> mutexPackage = gameEntity.getMutexPackage();
if (mutexPackage != null && mutexPackage.size() > 0) {
@ -261,7 +251,6 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setPackageName(apkEntity.getPackageName());
downloadEntity.setGameId(gameEntity.getId());
downloadEntity.setEntrance(entrance);
downloadEntity.setExposureTrace(gson.toJson(traceEvent));
downloadEntity.setLocation(location);
downloadEntity.setVersionName(apkEntity.getVersion());
int installed = 0;
@ -281,9 +270,16 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getPlatform(), traceEvent, downloadType);
// 将下载事件放入 downloadEntity 中供下载完成时取出使用
downloadEntity.setExposureTrace(gson.toJson(downloadExposureEvent));
if (isSubscribe) {
DownloadManager.getInstance(context).subscribe(downloadEntity);
} else {
HistoryHelper.insertGameEntity(gameEntity);
DownloadManager.getInstance(context).add(downloadEntity);
}
@ -294,6 +290,7 @@ public class DownloadManager implements DownloadStatusListener {
//TODO remove
DownloadManager.getInstance(context).putStatus(downloadEntity.getUrl(), DownloadStatus.downloading);
DownloadManager.getInstance(context).markDownloadingTaskAsUnread();
// 收集下载数据
DataCollectionUtils.uploadDownload(context, downloadEntity, "开始");
GdtHelper.INSTANCE.logAction(ActionType.DOWNLOAD_APP,
@ -631,7 +628,6 @@ public class DownloadManager implements DownloadStatusListener {
}
}
// 开启下载服务, Fuck me, 即便是在启动页调用的方法,依然有可能触发 `unable is in background`
startDownloadService();
checkRetryDownload();
}
@ -648,11 +644,11 @@ public class DownloadManager implements DownloadStatusListener {
private void startDownloadService() {
Intent serviceIntent = new Intent(mContext, DownloadService.class);
// 当满足系统版本大于 8.0 就以前台服务开启 DownloadService
// (因为即便在 SplashActivity 里初始化,也有可能报 not allowed to start service, app is in background 的错误)
// DownloadService 会调用 stopForeground 方法,理论上会去掉 `光环助手正在运行中` 的通知
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
// 当满足系统版本大于 8.0 并且进程处于 CREATED 状态 (ON_STOP后的状态) 的时候才以前台服务开启
// "not allowed to start service, app is in background" 的错误概率比 "startForegroundService() did not then call Service.startForeground() " 低
// 所以还是老老实实地以 startService 为主吧
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
mContext.startForegroundService(serviceIntent);
} else {
mContext.startService(serviceIntent);
@ -674,8 +670,7 @@ public class DownloadManager implements DownloadStatusListener {
Intent serviceIntent = getIntent(downloadEntity, status);
// 当满足系统版本大于 8.0 、应用在后台运行时以前台服务开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& !HaloApp.getInstance().isRunningForeground) {
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
mContext.startForegroundService(serviceIntent);
} else {
mContext.startService(serviceIntent);
@ -713,19 +708,26 @@ public class DownloadManager implements DownloadStatusListener {
*/
@Nullable
public String getDownloadOrUpdateCount(List<GameUpdateEntity> updateList) {
boolean containsReadDownloadingTask = false; // 存在已读的下载中任务
boolean showRedPoint = false;
int downloadingSize = 0;
for (DownloadEntity downloadEntity : getAll()) {
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
String mark = downloadEntity.getMeta().get(HINT_MARK);
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) showRedPoint = true;
} else {
// 存在已读的下载中任务就直接不返回下载中数量,因为在新建下载时就执行了将所有下载中任务的已读变为未读的操作
if (!TextUtils.isEmpty(downloadEntity.getMeta().get(DOWNLOADING_IS_READ_MARK))) {
containsReadDownloadingTask = true;
}
downloadingSize++;
}
}
if (downloadingSize != 0) return String.valueOf(downloadingSize);
if (downloadingSize != 0 && !containsReadDownloadingTask) {
return String.valueOf(downloadingSize);
}
if (showRedPoint) return "";
@ -740,6 +742,31 @@ public class DownloadManager implements DownloadStatusListener {
return null;
}
public int getUnreadUpdateCount(List<GameUpdateEntity> updateList) {
int unreadUpdateCount = 0;
if (updateList != null) {
for (GameUpdateEntity updateEntity : updateList) {
if (updateEntity.isShowPlugin(PluginLocation.only_index)
&& !mUpdateMarks.contains(updateEntity.getId() + updateEntity.getPackageName())) {
unreadUpdateCount++;
}
}
}
return unreadUpdateCount;
}
public boolean isContainsUnreadDownloadedTask() {
for (DownloadEntity downloadEntity : getAll()) {
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) {
return true;
}
}
}
return false;
}
/**
* 标记下载已完成的任务为已读 (用于下载管理页入口的 toolbar 红点显示)
*/
@ -751,9 +778,54 @@ public class DownloadManager implements DownloadStatusListener {
for (DownloadEntity downloadEntity : all) {
DownloadStatus status = downloadEntity.getStatus();
if (status == DownloadStatus.done) {
String mark = downloadEntity.getMeta().get(HINT_MARK);
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) {
downloadEntity.getMeta().put(HINT_MARK, HINT_MARK);
downloadEntity.getMeta().put(DOWNLOADED_IS_READ_MARK, DOWNLOADED_IS_READ_MARK);
mDownloadDao.newOrUpdate(downloadEntity);
if (!markHasChanged) markHasChanged = true;
}
}
}
if (markHasChanged) {
EventBus.getDefault().post(new EBDownloadStatus("download", "", "", "", "", ""));
}
});
}
/**
* 标记下载中任务为已读状态(用于下载页及外部toolbar)
*/
public void markDownloadingTaskAsRead() {
markDownloadingTaskAsReadOrUnread(true);
}
/**
* 标记下载中任务为未读状态(用于下载页及外部toolbar)
*/
public void markDownloadingTaskAsUnread() {
markDownloadingTaskAsReadOrUnread(false);
}
/**
* 更改下载中任务的已读状态(用于下载页及外部toolbar)
*/
private void markDownloadingTaskAsReadOrUnread(boolean isRead) {
AppExecutor.getIoExecutor().execute(() -> {
boolean markHasChanged = false;
List<DownloadEntity> all = getAll();
for (DownloadEntity downloadEntity : all) {
if (downloadEntity.getStatus() != DownloadStatus.done) {
if (isRead) {
String mark = downloadEntity.getMeta().get(DOWNLOADING_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) {
downloadEntity.getMeta().put(DOWNLOADING_IS_READ_MARK, DOWNLOADING_IS_READ_MARK);
mDownloadDao.newOrUpdate(downloadEntity);
if (!markHasChanged) markHasChanged = true;
}
} else {
downloadEntity.getMeta().put(DOWNLOADING_IS_READ_MARK, "");
mDownloadDao.newOrUpdate(downloadEntity);
if (!markHasChanged) markHasChanged = true;
}
@ -795,7 +867,7 @@ public class DownloadManager implements DownloadStatusListener {
public void saveUpdateMarkToStorage() {
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
if (updates.size() == mUpdateMarks.size()) {
SPUtils.setStringSet(HINT_MARK, mUpdateMarks);
SPUtils.setStringSet(UPDATE_IS_READ_MARK, mUpdateMarks);
return;
}
@ -804,7 +876,18 @@ public class DownloadManager implements DownloadStatusListener {
String mark = update.getId() + update.getPackageName();
marks.add(mark);
}
SPUtils.setStringSet(HINT_MARK, marks);
SPUtils.setStringSet(UPDATE_IS_READ_MARK, marks);
}
public void updateDownloadEntity(DownloadEntity downloadEntity) {
mDownloadDao.newOrUpdate(downloadEntity);
}
public void startDownload(String url) {
put(url, System.currentTimeMillis());
Message msg = Message.obtain();
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_AUTO_TASK;
msg.obj = url;
sendMessageDelayed(msg, 1000);
}
}

View File

@ -16,7 +16,7 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import tv.danmaku.ijk.media.exo2.ExoSourceManager
import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSource
import tv.danmaku.ijk.media.exo2.source.GSYDefaultHttpDataSource
import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSourceFactory
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
@ -25,41 +25,58 @@ object ExoCacheManager {
private val threads = ConcurrentHashMap<String, AtomicBoolean>()
private val preLength by lazy {
private fun getPreLength(): Long {
val totalRamSizeOfDevice = DeviceUtils.getTotalRamSizeOfDevice(HaloApp.getInstance().application)
if (totalRamSizeOfDevice <= 2 * 1024) {
10 * 1024 * 1024L
return if (totalRamSizeOfDevice <= 2 * 1024) {
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
10 * 1024 * 1024L
} else {
when (NetworkUtils.getMobileNetworkType(HaloApp.getInstance().application)) {
"5G", "4G" -> 10 * 1024 * 1024L
"3G" -> 5 * 1024 * 1024L
else -> 0L
}
}
} else {
50 * 1024 * 1024L
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
50 * 1024 * 1024L
} else {
when (NetworkUtils.getMobileNetworkType(HaloApp.getInstance().application)) {
"5G", "4G" -> 20 * 1024 * 1024L
"3G" -> 5 * 1024 * 1024L
else -> 0L
}
}
}
}
fun preload(videoUri: String) {
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
runOnIoThread {
threads[videoUri] = AtomicBoolean(false)
val contentLength = getContentLength(videoUri)
val cacheLength = if (contentLength >= preLength) preLength else contentLength
val dataSpec = DataSpec(Uri.parse(videoUri), 0, cacheLength, null)
val simpleCache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
val dataSourceFactory = GSYExoHttpDataSourceFactory(Util.getUserAgent(HaloApp.getInstance().application,
"ExoCacheManager"), DefaultBandwidthMeter.Builder(HaloApp.getInstance().application).build(),
GSYExoHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
GSYExoHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false)
val cacheDataSource = CacheDataSource(simpleCache, dataSourceFactory.createDataSource())
try {
CacheUtil.cache(dataSpec, simpleCache, CacheUtil.DEFAULT_CACHE_KEY_FACTORY, cacheDataSource, CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->
if (requestLength == bytesCached) {
threads.remove(videoUri)
}
if (BuildConfig.DEBUG) {
Utils.log("$requestLength--$bytesCached--$newBytesCached")
}
}, threads[videoUri])
} catch (e: Throwable) {
threads.remove(videoUri)
e.printStackTrace()
}
val preLength = getPreLength()
if (preLength == 0L) return
runOnIoThread {
Thread.sleep(100)
threads[videoUri] = AtomicBoolean(false)
val contentLength = getContentLength(videoUri)
val cacheLength = if (contentLength >= preLength) preLength else contentLength
val dataSpec = DataSpec(Uri.parse(videoUri), 0, cacheLength, null)
val simpleCache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
val dataSourceFactory = GSYExoHttpDataSourceFactory(Util.getUserAgent(HaloApp.getInstance().application,
"ExoCacheManager"), DefaultBandwidthMeter.Builder(HaloApp.getInstance().application).build(),
GSYDefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
GSYDefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false)
val cacheDataSource = CacheDataSource(simpleCache, dataSourceFactory.createDataSource())
try {
CacheUtil.cache(dataSpec, simpleCache, CacheUtil.DEFAULT_CACHE_KEY_FACTORY, cacheDataSource, CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->
if (requestLength == bytesCached) {
threads.remove(videoUri)
}
if (BuildConfig.DEBUG) {
Utils.log("$requestLength--$bytesCached--$newBytesCached")
}
}, threads[videoUri])
} catch (e: Throwable) {
threads.remove(videoUri)
e.printStackTrace()
}
}
}

View File

@ -16,6 +16,7 @@ import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView.SmoothScroller
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.TimeElapsedHelper
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
@ -45,6 +46,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
private lateinit var mGestureDetector: GestureDetector
private var mAdapter: DownloadDialogAdapter? = null
private var mTraceEvent: ExposureEvent? = null
// 合集页面保持和后台一样的顺序
private var mCollectionAdapter: DownloadDialogAdapter? = null
@ -99,11 +101,12 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
mGameEntity = requireArguments().getParcelable(GameEntity::class.java.simpleName)!!
mEntrance = requireArguments().getString(EntranceUtils.KEY_ENTRANCE) ?: ""
mLocation = requireArguments().getString(EntranceUtils.KEY_LOCATION) ?: ""
mTraceEvent = requireArguments().getParcelable(EntranceUtils.KEY_TRACE_EVENT) ?: null
val factory = DownloadViewModel.Factory(HaloApp.getInstance().application, mGameEntity)
mViewModel = ViewModelProviders.of(this, factory).get(DownloadViewModel::class.java)
mViewModel.listLiveData.observeNonNull(this, callback = { itemList ->
mAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mEntrance, mLocation)
mAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mTraceEvent, mEntrance, mLocation)
mBinding.contentList.layoutManager = createLayoutManager(itemList)
mBinding.contentList.adapter = mAdapter
})
@ -124,7 +127,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
itemList.add(DownloadDialogItemData(instruction = collection.downloadInstruction))
}
mCollectionAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, true, mEntrance, mLocation)
mCollectionAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, true, mTraceEvent, mEntrance, mLocation)
mBinding.collectionList.layoutManager = createLayoutManager(itemList)
mBinding.collectionList.adapter = mCollectionAdapter
@ -383,7 +386,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
companion object {
@JvmStatic
fun showDownloadDialog(context: Context?, gameEntity: GameEntity, entrance: String?, location: String?) {
fun showDownloadDialog(context: Context?, gameEntity: GameEntity, traceEvent: ExposureEvent?, entrance: String?, location: String?) {
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
context
} else if (BuildConfig.DEBUG) {
@ -405,6 +408,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance)
bundle.putString(EntranceUtils.KEY_LOCATION, location)
bundle.putParcelable(GameEntity::class.java.simpleName, gameEntity)
bundle.putParcelable(EntranceUtils.KEY_TRACE_EVENT, traceEvent)
arguments = bundle
}
downloadDialog.show(fragmentActivity.supportFragmentManager, DownloadDialog::class.java.name)

View File

@ -5,6 +5,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.OnViewClickListener
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.MtaHelper
import com.gh.common.util.throwExceptionInDebug
import com.gh.gamecenter.NewsDetailActivity
@ -19,6 +20,7 @@ class DownloadDialogAdapter(context: Context,
val viewModel: DownloadViewModel,
val listData: List<DownloadDialogItemData>,
val isCollectionPage: Boolean,
private val mTraceEvent: ExposureEvent?,
private val mEntrance: String,
private val mLocation: String) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
@ -104,11 +106,11 @@ class DownloadDialogAdapter(context: Context,
holder.bindItem(viewModel.gameEntity)
}
is DownloadDialogInstalledItemViewHolder -> {
holder.bindInstalledItem(listData[position].installed!!, viewModel, mEntrance, mPath, mLocation)
holder.bindInstalledItem(listData[position].installed!!, viewModel, mTraceEvent, mEntrance, mPath, mLocation)
throwExceptionInDebug("合集页面不应该存在该条数据", isCollectionPage)
}
is DownloadDialogItemViewHolder -> {
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mEntrance, mPath, mLocation)
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mTraceEvent, mEntrance, mPath, mLocation)
}
}
}

View File

@ -3,6 +3,7 @@ package com.gh.download.dialog
import android.view.View
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.PackageUtils
import com.gh.common.util.goneIf
import com.gh.common.util.throwExceptionInDebug
@ -15,7 +16,7 @@ import com.lightgame.download.DownloadStatus
class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalledItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindInstalledItem(apkEntity: ApkEntity, viewModel: DownloadViewModel, entrance: String, path: String, location: String) {
fun bindInstalledItem(apkEntity: ApkEntity, viewModel: DownloadViewModel, traceEvent: ExposureEvent?, entrance: String, path: String, location: String) {
val gameEntity = viewModel.gameEntity
val apkCollection = apkEntity.apkCollection
@ -122,7 +123,7 @@ class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalled
}
}
DownloadDialogItemViewHolder.setDownloadClickListener(itemView, apkEntity, viewModel, entrance, path, location)
DownloadDialogItemViewHolder.setDownloadClickListener(itemView, apkEntity, viewModel, traceEvent, entrance, path, location)
binding.executePendingBindings()
}
}

View File

@ -7,6 +7,7 @@ import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.dialog.CertificationDialog
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.download.DownloadManager
@ -16,6 +17,7 @@ import com.gh.gamecenter.databinding.DownloadDialogItemBinding
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameCollectionEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.manager.PackagesManager
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@ -28,6 +30,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
fun bindItem(apkEntity: ApkEntity,
viewModel: DownloadViewModel,
isCollectionPage: Boolean,
traceEvent: ExposureEvent?,
entrance: String,
path: String,
location: String) {
@ -105,7 +108,8 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
binding.status.text = "可更新"
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_update)
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.UPDATE)
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id) {
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id ||
PackagesManager.isInstalled(apkEntity.packageName) && Config.getSettings()?.gameDownloadBlackList?.contains(apkEntity.packageName) == true) {
binding.downloadStatusIcon.visibility = View.GONE
binding.status.visibility = View.VISIBLE
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
@ -140,7 +144,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
}
}
setDownloadClickListener(itemView, apkEntity, viewModel, entrance, path, location)
setDownloadClickListener(itemView, apkEntity, viewModel, traceEvent, entrance, path, location)
binding.executePendingBindings()
}
@ -157,6 +161,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
fun setDownloadClickListener(itemView: View,
apkEntity: ApkEntity,
viewModel: DownloadViewModel,
traceEvent: ExposureEvent?,
entrance: String,
path: String,
location: String) {
@ -166,7 +171,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
var mtaValue = "未知"
when (itemView.getTag(DownloadDialogAdapter.ITEM_TAG_KEY)) {
DownloadDialogItemStatus.DOWNLOAD -> {
createDownloadTask(it.context, apkEntity, gameEntity, "下载", entrance, location)
createDownloadTask(it.context, apkEntity, gameEntity, "下载", traceEvent, entrance, location)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_下载"
}
DownloadDialogItemStatus.LAUNCH -> {
@ -218,12 +223,12 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
}
}
DownloadDialogItemStatus.PLUGGABLE -> {
createDownloadTask(it.context, apkEntity, gameEntity, "插件化", entrance, location)
createDownloadTask(it.context, apkEntity, gameEntity, "插件化", traceEvent, entrance, location)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_插件化"
}
DownloadDialogItemStatus.UPDATE -> {
createDownloadTask(it.context, apkEntity, gameEntity, "更新", entrance, location)
createDownloadTask(it.context, apkEntity, gameEntity, "更新", traceEvent, entrance, location)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_更新"
}
@ -263,26 +268,33 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
apkEntity: ApkEntity,
gameEntity: GameEntity,
downloadMethod: String,
traceEvent: ExposureEvent?,
entrance: String,
location: String) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
override fun onCallback() {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, null)
// todo 有时间存储判断统一处理
val msg = FileUtils.isCanDownload(context, apkEntity.size)
if (msg.isNullOrEmpty()) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
override fun onCallback() {
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
DownloadManager.createDownload(
context,
apkEntity,
gameEntity,
downloadMethod,
entrance,
location,
isSubscribe, traceEvent)
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
}
})
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
}
})
} else {
Utils.toast(context, msg)
}
}
}
}

View File

@ -5,6 +5,7 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.constant.Config
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.entity.ApkEntity
@ -61,12 +62,14 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
apk.apkCollection?.saveApkEntity?.let {
for (entity in it) {
isInstalled = PackagesManager.isInstalled(entity.packageName)
&& Config.getSettings()?.gameDownloadBlackList?.contains(entity.packageName) != true
if (isInstalled) break
}
}
isInstalled
} else {
PackagesManager.isInstalled(apk.packageName)
&& Config.getSettings()?.gameDownloadBlackList?.contains(apk.packageName) != true
}
if (installed) {
mInstalledApkList.add(apk)

View File

@ -3,7 +3,10 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.MessageEntity;
@ -11,11 +14,30 @@ import com.gh.gamecenter.qa.comment.CommentActivity;
import com.gh.gamecenter.qa.comment.NewCommentConversationFragment;
import com.halo.assistant.fragment.comment.CommentDetailFragment;
import butterknife.BindView;
/**
* Created by khy on 2017/3/22.
*/
public class CommentDetailActivity extends NormalActivity {
@BindView(R.id.shadowView)
public View shadowView;
@Override
protected int getLayoutId() {
return R.layout.toolbar_shadow;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup.LayoutParams layoutParams = shadowView.getLayoutParams();
layoutParams.height = DisplayUtils.dip2px(50f) + DisplayUtils.getStatusBarHeight(getResources());
shadowView.setLayoutParams(layoutParams);
DisplayUtils.setStatusBarColor(this, R.color.transparent, true);
}
// article 不为空则显示跳转原文按钮
public static Intent getIntent(Context context, String commentId, MessageEntity.Article article) {
Bundle args = new Bundle();

View File

@ -23,9 +23,6 @@ import android.view.View;
import android.view.Window;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProviders;
import com.gh.base.AppUncaughtHandler;
import com.gh.base.BaseActivity;
import com.gh.base.fragment.BaseFragment_ViewPager;
@ -119,6 +116,8 @@ import java.util.TimerTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProviders;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
@ -265,22 +264,6 @@ public class MainActivity extends BaseActivity {
//启动app删除视频缓存文件
AppExecutor.getIoExecutor().execute(() -> {
try {
/*File cacheFileDirectory = StorageUtils.getIndividualCacheDirectory(this);
if (cacheFileDirectory.exists() && cacheFileDirectory.isDirectory()) {
for (File file : cacheFileDirectory.listFiles()) {
FileUtils.deleteFile(file.getPath());
}
}
//创建nomedia文件
File noMediaFile = new File(cacheFileDirectory.getParent(), ".nomedia");
if (!cacheFileDirectory.exists()) {
cacheFileDirectory.mkdirs();
}
if (!noMediaFile.exists()) {
noMediaFile.createNewFile();
}*/
String dirPath = getCacheDir().getAbsolutePath() + File.separator + "exo";
FileUtils.deleteFolder(new File(dirPath));
} catch (Exception e) {
@ -292,6 +275,8 @@ public class MainActivity extends BaseActivity {
SPUtils.setBoolean(Constants.SP_TOP_VIDEO_VOICE, true);
//恢复视频流非Wifi提醒
SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true);
//重置顶部视频播放进度
SPUtils.setString(Constants.SP_TOP_VIDEO_SCHEDULE, "");
}
@Override
@ -430,7 +415,7 @@ public class MainActivity extends BaseActivity {
if (entity.getStatus().equals(DownloadStatus.done)) {
if (PackageUtils.isInstalled(getApplicationContext(), entity.getPackageName())
&& (!entity.isPlugin()
|| PackageUtils.isSignature(getApplicationContext(), entity.getPackageName()))) {
|| PackageUtils.isSignedByGh(getApplicationContext(), entity.getPackageName()))) {
continue;
}
if (downloadEntity == null) {
@ -523,10 +508,6 @@ public class MainActivity extends BaseActivity {
EventBus.getDefault().post(new EBReuse(CommunityFragment.EB_RETRY_PAGE));
}
private void checkRetryDownload() {
DownloadManager.getInstance(this).checkRetryDownload();
}
private void checkTinkerPath() {
CommonDebug.logMethodWithParams(this, TinkerManager.getTinkerId(), TinkerManager.getNewTinkerId());
CommonDebug.logMethodWithParams(this, CrashReport.getAppVer(), CrashReport.getAppID(), CrashReport.getAppChannel(), CrashReport.getSdkExtraData());
@ -687,7 +668,6 @@ public class MainActivity extends BaseActivity {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBNetworkState busNetworkState) {
if (busNetworkState.isNetworkConnected()) {
checkRetryDownload();
if (Config.getSettings() == null) {
Config.getGhzsSettings();
}

View File

@ -2,13 +2,19 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.entity.ConcernEntity;
import com.gh.gamecenter.message.MessageDetailFragment;
import com.halo.assistant.HaloApp;
import butterknife.BindView;
/**
* Created by khy on 2016/11/8.
* 消息详情界面(评论详情)
@ -16,6 +22,23 @@ import com.halo.assistant.HaloApp;
@Deprecated
public class MessageDetailActivity extends NormalActivity {
@BindView(R.id.shadowView)
public View shadowView;
@Override
protected int getLayoutId() {
return R.layout.toolbar_shadow;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup.LayoutParams layoutParams = shadowView.getLayoutParams();
layoutParams.height = DisplayUtils.dip2px(50f) + DisplayUtils.getStatusBarHeight(getResources());
shadowView.setLayoutParams(layoutParams);
DisplayUtils.setStatusBarColor(this, R.color.transparent, false);
}
// 评论回复
public static Intent getMessageDetailIntent(Context context, CommentEntity entity, String newsId) {
Intent intent = new Intent(context, MessageDetailActivity.class);

View File

@ -7,11 +7,11 @@ import android.text.TextUtils;
import android.view.MenuItem;
import android.view.MotionEvent;
import androidx.fragment.app.Fragment;
import com.gh.base.ToolBarActivity;
import com.gh.gamecenter.normal.NormalFragment;
import androidx.fragment.app.Fragment;
/**
* Created by khy on 17/10/17.
*/

View File

@ -52,7 +52,6 @@ open class SearchActivity : BaseActivity() {
@SuppressLint("CheckResult")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val hint = intent.getStringExtra(EntranceUtils.KEY_HINT)
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)

View File

@ -22,9 +22,13 @@ import com.lightgame.utils.Utils;
import static com.gh.common.util.EntranceUtils.ENTRANCE_BROWSER;
import static com.gh.common.util.EntranceUtils.HOST_ANSWER;
import static com.gh.common.util.EntranceUtils.HOST_ARTICLE;
import static com.gh.common.util.EntranceUtils.HOST_CATEGORY;
import static com.gh.common.util.EntranceUtils.HOST_COLUMN;
import static com.gh.common.util.EntranceUtils.HOST_COLUMN_COLLECTION;
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY;
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_COLUMN;
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL;
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL;
import static com.gh.common.util.EntranceUtils.HOST_DOWNLOAD;
import static com.gh.common.util.EntranceUtils.HOST_GAME;
import static com.gh.common.util.EntranceUtils.HOST_LIBAO;
@ -239,6 +243,28 @@ public class SkipActivity extends BaseActivity {
String columnId = uri.getQueryParameter("column_id");
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
break;
case HOST_CATEGORY:
title = uri.getQueryParameter("title");
DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COLUMN_COLLECTION:
DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_QUESTION_LABEL_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String tag = uri.getQueryParameter("tag");
DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN_DETAIL:
community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
columnId = uri.getQueryParameter("column_id");
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;

View File

@ -13,6 +13,7 @@ import android.os.Environment;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.text.Html;
import android.text.InputFilter;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
@ -23,6 +24,12 @@ import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.base.OnListClickListener;
import com.gh.base.OnRequestCallBackListener;
import com.gh.base.ToolBarActivity;
@ -42,6 +49,7 @@ import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.TextHelper;
import com.gh.common.util.UploadImageUtils;
import com.gh.common.util.UrlFilterUtils;
import com.gh.common.view.FixLinearLayoutManager;
@ -81,12 +89,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.OnClick;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -421,6 +423,9 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
mSuggestContentEt.setFocusable(true);
mSuggestContentEt.setFocusableInTouchMode(true);
mSuggestContentEt.requestFocus();
mSuggestContentEt.setFilters(new InputFilter[]{TextHelper.getFilter(256, "最多输入256个字")});
mSuggestEmailEt.setFilters(new InputFilter[]{TextHelper.getFilter(64, "最多输入64个字")});
mTypeOtherName.setFilters(new InputFilter[]{TextHelper.getFilter(30, " 最多输入30个字")});
Util_System_Keyboard.showSoftKeyboard(this, mSuggestContentEt);
}
@ -760,7 +765,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
}
@Override
public void onSuccess(@NotNull LinkedHashMap<String, String> imageUrl) {
public void onSuccess(@NotNull LinkedHashMap<String, String> imageUrl, @NotNull Map<String, ? extends Exception> errorMap) {
Utils.log("意见反馈:图片上传完成");
final JSONArray picArray = new JSONArray();
for (String s : imageUrl.keySet()) {
@ -770,7 +775,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
}
@Override
public void onError() {
public void onError(@NotNull Map<String, ? extends Exception> errorMap) {
if (postDialog != null) {
postDialog.dismissAllowingStateLoss();
}
@ -934,6 +939,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
View manualContainer = view.findViewById(R.id.dialog_suggest_manual_container);
View manualConfirm = view.findViewById(R.id.dialog_suggest_confirm);
EditText manualEdit = view.findViewById(R.id.dialog_suggest_edit);
manualEdit.setFilters(new InputFilter[]{TextHelper.getFilter(30, " 最多输入30个字")});
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
recyclerView.setAdapter(new SuggestSelectGameAdapter(this, pb));

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import com.gh.common.constant.Constants;
@ -18,12 +19,37 @@ import java.util.Locale;
import androidx.annotation.NonNull;
import static com.halo.assistant.fragment.WebFragment.KEY_GAME_NAME;
import static com.halo.assistant.fragment.WebFragment.KEY_REQUIRE_BACK_CONFIRMATION;
/**
* Created by khy on 2016/10/18.
*/
@Deprecated
public class WebActivity extends NormalActivity {
private boolean mIsFullScreen;
@Override
protected void onCreate(Bundle savedInstanceState) {
Bundle bundle = getIntent().getBundleExtra(NORMAL_FRAGMENT_BUNDLE);
if (bundle != null) {
String mGameName = bundle.getString(KEY_GAME_NAME);
boolean mIsBackpressRequireConfirmation = bundle.getBoolean(KEY_REQUIRE_BACK_CONFIRMATION, false);
mIsFullScreen = !TextUtils.isEmpty(mGameName) && mIsBackpressRequireConfirmation;
if (mIsFullScreen) {
setTheme(R.style.AppFullScreenTheme);
}
super.onCreate(savedInstanceState);
if (mIsFullScreen) {
hideToolbar(true);
}
} else {
super.onCreate(savedInstanceState);
}
}
@Override
protected Intent provideNormalIntent() {
return getTargetIntent(this, WebActivity.class, WebFragment.class);
@ -203,10 +229,10 @@ public class WebActivity extends NormalActivity {
public static Intent getIntentForWebGame(Context context, String url, String gameName, boolean interveneBackpress) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_URL, url);
bundle.putString(WebFragment.KEY_GAME_NAME, gameName);
bundle.putString(KEY_GAME_NAME, gameName);
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, true);
if (interveneBackpress) {
bundle.putBoolean(WebFragment.KEY_REQUIRE_BACK_CONFIRMATION, true);
bundle.putBoolean(KEY_REQUIRE_BACK_CONFIRMATION, true);
bundle.putString(WebFragment.KEY_BACK_CONFIRMATION_CONTENT, "退出后将不保存当前游戏进度,确定退出吗?");
}
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);

View File

@ -9,9 +9,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.gh.common.constant.Config;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.CommentUtils;
@ -20,6 +17,7 @@ import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NewsUtils;
@ -55,7 +53,10 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.HttpException;
@ -331,7 +332,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
}
private void initCommentViewHolder(final CommentViewHolder holder, int position) {
AtomicBoolean isChildLongClick = new AtomicBoolean(false);
int index;
if (mHotCommentList.size() == 0) {
index = 2;
@ -412,6 +413,10 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
));
holder.itemView.setOnClickListener(v -> {
if (isChildLongClick.get()) {
isChildLongClick.set(false);
return;
}
if (holder.commentReply.getVisibility() == View.VISIBLE) {
CheckLoginUtils.checkLogin(mContext, "资讯文章详情-评论详情-回复", () -> {
mOnCommentCallBackListener.onCommentCallback(finalCommentEntity);
@ -419,6 +424,17 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
}
});
holder.commentContentTv.setOnLongClickListener(v -> {
isChildLongClick.set(true);
ExtensionsKt.copyTextAndToast(holder.commentContentTv.getText().toString(), "复制成功");
return true;
});
holder.quoteContentTv.setOnLongClickListener(v -> {
isChildLongClick.set(true);
ExtensionsKt.copyTextAndToast(holder.quoteContentTv.getText().toString(), "复制成功");
return true;
});
holder.commentMore.setOnClickListener(v ->
CommentUtils.showReportDialog(finalCommentEntity,
mContext, true, "资讯文章详情-评论详情"));

View File

@ -5,16 +5,12 @@ import android.content.Intent;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.GameOffServiceDialogFragment;
import com.gh.common.dialog.ReserveDialogFragment;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.history.HistoryHelper;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DataLogUtils;
import com.gh.common.util.DataUtils;
@ -44,6 +40,10 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
/**
* Created by khy on 27/06/17.
* 详情页面下载ViewHolder
@ -182,6 +182,7 @@ public class DetailViewHolder {
DownloadDialog.showDownloadDialog(
mViewHolder.context,
mGameEntity,
mTraceEvent,
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
mName + ":" + mTitle);
});
@ -198,6 +199,7 @@ public class DetailViewHolder {
DownloadDialog.showDownloadDialog(
mViewHolder.context,
mGameEntity,
mTraceEvent,
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
mName + ":" + mTitle);
});
@ -245,7 +247,13 @@ public class DetailViewHolder {
case H5_GAME:
MtaHelper.onEvent("H5页面", "入口", "详情页_" + mGameEntity.getName());
LinkEntity linkEntity = mGameEntity.getH5Link();
Intent i = new Intent(WebActivity.getIntentForWebGame(mViewHolder.context, linkEntity.getLink(), mGameEntity.getName(), "play".equals(linkEntity.getType())));
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(mGameEntity);
}
Intent i = new Intent(WebActivity.getIntentForWebGame(mViewHolder.context, linkEntity.getLink(), mGameEntity.getName(),isPlay));
mViewHolder.context.startActivity(i);
break;
}
@ -275,9 +283,6 @@ public class DetailViewHolder {
"下载开始",
method);
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, method);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(mGameEntity, apkEntity.getPlatform(), mTraceEvent, downloadType);
DownloadManager.createDownload(mViewHolder.context,
apkEntity,
mGameEntity,
@ -285,7 +290,7 @@ public class DetailViewHolder {
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
mName + ":" + mTitle,
isSubscribe,
downloadExposureEvent);
mTraceEvent);
mViewHolder.mDownloadPb.setProgress(0);
mViewHolder.mDownloadPb.setDownloadType("插件化".equals(method) ?

View File

@ -1,10 +1,13 @@
package com.gh.gamecenter.amway
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.lottie.LottieAnimationView
import com.gh.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
@ -23,9 +26,9 @@ import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
import com.gh.gamecenter.home.LegacyHomeFragmentAdapterAssistant
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
import com.halo.assistant.fragment.game.GamePluginAdapter
import com.lightgame.download.DownloadEntity
import com.lightgame.view.CheckableImageView
import java.util.*
import java.util.regex.Pattern
@ -159,7 +162,6 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
when (val adapter = recyclerView?.adapter) {
is GameVerticalAdapter -> adapter.notifyItemByDownload(download)
is GamePluginAdapter -> adapter.notifyItemByDownload(download)
is HomeSlideListAdapter -> adapter.notifyItemByDownload(download)
}
} else {
notifyItemChanged(gameAndPosition.position)
@ -208,11 +210,10 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
}
if (amway.comment.me.isVoted) {
binding.likeIv.setImageResource(R.drawable.ic_amway_liked)
binding.likeIv.isChecked = true
binding.likeCountTv.setTextColor(R.color.theme_font.toColor())
binding.likeCountTv.setOnClickListener { binding.likeIv.performClick() }
binding.likeIv.setOnClickListener {
debounceActionWithInterval(binding.likeIv.id, 1000L) {
binding.likeClickableView.setOnClickListener {
debounceActionWithInterval(binding.likeClickableView.id, 1000L) {
binding.likeIv.context.ifLogin("安利墙") {
viewModel.undoLikeAmwayComment(amway.game.id, amway.comment.id)
MtaHelper.onEvent("安利墙", "点击", "评论${blockPosition}_${amway.game.name}_取消点赞")
@ -220,12 +221,12 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
}
}
} else {
binding.likeIv.setImageResource(R.drawable.ic_amway_like)
binding.likeIv.isChecked = false
binding.likeCountTv.setTextColor(R.color.text_B3B3B3.toColor())
binding.likeCountTv.setOnClickListener { binding.likeIv.performClick() }
binding.likeIv.setOnClickListener {
debounceActionWithInterval(binding.likeIv.id, 1000L) {
binding.likeClickableView.setOnClickListener {
debounceActionWithInterval(binding.likeClickableView.id, 1000L) {
binding.likeIv.context.ifLogin("安利墙") {
playLikedAnimation(binding.likeCountTv, binding.likeIv, binding.likeAnimView)
viewModel.likeAmwayComment(amway.game.id, amway.comment.id)
MtaHelper.onEvent("安利墙", "点击", "评论${blockPosition}_${amway.game.name}_点赞")
}
@ -241,6 +242,19 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
DirectUtils.directToBadgeWall(context, amway.comment.user.id, amway.comment.user.name, amway.comment.user.icon)
}
}
private fun playLikedAnimation(likeTv: TextView, likeIv: CheckableImageView, likeAnimView: LottieAnimationView) {
likeTv.setTextColor(R.color.theme_font.toColor())
likeIv.isChecked = true
likeIv.visibility = View.INVISIBLE
likeAnimView.visibility = View.VISIBLE
likeAnimView.setAnimation("lottie/community_vote.json")
likeAnimView.playAnimation()
likeAnimView.doOnAnimationEnd {
likeAnimView.visibility = View.INVISIBLE
likeIv.visibility = View.VISIBLE
}
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {

View File

@ -162,7 +162,7 @@ public abstract class ListActivity<T, VM extends BaseListViewModel /* 该泛型
public void onLoadRefresh() {
mReuseNoConn.setVisibility(View.GONE);
mReuseNoData.setVisibility(View.GONE);
mListLoading.setVisibility(View.VISIBLE);
mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
mListRv.setVisibility(View.GONE);
mBaseHandler.postDelayed(() -> {
mListViewModel.load(LoadType.REFRESH);

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter.baselist;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import androidx.recyclerview.widget.DiffUtil;
import com.lightgame.adapter.BaseRecyclerAdapter;
@ -128,7 +129,7 @@ public abstract class ListAdapter<DataType> extends BaseRecyclerAdapter {
if (mEntityList != null) mEntityList.clear();
mIsNetworkError = false;
mIsOver = false;
mIsLoading = false;
mIsLoading = true;
notifyDataSetChanged();
return;
}

View File

@ -180,7 +180,7 @@ public abstract class ListFragment<T, VM extends BaseListViewModel /* 该泛型
showSkeleton(true);
mReuseNoConn.setVisibility(View.GONE);
mReuseNoData.setVisibility(View.GONE);
mListLoading.setVisibility(View.VISIBLE);
mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
mListRv.setVisibility(View.GONE);
mBaseHandler.postDelayed(() -> {
mListViewModel.load(LoadType.REFRESH);

View File

@ -34,4 +34,8 @@ class CategoryDirectoryActivity : NormalActivity() {
return "游戏分类"
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, CategoryDirectoryActivity::class.java, CategoryDirectoryFragment::class.java)
}
}

View File

@ -135,15 +135,6 @@ class NewCategoryListFragment : ListFragment<GameEntity, NewCategoryListViewMode
}
}
override fun onLoadRefresh() {
mBaseHandler.postDelayed({ mListViewModel.load(LoadType.REFRESH) }, 200)
mReuseNoConn.visibility = View.GONE
mReuseNoData.visibility = View.GONE
mListLoading.visibility = View.VISIBLE
mListRv.visibility = View.GONE
}
override fun onRefresh() {
mAdapter?.clearPositionAndPackageMap()

View File

@ -1,10 +1,6 @@
package com.gh.gamecenter.collection;
import android.content.Context;
import androidx.recyclerview.widget.RecyclerView;
import kotlin.Pair;
import android.view.View;
import android.view.ViewGroup;
@ -12,22 +8,25 @@ import com.gh.base.OnListClickListener;
import com.gh.common.constant.ItemViewType;
import com.gh.common.syncpage.ISyncAdapterHandler;
import com.gh.common.util.CollectionUtils;
import com.gh.common.util.DialogHelper;
import com.gh.common.util.DialogUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
import com.gh.gamecenter.baselist.ListAdapter;
import com.gh.gamecenter.baselist.LoadType;
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding;
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder;
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
import com.gh.gamecenter.qa.entity.AnswerEntity;
import com.gh.gamecenter.qa.entity.Questions;
import com.gh.gamecenter.qa.questions.detail.AnswerViewHolder;
import com.gh.gamecenter.baselist.ListAdapter;
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity;
import com.lightgame.utils.Utils;
import org.jetbrains.annotations.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import kotlin.Pair;
/**
* Created by khy on 22/12/17.
*/
@ -39,14 +38,12 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> implements ISyncAda
private AnswerViewModel mListViewModel;
private String mEntrance;
private AnswerFragment.Type mType;
public AnswerAdapter(Context context, AnswerViewModel viewModel, AnswerFragment.Type type, OnListClickListener listClickListener, String entrance) {
public AnswerAdapter(Context context, AnswerViewModel viewModel, OnListClickListener listClickListener, String entrance) {
super(context);
mListViewModel = viewModel;
mListClickListener = listClickListener;
mEntrance = entrance;
this.mType = type;
}
@Override
@ -77,37 +74,45 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> implements ISyncAda
CommunityAnswerItemViewHolder viewHolder = (CommunityAnswerItemViewHolder) holder;
AnswerEntity entity = mEntityList.get(position);
String path;
if (mType == AnswerFragment.Type.COLLECTION) {
if (AnswerFragment.COLLECTION.equals(mListViewModel.getType())) {
path = "我的收藏-回答列表";
} else if (mType == AnswerFragment.Type.HISTORY) {
} else if (AnswerFragment.HISTORY.equals(mListViewModel.getType())) {
path = "浏览记录-回答列表";
viewHolder.itemView.setOnLongClickListener(v -> {
DialogHelper.showDialog(holder.itemView.getContext(),
"删除记录",
"删除浏览记录将不可恢复,确定删除吗?",
"确定",
"取消",
() -> {
mListViewModel.removeHistory(entity);
},
() -> {
},
false, "", "");
return false;
});
} else {
path = "插入回答-收藏回答列表";
}
viewHolder.bindAnswerItem(entity, mEntrance, path);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (entity.getActive()) {
mContext.startActivity(AnswerDetailActivity.getIntent(mContext, entity.getId(), mEntrance, path));
} else {
showDeleteDialog(entity.getId());
}
holder.itemView.setOnClickListener(v -> {
if (entity.getActive()) {
mContext.startActivity(AnswerDetailActivity.getIntent(mContext, entity.getId(), mEntrance, path));
} else {
showDeleteDialog(entity.getId());
}
if (!entity.getRead()) {
entity.setRead(true);
notifyItemChanged(position);
mListViewModel.postCollectionAnswerRead(entity.getId());
}
if (!entity.getRead()) {
entity.setRead(true);
notifyItemChanged(position);
mListViewModel.postCollectionAnswerRead(entity.getId());
}
});
viewHolder.getBinding().title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Questions questions = entity.getQuestions();
mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
}
viewHolder.getBinding().title.setOnClickListener(v -> {
Questions questions = entity.getQuestions();
mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
});
break;
case ItemViewType.ITEM_FOOTER:

View File

@ -1,8 +1,10 @@
package com.gh.gamecenter.collection;
import android.os.Bundle;
import android.view.View;
import com.gh.common.util.CollectionUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.baselist.ListAdapter;
import com.gh.gamecenter.baselist.ListFragment;
@ -24,35 +26,26 @@ import androidx.recyclerview.widget.RecyclerView;
public class AnswerFragment extends ListFragment<AnswerEntity, AnswerViewModel> {
private AnswerAdapter mAdapter;
private Type mType;
private String mType;
public static AnswerFragment getInstance(Type type) {
AnswerFragment fragment = new AnswerFragment();
fragment.mType = type;
return fragment;
}
public static String COLLECTION = "collection";
public static String COLLECTION_ANSWER = "collection_answer";
public static String HISTORY = "history";
@Override
protected ListAdapter provideListAdapter() {
return mAdapter == null ? mAdapter = new AnswerAdapter(getContext(), mListViewModel, mType, this, mEntrance) : mAdapter;
return mAdapter == null ? mAdapter = new AnswerAdapter(getContext(), mListViewModel, this, mEntrance) : mAdapter;
}
/*@Override
public Single<List<AnswerEntity>> provideDataSingle(int page) {
if (mType == Type.COLLECTION) {
return Single.fromObservable(RetrofitManager.getInstance(getContext()).getApi().getCollectionAnswer(UserManager.getInstance().getUserId(), page));
} else {
return HistoryDatabase.Companion.getInstance().answerDao().getAnswersWithOffset(20, (page - 1) * 20);
}
}*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
mType = getArguments().getString(EntranceUtils.KEY_TYPE, COLLECTION);
super.onCreate(savedInstanceState);
}
@Override
protected AnswerViewModel provideListViewModel() {
AnswerViewModel viewModel = ViewModelProviders.of(this).get(AnswerViewModel.class);
// TODO 因为 mType 是从外面传进来的,所以在应用回收重构时会为空,这里设置为 Type.Collection 只是为了不闪退,会影响逻辑(譬如当前类型为历史的时候)
if (mType == null) {
mType = Type.COLLECTION;
}
viewModel.setType(mType);
return viewModel;
}
@ -74,14 +67,6 @@ public class AnswerFragment extends ListFragment<AnswerEntity, AnswerViewModel>
}
}
public enum Type {
COLLECTION,
COLLECTION_ANSWER,
HISTORY
}
@Override
protected boolean addSyncPageObserver() {
return true;

View File

@ -2,8 +2,11 @@ package com.gh.gamecenter.collection
import android.annotation.SuppressLint
import android.app.Application
import com.gh.common.AppExecutor
import com.gh.common.history.HistoryDatabase
import com.gh.common.history.HistoryHelper
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.retrofit.BiResponse
@ -18,14 +21,14 @@ class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, An
private var mApi = RetrofitManager.getInstance(getApplication()).api
var type: AnswerFragment.Type = AnswerFragment.Type.COLLECTION
var type: String = AnswerFragment.COLLECTION
override fun provideDataObservable(page: Int): Observable<MutableList<AnswerEntity>>? {
return null
}
override fun provideDataSingle(page: Int): Single<List<AnswerEntity>> {
return if (type == AnswerFragment.Type.COLLECTION) {
return if (type == AnswerFragment.COLLECTION) {
Single.fromObservable(mApi.getCollectionAnswer(UserManager.getInstance().userId, page))
} else {
if (page > 5) {
@ -33,7 +36,6 @@ class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, An
} else {
HistoryDatabase.instance.answerDao().getAnswersWithOffset(20, (page - 1) * 20)
}
}
}
@ -52,4 +54,17 @@ class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, An
}
})
}
fun removeHistory(answerEntity: AnswerEntity) {
mResultLiveData.value?.let {
HistoryHelper.deleteAnswerEntity(answerEntity.id!!)
it.remove(answerEntity)
if (it.size == 0) {
AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
} else {
mResultLiveData.postValue(it)
}
}
}
}

View File

@ -2,8 +2,6 @@ package com.gh.gamecenter.collection;
import android.content.Context;
import android.graphics.Paint;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
@ -13,6 +11,7 @@ import android.widget.LinearLayout;
import com.gh.base.OnListClickListener;
import com.gh.common.constant.ItemViewType;
import com.gh.common.util.DialogHelper;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.NewsUtils;
@ -33,6 +32,8 @@ import org.json.JSONObject;
import java.util.Locale;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -43,9 +44,11 @@ import io.reactivex.schedulers.Schedulers;
public class ArticleAdapter extends ListAdapter<NewsEntity> {
private OnListClickListener mListListener;
private ArticleViewModel mViewModel;
public ArticleAdapter(Context context, OnListClickListener listListener) {
public ArticleAdapter(Context context, ArticleViewModel viewModel, OnListClickListener listListener) {
super(context);
mViewModel = viewModel;
mListListener = listListener;
}
@ -103,12 +106,15 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
switch (getItemViewType(position)) {
case ItemViewType.NEWS_IMAGE1:
initNewsImage1ViewHolder((NewsImage1ViewHolder) holder, position);
addLongClickListenerIfNeed(holder, mEntityList.get(position));
break;
case ItemViewType.NEWS_IMAGE2:
initNewsImage2ViewHolder((NewsImage2ViewHolder) holder, position);
addLongClickListenerIfNeed(holder, mEntityList.get(position));
break;
case ItemViewType.NEWS_IMAGE3:
initNewsImage3ViewHolder((NewsImage3ViewHolder) holder, position);
addLongClickListenerIfNeed(holder, mEntityList.get(position));
break;
case ItemViewType.LOADING:
FooterViewHolder footerViewHolder = (FooterViewHolder) holder;
@ -118,6 +124,24 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
}
}
private void addLongClickListenerIfNeed(RecyclerView.ViewHolder holder, NewsEntity newsEntity) {
if (ArticleFragment.HISTORY.equals(mViewModel.type)) {
holder.itemView.setOnLongClickListener(v -> {
DialogHelper.showDialog(holder.itemView.getContext(),
"删除记录",
"删除浏览记录将不可恢复,确定删除吗?",
"确定",
"取消",
() -> {
mViewModel.removeHistory(newsEntity);
},
() -> {
},
false, "", "");
return false;
});
}
}
@Override
public int getItemCount() {

View File

@ -1,10 +1,12 @@
package com.gh.gamecenter.collection;
import android.os.Bundle;
import android.view.View;
import com.gh.common.util.CollectionUtils;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.NewsDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.baselist.ListAdapter;
@ -16,31 +18,39 @@ import com.gh.gamecenter.eventbus.EBCollectionChanged;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import androidx.annotation.Nullable;
/**
* Created by khy on 18/07/17.
*/
public class ArticleFragment extends ListFragment<NewsEntity, ArticleViewModel> {
private Type mType;
private String mType;
private ArticleAdapter mAdapter;
private ArticleViewModel mViewModel;
public static ArticleFragment getInstance(Type type) {
ArticleFragment fragment = new ArticleFragment();
fragment.mType = type;
return fragment;
}
public static String COLLECTION = "collection";
public static String HISTORY = "history";
@Override
protected ArticleViewModel provideListViewModel() {
ArticleViewModel viewModel = super.provideListViewModel();
viewModel.type = mType;
return viewModel;
public void onCreate(@Nullable Bundle savedInstanceState) {
mType = getArguments().getString(EntranceUtils.KEY_TYPE, COLLECTION);
super.onCreate(savedInstanceState);
}
@Override
protected ListAdapter provideListAdapter() {
return mAdapter == null ? mAdapter = new ArticleAdapter(getContext(), this) : mAdapter;
return mAdapter == null ? mAdapter = new ArticleAdapter(getContext(), mViewModel,this) : mAdapter;
}
@Override
protected ArticleViewModel provideListViewModel() {
if (mViewModel == null) {
mViewModel = super.provideListViewModel();
}
mViewModel.type = mType;
return mViewModel;
}
// 收藏事件
@ -55,7 +65,7 @@ public class ArticleFragment extends ListFragment<NewsEntity, ArticleViewModel>
public void onListClick(View view, int position, Object data) {
NewsEntity newsEntity = (NewsEntity) data;
if (mType == Type.COLLECTION) {
if (COLLECTION.equals(mType)) {
if (!newsEntity.getActive()) {
showDeleteDialog(newsEntity.getId());
return;
@ -89,10 +99,4 @@ public class ArticleFragment extends ListFragment<NewsEntity, ArticleViewModel>
}
}), null);
}
public enum Type {
COLLECTION,
HISTORY
}
}

View File

@ -2,9 +2,12 @@ package com.gh.gamecenter.collection;
import android.app.Application;
import com.gh.common.AppExecutor;
import com.gh.common.history.HistoryDatabase;
import com.gh.common.history.HistoryHelper;
import com.gh.common.util.UrlFilterUtils;
import com.gh.gamecenter.baselist.ListViewModel;
import com.gh.gamecenter.baselist.LoadType;
import com.gh.gamecenter.entity.NewsEntity;
import com.gh.gamecenter.entity.ViewsEntity;
import com.gh.gamecenter.info.NewsViewsRepository;
@ -25,7 +28,7 @@ import io.reactivex.Single;
public class ArticleViewModel extends ListViewModel<NewsEntity, NewsEntity> {
public ArticleFragment.Type type;
public String type;
NewsViewsRepository<ViewsEntity> mNewsViewsRepository = new NewsViewsRepository<>();
@ -76,7 +79,7 @@ public class ArticleViewModel extends ListViewModel<NewsEntity, NewsEntity> {
@Override
public Single<List<NewsEntity>> provideDataSingle(int page) {
if (type == ArticleFragment.Type.COLLECTION) {
if (ArticleFragment.COLLECTION.equals(type)) {
return Single.fromObservable(RetrofitManager.getInstance(getApplication()).getApi().getCollectionArticle(UserManager.getInstance().getUserId(), page));
} else {
if (page > 5) {
@ -90,4 +93,20 @@ public class ArticleViewModel extends ListViewModel<NewsEntity, NewsEntity> {
public Observable<List<NewsEntity>> provideDataObservable(int page) {
return null;
}
public void removeHistory(NewsEntity newsEntity) {
List<NewsEntity> originList = mResultLiveData.getValue();
if (originList != null) {
HistoryHelper.deleteNewsEntity(newsEntity.getId());
originList.remove(newsEntity);
if (originList.size() == 0) {
AppExecutor.getUiExecutor().executeWithDelay(() -> {
load(LoadType.REFRESH);
}, 100);
} else {
mResultLiveData.postValue(originList);
}
}
}
}

View File

@ -40,10 +40,10 @@ public class CollectionWrapperFragment extends BaseFragment_TabLayout {
@Override
protected void initFragmentList(List<Fragment> fragments) {
fragments.add(AnswerFragment.getInstance(AnswerFragment.Type.COLLECTION).with(getArguments()));
fragments.add(CommunityArticleFragment.getInstance(CommunityArticleFragment.Type.COLLECTION).with(getArguments()));
fragments.add(new AnswerFragment().with(getArguments()));
fragments.add(new CommunityArticleFragment().with(getArguments()));
fragments.add(new ToolsFragment().with(getArguments()));
fragments.add(ArticleFragment.getInstance(ArticleFragment.Type.COLLECTION).with(getArguments()));
fragments.add(new ArticleFragment().with(getArguments()));
Bundle arguments = getArguments();
if (arguments != null)

View File

@ -6,18 +6,18 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.ItemViewType
import com.gh.common.syncpage.ISyncAdapterHandler
import com.gh.common.util.*
import com.gh.common.util.DialogHelper
import com.gh.common.util.DialogUtils
import com.gh.common.util.consume
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.qa.entity.ArticleEntity
class CommunityArticleAdapter(context: Context,
val mType: CommunityArticleFragment.Type,
private val mViewModel: CommunityArticleViewModel,
private val mEntrance: String) : ListAdapter<ArticleEntity>(context), ISyncAdapterHandler {
@ -46,13 +46,29 @@ class CommunityArticleAdapter(context: Context,
override fun getItemCount(): Int = if (mEntityList.size == 0) 0 else mEntityList.size + 1
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is CommunityAnswerItemViewHolder) {
val path = if (mType == CommunityArticleFragment.Type.COLLECTION) "我的收藏-文章列表" else "浏览记录-文章列表"
var path = ""
val entity = mEntityList[position]
holder.bindArticleItem(entity, mEntrance, path)
if (mViewModel.type == CommunityArticleFragment.Type.COLLECTION.value) {
path = "我的收藏-文章列表"
} else {
path = "浏览记录-文章列表"
holder.itemView.setOnLongClickListener {
consume {
DialogHelper.showDialog(holder.binding.root.context,
"删除记录",
"删除浏览记录将不可恢复,确定删除吗?",
"确定",
"取消", {
mViewModel.removeHistory(entity)
})
}
}
}
holder.bindArticleItem(entity, mEntrance, path)
holder.itemView.setOnClickListener {
if (entity.active) {
mContext.startActivity(ArticleDetailActivity.getIntent(mContext, entity.community, entity.id, mEntrance, path))

View File

@ -1,8 +1,10 @@
package com.gh.gamecenter.collection
import android.os.Bundle
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.CollectionUtils
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.eventbus.EBCollectionChanged
@ -12,25 +14,35 @@ import org.greenrobot.eventbus.ThreadMode
class CommunityArticleFragment : ListFragment<ArticleEntity, CommunityArticleViewModel>() {
private var mType = Type.COLLECTION
private var mType = Type.COLLECTION.value
private var mViewModel: CommunityArticleViewModel? = null
private var mAdapter: CommunityArticleAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
mType = arguments?.getString(EntranceUtils.KEY_TYPE, Type.COLLECTION.value) ?: Type.COLLECTION.value
super.onCreate(savedInstanceState)
}
override fun provideListAdapter(): CommunityArticleAdapter {
if (mAdapter == null) {
mAdapter = CommunityArticleAdapter(requireContext(), mType, mListViewModel, mEntrance)
mAdapter = CommunityArticleAdapter(requireContext(), mViewModel!!, mEntrance)
}
return mAdapter!!
}
override fun provideListViewModel(): CommunityArticleViewModel {
return ViewModelProviders.of(this).get(CommunityArticleViewModel::class.java).apply { type = mType }
if (mViewModel == null) {
mViewModel = ViewModelProviders.of(this).get(CommunityArticleViewModel::class.java).apply { type = mType }
}
return mViewModel!!
}
// 收藏事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(changed: EBCollectionChanged) {
if (changed.collectionType == CollectionUtils.CollectionType.communityArticle
&& mType == Type.COLLECTION) {
&& mType == Type.COLLECTION.value) {
mListViewModel.load(LoadType.REFRESH)
}
}
@ -43,18 +55,9 @@ class CommunityArticleFragment : ListFragment<ArticleEntity, CommunityArticleVie
return true
}
companion object {
@JvmStatic
fun getInstance(type: Type): CommunityArticleFragment {
val fragment = CommunityArticleFragment()
fragment.mType = type
return fragment
}
}
enum class Type(val value: String) {
COLLECTION("collection"),
enum class Type {
COLLECTION,
HISTORY
HISTORY("history")
}
}

View File

@ -2,9 +2,12 @@ package com.gh.gamecenter.collection
import android.annotation.SuppressLint
import android.app.Application
import com.gh.common.AppExecutor
import com.gh.common.history.HistoryDatabase
import com.gh.common.history.HistoryHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.retrofit.BiResponse
@ -21,14 +24,14 @@ import retrofit2.HttpException
class CommunityArticleViewModel(application: Application) : ListViewModel<ArticleEntity, ArticleEntity>(application) {
var type: CommunityArticleFragment.Type = CommunityArticleFragment.Type.COLLECTION
var type: String = CommunityArticleFragment.Type.COLLECTION.value
override fun provideDataObservable(page: Int): Observable<MutableList<ArticleEntity>>? {
return null
}
override fun provideDataSingle(page: Int): Single<List<ArticleEntity>> {
return if (type == CommunityArticleFragment.Type.COLLECTION) {
return if (type == CommunityArticleFragment.Type.COLLECTION.value) {
Single.fromObservable(RetrofitManager.getInstance(getApplication()).api.getCollectionCommunityArticle(UserManager.getInstance().userId, page))
} else {
if (page > 5) {
@ -43,6 +46,18 @@ class CommunityArticleViewModel(application: Application) : ListViewModel<Articl
mResultLiveData.addSource<List<ArticleEntity>>(mListLiveData) { mResultLiveData.postValue(it) }
}
fun removeHistory(articleEntity: ArticleEntity) {
mResultLiveData.value?.let {
HistoryHelper.deleteArticleEntity(articleEntity.id)
it.remove(articleEntity)
if (it.size == 0) {
AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
} else {
mResultLiveData.postValue(it)
}
}
}
fun deleteCollection(communityId: String, articleId: String) {
RetrofitManager.getInstance(getApplication()).api

View File

@ -5,20 +5,17 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.ItemViewType
import com.gh.common.util.DirectUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.toSimpleCount
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.NormalListViewModel
import com.gh.gamecenter.databinding.VideoItemBinding
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.video.VideoItemViewHolder
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
class VideoAdapter(context: Context,
val mViewModel: NormalListViewModel<MyVideoEntity>, val mVideoStyle: String) : ListAdapter<MyVideoEntity>(context) {
val mViewModel: VideoViewModel, val mVideoStyle: String) : ListAdapter<MyVideoEntity>(context) {
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER
return ItemViewType.ITEM_BODY
@ -55,6 +52,18 @@ class VideoAdapter(context: Context,
DirectUtils.directToVideoDetail(mContext, entity.id, VideoDetailContainerViewModel.Location.VIDEO_HOT.value, false, path = getPath())
}
}
holder.itemView.setOnLongClickListener {
consume {
DialogHelper.showDialog(holder.binding.root.context,
"删除记录",
"删除浏览记录将不可恢复,确定删除吗?",
"确定",
"取消", {
mViewModel.removeHistory(entity)
})
}
}
} else if (holder is FooterViewHolder) {
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
}

View File

@ -2,30 +2,22 @@ package com.gh.gamecenter.collection
import android.os.Bundle
import android.view.View
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.Config
import com.gh.common.history.HistoryDatabase
import com.gh.common.util.dip2px
import com.gh.common.util.viewModelProvider
import com.gh.common.view.GridSpacingItemDecoration
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.baselist.NormalListViewModel
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.Observable
import io.reactivex.Single
class VideoFragment : ListFragment<MyVideoEntity, NormalListViewModel<MyVideoEntity>>() {
class VideoFragment : ListFragment<MyVideoEntity, VideoViewModel>() {
private var mAdapter: VideoAdapter? = null
private var mViewModel: VideoViewModel? = null
private lateinit var mVideoStyle: String
override fun provideListAdapter(): VideoAdapter {
if (mAdapter == null) {
mAdapter = VideoAdapter(context!!, mListViewModel, mVideoStyle)
mAdapter = VideoAdapter(requireContext(), mViewModel!!, mVideoStyle)
}
return mAdapter!!
}
@ -54,27 +46,12 @@ class VideoFragment : ListFragment<MyVideoEntity, NormalListViewModel<MyVideoEnt
mListRv.layoutManager = gridLayoutManager
}
override fun provideListViewModel(): NormalListViewModel<MyVideoEntity> {
val factory = NormalListViewModel.Factory(HaloApp.getInstance().application, this)
return ViewModelProviders.of(this, factory).get(NormalListViewModel::class.java) as NormalListViewModel<MyVideoEntity>
}
override fun provideDataObservable(page: Int): Observable<MutableList<MyVideoEntity>>? {
if (mVideoStyle == VideoStyle.COLLECT.value) {
return RetrofitManager.getInstance(context).api.getCollectionVideo(UserManager.getInstance().userId, page, Config.VIDEO_PAGE_SIZE)
override fun provideListViewModel(): VideoViewModel {
if (mViewModel == null) {
mViewModel = viewModelProvider()
}
return null
}
override fun provideDataSingle(page: Int): Single<MutableList<MyVideoEntity>>? {
if (page > 5) {
mAdapter?.loadChange(LoadStatus.LIST_OVER)
return null
}
if (mVideoStyle == VideoStyle.BROWSING_HISTORY.value) {
return HistoryDatabase.instance.videoHistoryDao().getVideoWithOffset(20, (page - 1) * 20)
}
return null
mViewModel?.type = mVideoStyle
return mViewModel!!
}
enum class VideoStyle(val value: String) {

View File

@ -0,0 +1,46 @@
package com.gh.gamecenter.collection
import android.app.Application
import com.gh.common.AppExecutor
import com.gh.common.constant.Config
import com.gh.common.history.HistoryDatabase
import com.gh.common.history.HistoryHelper
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
class VideoViewModel(application: Application) : ListViewModel<MyVideoEntity, MyVideoEntity>(application) {
var type = ""
override fun provideDataObservable(page: Int): Observable<MutableList<MyVideoEntity>>? {
if (type == VideoFragment.VideoStyle.COLLECT.value) {
return RetrofitManager.getInstance(getApplication()).api.getCollectionVideo(UserManager.getInstance().userId, page, Config.VIDEO_PAGE_SIZE)
}
return null
}
override fun provideDataSingle(page: Int): Single<MutableList<MyVideoEntity>>? {
if (page > 5) {
return Single.create { it.onSuccess(arrayListOf()) }
}
if (type == VideoFragment.VideoStyle.BROWSING_HISTORY.value) {
return HistoryDatabase.instance.videoHistoryDao().getVideoWithOffset(20, (page - 1) * 20)
}
return null
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
}
fun removeHistory(myVideoEntity: MyVideoEntity) {
HistoryHelper.deleteVideoEntity(myVideoEntity.id)
AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
}
}

View File

@ -11,6 +11,7 @@ import androidx.fragment.app.Fragment
import com.gh.base.fragment.BaseFragment_TabLayout
import com.gh.common.util.MtaHelper
import com.gh.common.util.dip2px
import com.gh.common.util.visibleIf
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
@ -33,8 +34,19 @@ class DownloadFragment : BaseFragment_TabLayout() {
const val INDEX_UPDATE = 1
}
lateinit var mDownloadNumber: TextView
lateinit var mUpdateNumber: TextView
// 下载 tab 是否被手动选中过
private var mIsDownloadTabHasBeenSelected: Boolean = false
private var mIsUpdateTabHasBeenSelected: Boolean = false
private lateinit var mDownloadNumber: TextView
private lateinit var mUpdateNumber: TextView
private lateinit var mDownloadManager: DownloadManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mDownloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
}
override fun initFragmentList(fragments: MutableList<Fragment>) {
fragments.add(GameDownloadFragment())
@ -67,14 +79,17 @@ class DownloadFragment : BaseFragment_TabLayout() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpdateHint()
setDownloadHint()
updateUpdateHint()
updateDownloadHint()
if (mDownloadNumber.visibility != View.VISIBLE) {
if (mDownloadNumber.visibility != View.VISIBLE && mUpdateNumber.visibility == View.VISIBLE) {
mViewPager.currentItem = INDEX_UPDATE
} else {
// 进入并选中下载管理时立马标记已下载待安装为已读
DownloadManager.getInstance(HaloApp.getInstance().application).markDownloadedTaskAsRead()
mIsDownloadTabHasBeenSelected = true
updateDownloadHint()
mDownloadManager.markDownloadingTaskAsRead()
mDownloadManager.markDownloadedTaskAsRead()
}
}
@ -84,11 +99,14 @@ class DownloadFragment : BaseFragment_TabLayout() {
DownloadManager.getInstance(requireContext()).checkRetryDownload()
}
override fun onStop() {
super.onStop()
override fun onParentActivityFinish() {
super.onParentActivityFinish()
// onDestory 的回调有点晚,不能及时更新外部红点
DownloadManager.getInstance(HaloApp.getInstance().application).markDownloadedTaskAsRead()
// onDestroy 的回调有点晚,不能及时更新外部红点
if (mIsDownloadTabHasBeenSelected || mViewPager.currentItem == INDEX_DOWNLOAD) {
mDownloadManager.markDownloadingTaskAsRead()
mDownloadManager.markDownloadedTaskAsRead()
}
}
override fun onPageSelected(index: Int) {
@ -101,7 +119,13 @@ class DownloadFragment : BaseFragment_TabLayout() {
}
if (index == INDEX_UPDATE) {
DownloadManager.getInstance(HaloApp.getInstance().application).markUpdatableTaskAsRead()
mIsUpdateTabHasBeenSelected = true
updateUpdateHint()
mDownloadManager.markUpdatableTaskAsRead()
} else if (index == INDEX_DOWNLOAD) {
mIsDownloadTabHasBeenSelected = true
updateDownloadHint()
mDownloadManager.markDownloadingTaskAsRead()
}
MtaHelper.onEvent("下载管理", "Tab", tabName)
@ -117,13 +141,13 @@ class DownloadFragment : BaseFragment_TabLayout() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(changed: EBDownloadChanged) {
if ("download" == changed.type) {
setDownloadHint()
updateDownloadHint()
} else if ("update" == changed.type) {
setUpdateHint()
updateUpdateHint()
}
}
private fun setDownloadHint() {
private fun updateDownloadHint() {
val downloadData = DownloadManager.getInstance(context).all
if (downloadData.size > 0) {
mDownloadNumber.visibility = View.VISIBLE
@ -140,31 +164,35 @@ class DownloadFragment : BaseFragment_TabLayout() {
}
val layoutParams = mDownloadNumber.layoutParams as LinearLayout.LayoutParams
if (downloadingCount > 0) {
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
layoutParams.setMargins(4F.dip2px(), 0, 0, 0F.dip2px())
mDownloadNumber.setBackgroundColor(Color.TRANSPARENT)
mDownloadNumber.text = downloadingCount.toString()
} else {
layoutParams.width = 6F.dip2px()
layoutParams.height = 6F.dip2px()
layoutParams.setMargins(2F.dip2px(), 0, 0, 3F.dip2px())
mDownloadNumber.setBackgroundResource(R.drawable.oval_hint_red_bg)
mDownloadNumber.text = ""
when {
downloadingCount > 0 -> {
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
layoutParams.setMargins(4F.dip2px(), 0, 0, 0F.dip2px())
mDownloadNumber.setBackgroundColor(Color.TRANSPARENT)
mDownloadNumber.text = downloadingCount.toString()
}
mDownloadManager.isContainsUnreadDownloadedTask -> {
layoutParams.width = 6F.dip2px()
layoutParams.height = 6F.dip2px()
layoutParams.setMargins(2F.dip2px(), 0, 0, 3F.dip2px())
mDownloadNumber.setBackgroundResource(R.drawable.oval_hint_red_bg)
mDownloadNumber.text = ""
}
else -> mDownloadNumber.visibility = View.GONE
}
mDownloadNumber.layoutParams = layoutParams
}
private fun setUpdateHint() {
var updateSize = 0
for (updateEntity in PackagesManager.getUpdateList()) {
if (updateEntity.isShowPlugin(PluginLocation.only_index)) updateSize++
private fun updateUpdateHint() {
if (mIsUpdateTabHasBeenSelected) {
mUpdateNumber.visibility = View.INVISIBLE
return
}
mUpdateNumber.visibility = if (updateSize != 0) {
View.VISIBLE
} else View.INVISIBLE
val updateCount = mDownloadManager.getUnreadUpdateCount(PackagesManager.getUpdateList().filter { it.isShowPlugin(PluginLocation.only_index) })
mUpdateNumber.visibleIf(updateCount != 0)
}
@Subscribe(threadMode = ThreadMode.MAIN)

View File

@ -12,11 +12,6 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.gh.common.util.BitmapUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
@ -50,6 +45,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
/**
* Created by LGT on 2016/8/15.
@ -155,6 +154,11 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
downloadTitle = downloadEntity.getName() + " - " + platform;
}
}
if (!TextUtils.isEmpty(downloadEntity.getVersionName())) {
downloadTitle = downloadTitle + " - V" + downloadEntity.getVersionName();
}
if (!viewHolder.dmTitle.getText().equals(downloadTitle)) {
viewHolder.dmTitle.setText(downloadTitle);
}

View File

@ -8,17 +8,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.gh.common.AppExecutor;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureSource;
import com.gh.common.exposure.ExposureType;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.exposure.IExposable;
import com.gh.common.history.HistoryHelper;
import com.gh.common.util.ApkActiveUtils;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DataUtils;
@ -65,6 +61,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -128,7 +128,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
.subscribe(new Response<GameEntity>() {
@Override
public void onResponse(GameEntity response) {
List<GameUpdateEntity> update = PackageUtils.getUpdateData(mContext, response);
List<GameUpdateEntity> update = PackageUtils.getUpdateData(response);
if (update.size() > 0) {
updateList.addAll(update);
// PackagesManager.INSTANCE.addUpdateList(update);
@ -351,7 +351,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
DialogUtils.checkDownload(mContext, updateEntity.getSize(), isSubscribe -> {
if (str.contains("")) {
if (updateEntity.getPluggableCollection() != null) {
DownloadDialog.showDownloadDialog(mContext, updateEntity.transformGameEntity(), entrance, finalPluginDesc + "化:" + updateEntity.getName());
DownloadDialog.showDownloadDialog(mContext, updateEntity.transformGameEntity(), updateEntity.getExposureEvent(), entrance, finalPluginDesc + "化:" + updateEntity.getName());
return;
} else {
viewHolder.guUpdate.setText(R.string.downloading);
@ -549,6 +549,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
if (isSubscribe) {
DownloadManager.getInstance(mContext).subscribe(downloadEntity);
} else {
HistoryHelper.insertGameEntity(updateEntity);
DownloadManager.getInstance(mContext).add(downloadEntity);
}

View File

@ -18,7 +18,7 @@ data class AmwayCommentEntity(
var id: String,
var icon: String,
var name: String,
@SerializedName(value="tag", alternate=["tag_style"])
@SerializedName(value="new_tag_style")
var tag: List<TagStyleEntity>? = arrayListOf(),
var star: Float) : Parcelable {
fun toGameEntity() : GameEntity {

View File

@ -0,0 +1,10 @@
package com.gh.gamecenter.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
class CommentDraft(
@PrimaryKey
var id: String,
var draft: String)

View File

@ -19,7 +19,7 @@ data class GameInstall(
fun transformGameInstall(game: GameEntity, installedPkgName: String): GameInstall {
val gameInstall = GameInstall()
val application = HaloApp.getInstance().application
gameInstall.isSignature = PackageUtils.isSignature(application, installedPkgName)
gameInstall.isSignature = PackageUtils.isSignedByGh(application, installedPkgName)
gameInstall.installTime = PackageUtils.getInstalledTime(application, installedPkgName)
gameInstall.id = game.id
gameInstall.name = game.name

View File

@ -1,7 +1,11 @@
package com.gh.gamecenter.entity
import android.os.Parcelable
import com.gh.common.annotation.SyncPage
import com.gh.common.syncpage.SyncFieldConstants
import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.qa.entity.CommunityVideoEntity
import com.gh.gamecenter.qa.entity.Questions
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
@ -15,13 +19,15 @@ data class PersonalHistoryEntity(
var count: Count = Count(),
val time: Long = 0,
var title: String = "",
var description: String = "",
val community: CommunityEntity = CommunityEntity(),
var videos: List<CommunityVideoEntity> = ArrayList(),
var user: PersonalEntity? = null,
@SerializedName("fold_users")
var foldUsers: List<UserEntity>? = null,
val images: List<String> = ArrayList(),
var comment: Comment = Comment()) :Parcelable{
val me: MeEntity = MeEntity(),
var comment: Comment = Comment()) : Parcelable {
fun getPassVideos(): List<CommunityVideoEntity> {
val passVideos = arrayListOf<CommunityVideoEntity>()
@ -36,20 +42,25 @@ data class PersonalHistoryEntity(
data class Question(
@SerializedName("_id")
val id: String = "",
var title: String = ""):Parcelable
var title: String = "") : Parcelable
@Parcelize
data class Count(
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_COMMENT_COUNT, SyncFieldConstants.ARTICLE_COMMENT_COUNT])
var comment: Int = -1,
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_VOTE_COUNT, SyncFieldConstants.ARTICLE_VOTE_COUNT])
var vote: Int = -1,
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_COUNT])
var answer: Int = -1,
var reply: Int = -1):Parcelable
var reply: Int = -1) : Parcelable
@Parcelize
data class Comment(
@SerializedName("_id")
val id: String = "",
var star: Int = 0,
var content: String = "",
val game: Game = Game()):Parcelable
val game: Game = Game()) : Parcelable
@Parcelize
data class Game(
@ -60,11 +71,41 @@ data class PersonalHistoryEntity(
val nameSuffix: String = "",
val icon: String = "",
@SerializedName(value = "tag", alternate = ["tag_style"])
@SerializedName(value = "new_tag_style")
val tag: ArrayList<TagStyleEntity> = ArrayList(),
val star: Float = 0F,
@SerializedName("libao_exists")
var isLibaoExists: Boolean = false,
val active: Boolean = true//游戏是否被隐藏 false被隐藏
) : Parcelable
// 因为内容是文章和回答混合的,所以返回的有可能是文章的实体
fun transformAnswerEntity(): AnswerEntity {
val question = Questions(title = title)
val answer = AnswerEntity()
answer.id = id
answer.questions = question
answer.brief = brief
answer.images = images
answer.videos = videos
answer.time = time
answer.vote = count.vote
answer.commentCount = count.comment
answer.me = me
if (type.contains("article")) {
answer.type = "community_article"
}
return answer
}
fun transformQuestionEntity(): Questions {
val question = Questions(title = title)
question.answerCount = count.answer
question.me = me
question.id = id
question.images = images as ArrayList<String>
question.communityName = community.name
return question
}
}

View File

@ -70,7 +70,7 @@ class GameFragment : NormalFragment() {
mBinding.loadStatus = it
mListAdapter.setLoadStatus(it)
mNoConn.visibility = if (it == LoadStatus.INIT_FAILED) View.VISIBLE else View.GONE
mLoading.visibility = if (it == LoadStatus.INIT_LOADING) View.VISIBLE else View.GONE
mLoading.visibility = if (it == LoadStatus.INIT_LOADING && !mBinding.gameRefresh.isRefreshing) View.VISIBLE else View.GONE
if (it != LoadStatus.INIT_LOADING) {
mSkeleton.hide()
} else {

View File

@ -370,6 +370,7 @@ class GameFragmentAdapter(context: Context,
entity.type == EntranceUtils.HOST_COMMUNITY -> DirectUtils.directToCommunity(mContext, CommunityEntity(entity.link!!, entity.text!!))
entity.type == "top_game_comment" -> DirectUtils.directToAmway(mContext, null, "(推荐入口)", "")
entity.type == "server" -> mContext.startActivity(GameServersActivity.getIntent(mContext, "(推荐入口)", ""))
//entity.type == "h5_game_center" -> DirectUtils.directLetoGameCenter(mContext)
else -> DialogUtils.showLowVersionDialog(mContext)
}
}

View File

@ -2,11 +2,9 @@ package com.gh.gamecenter.game.horizontal
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.StringUtils
import com.gh.common.util.dip2px
import com.gh.common.util.*
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.GameHorizontalItemBinding
@ -55,6 +53,11 @@ class GameHorizontalAdapter(context: Context,
override fun onBindViewHolder(holder: GameHorizontalItemViewHolder, position: Int) {
holder.binding.root.setPadding(0, 0, 0, 8f.dip2px())
if (exposureEventList.isNullOrEmpty()) {
val params = holder.binding.root.layoutParams as RecyclerView.LayoutParams
params.width = RecyclerView.LayoutParams.WRAP_CONTENT
holder.binding.root.layoutParams = params
}
val gameEntity = mSubjectEntity.data!![position + getIndex()]
holder.binding.game = gameEntity

View File

@ -20,6 +20,7 @@ import com.facebook.drawee.view.SimpleDraweeView
import com.gh.base.BaseActivity
import com.gh.base.adapter.FragmentAdapter
import com.gh.base.fragment.BaseFragment_TabLayout
import com.gh.common.constant.Constants
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.*
import com.gh.common.view.FlexLinearLayout
@ -49,6 +50,7 @@ import com.gh.gamecenter.suggest.SuggestType
import com.gh.gamecenter.tag.TagsActivity
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayout
import com.google.gson.reflect.TypeToken
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.WebFragment
import com.lightgame.download.DataWatcher
@ -471,6 +473,9 @@ class GameDetailFragment : NormalFragment() {
val descFragment = DescFragment()
descFragment.arguments = bundle
// TODO 从 fragmentManager 里把已有的 fragment 找回来,而不是每次都新建一个
fragmentsList.clear()
tabTitleList.clear()
fragmentsList.add(descFragment)
tabTitleList.add(getString(R.string.game_detail_desc))
@ -911,10 +916,20 @@ class GameDetailFragment : NormalFragment() {
private fun releaseVideo() {
if (mViewModel.displayTopVideo) {
recordVideoSchedule()
mTopVideoView.release()
mTopVideoView.disposableTimer()
}
}
//保存视频进度
private fun recordVideoSchedule(){
val datas = SPUtils.getString(Constants.SP_TOP_VIDEO_SCHEDULE)
val type = object : TypeToken<HashMap<String, Long>>() {}.type
val schedules = GsonUtils.gson.fromJson<HashMap<String, Long>>(datas, type)
?: hashMapOf()
schedules[mTopVideoView.video?.url ?: ""] = mTopVideoView.getCurrentPosition()
SPUtils.setString(Constants.SP_TOP_VIDEO_SCHEDULE, GsonUtils.toJson(schedules))
}
private fun tabPerformClick(position: Int) {
if (!mIsPreferredTabSelected) {

View File

@ -15,10 +15,12 @@ import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.OnListClickListener
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.view.ExpandTextView
import com.gh.common.view.GridSpacingItemColorDecoration
import com.gh.common.view.divider.HorizontalDividerItemDecoration
import com.gh.common.view.divider.VerticalDividerItemDecoration
import com.gh.gamecenter.GameNewsActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.SuggestionActivity
@ -53,7 +55,8 @@ class DescAdapter(context: Context,
var descItemList = arrayListOf<DetailEntity>()
private var mExpandSparseBooleanArray = SparseBooleanArray()
private var mExpandableTextExpandStatusSparseBooleanArray = SparseBooleanArray()
private var mCustomColumnTagsExpandStatusSparseBooleanArray = SparseBooleanArray()
fun updateDescItemList(descItemList: ArrayList<DetailEntity>) {
this.descItemList = descItemList
@ -76,7 +79,6 @@ class DescAdapter(context: Context,
DetailEntity.Type.RECOMMENDED_GAMES.value -> RECOMMENDED_GAMES
DetailEntity.Type.CUSTOM_COLUMN.value -> CUSTOM_COLUMN
DetailEntity.Type.NOTICE.value -> NOTICE
DetailEntity.Type.INFERIOR_CUSTOM_COLUMN.value -> INFERIOR_CUSTOM_COLUMN
else -> FOOTER
}
}
@ -86,9 +88,6 @@ class DescAdapter(context: Context,
COMMENTS -> {
GameDetailCommentsViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.gamedetail_item_comments, parent, false))
}
INFERIOR_CUSTOM_COLUMN -> {
GameDetailInferiorCustomColumnViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.gamedetail_item_inferior_custom_column, parent, false))
}
CUSTOM_COLUMN -> {
GameDetailCustomColumnViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.gamedetail_item_custom_column, parent, false))
}
@ -140,8 +139,6 @@ class DescAdapter(context: Context,
when (holder) {
is GameDetailNoticeViewHolder -> bindNoticeViewHolder(holder, descItemList[position])
is GameDetailInferiorCustomColumnViewHolder -> bindCustomColumnViewHolder(holder, descItemList[position])
is GameDetailCustomColumnViewHolder -> bindCustomColumnViewHolder(holder, descItemList[position])
is GamesRecommendedGalleryViewHolder -> bindGamesRecommendedGalleryViewHolder(holder, position)
@ -222,7 +219,9 @@ class DescAdapter(context: Context,
linkImageIv = viewHolder.binding.linkImageIv,
linkHintIv = viewHolder.binding.linkHintIv,
linkHintTv = viewHolder.binding.linkHintTv,
linkHintArrowIv = viewHolder.binding.linkHintArrowIv)
linkHintArrowIv = viewHolder.binding.linkHintArrowIv,
expandTagsHint = viewHolder.binding.expandTagsHint
)
viewHolder.binding.customColumn = customColumn
viewHolder.binding.shouldBoundToNextItem = detailEntity.shouldBoundTogetherWithNextItem
@ -237,36 +236,20 @@ class DescAdapter(context: Context,
detailEntity.shouldBoundTogetherWithNextItem)
}
// 绑定低优先级自定义栏目
private fun bindCustomColumnViewHolder(viewHolder: GameDetailInferiorCustomColumnViewHolder, detailEntity: DetailEntity) {
val customColumn = detailEntity.customColumn!!
updateCommonCustomView(
customColumn,
position = viewHolder.adapterPosition,
titleHintTv = viewHolder.binding.titleHintTv,
contentTv = viewHolder.binding.contentTv,
recyclerView = viewHolder.binding.recyclerview,
linkImageIv = viewHolder.binding.linkImageIv,
linkHintIv = viewHolder.binding.linkHintIv,
linkHintTv = viewHolder.binding.linkHintTv,
linkHintArrowIv = viewHolder.binding.linkHintArrowIv)
viewHolder.binding.customColumn = customColumn
viewHolder.binding.executePendingBindings()
}
//绑定大家都在玩
private fun bindGamesRecommendedGalleryViewHolder(viewHolder: GamesRecommendedGalleryViewHolder, position: Int) {
viewHolder.binding.galleryRv.isNestedScrollingEnabled = false
viewHolder.binding.executePendingBindings()
//分割线
val params = viewHolder.itemView.layoutParams as RecyclerView.LayoutParams
params.topMargin = DisplayUtils.dip2px(8f)
viewHolder.itemView.layoutParams = params
// val params = viewHolder.itemView.layoutParams as RecyclerView.LayoutParams
// params.topMargin = DisplayUtils.dip2px(8f)
// viewHolder.itemView.layoutParams = params
//重新调整间距
// viewHolder.itemView.setPadding(viewHolder.itemView.paddingLeft, viewHolder.itemView.paddingTop - DisplayUtils.dip2px(4f), viewHolder.itemView.paddingRight, viewHolder.itemView.paddingBottom)
val galleryParams = viewHolder.binding.galleryRv.layoutParams as ConstraintLayout.LayoutParams
galleryParams.topMargin = DisplayUtils.dip2px(8f)
galleryParams.topMargin = DisplayUtils.dip2px(6f)
galleryParams.rightMargin = 0
viewHolder.binding.galleryRv.layoutParams = galleryParams
val subjectEntity = descItemList[position].recommendedGames
@ -277,6 +260,12 @@ class DescAdapter(context: Context,
subjectAdapter = GameHorizontalAdapter(mContext, subjectEntity, true)
subjectAdapter.gameName = gameName ?: ""
(viewHolder.binding.galleryRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
val dividerWidth = (DisplayUtils.getScreenWidth() - 20F.dip2px() * 2 - 72F.dip2px() * 4) / 3
val itemDecoration = VerticalDividerItemDecoration.Builder(mContext)
.size(dividerWidth)
.color(ContextCompat.getColor(mContext, R.color.transparent)).build()
viewHolder.binding.galleryRv.addItemDecoration(itemDecoration)
viewHolder.binding.galleryRv.adapter = subjectAdapter
} else {
(subjectAdapter as GameHorizontalAdapter).checkResetData(subjectEntity)
@ -298,13 +287,14 @@ class DescAdapter(context: Context,
if (viewHolder.binding.recyclerview.adapter == null) {
val commentsAdapter = viewHolder.binding.recyclerview.adapter as DescCommentsAdapter?
?: DescCommentsAdapter(mContext, mViewModel, mEntrance, gameName)
viewHolder.binding.recyclerview.background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
viewHolder.binding.recyclerview.isNestedScrollingEnabled = false
viewHolder.binding.recyclerview.adapter = commentsAdapter
viewHolder.binding.recyclerview.layoutManager = LinearLayoutManager(mContext)
val itemDecoration = HorizontalDividerItemDecoration.Builder(mContext)
.size(DisplayUtils.dip2px(1f))
.size(DisplayUtils.dip2px(0.5f))
.margin(DisplayUtils.dip2px(16f))
.color(ContextCompat.getColor(mContext, R.color.text_eeeeee)).build()
.color(ContextCompat.getColor(mContext, R.color.text_f5f5f5)).build()
viewHolder.binding.recyclerview.addItemDecoration(itemDecoration)
viewHolder.binding.tvAll.setOnClickListener {
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
@ -327,6 +317,8 @@ class DescAdapter(context: Context,
viewHolder.binding.galleryRv.isNestedScrollingEnabled = false
if (viewHolder.binding.galleryRv.adapter == null) {
viewHolder.binding.galleryRv.apply {
background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 16F.dip2px())
layoutManager = LinearLayoutManager(mContext)
val relatedVersionAdapter = GameRelatedVersionAdapter(mContext, gameName
?: "", relatedVersion!!, mEntrance)
@ -431,19 +423,19 @@ class DescAdapter(context: Context,
holder.binding.containerPaddingTop = itemData.paddingTop
holder.binding.containerPaddingBottom = itemData.paddingBottom
holder.binding.contentTv.text = updateContent?.updateDes ?: ""
val maxDesLines = if (mExpandSparseBooleanArray.get(holder.adapterPosition)) Int.MAX_VALUE else 4
val maxDesLines = if (mExpandableTextExpandStatusSparseBooleanArray.get(holder.adapterPosition)) Int.MAX_VALUE else 4
holder.binding.contentTv.setExpandMaxLines(maxDesLines)
holder.binding.contentTv.setIsExpanded(Int.MAX_VALUE == maxDesLines)
holder.binding.executePendingBindings()
holder.binding.contentTv.setExpandCallback {
mExpandSparseBooleanArray.put(holder.adapterPosition, true)
mExpandableTextExpandStatusSparseBooleanArray.put(holder.adapterPosition, true)
MtaHelper.onEvent("游戏详情_新", "展开更新内容", gameName)
}
holder.binding.historyVersionTv.setOnClickListener {
MtaHelper.onEvent("历史版本", "进入", gameName)
MtaHelper.onEvent("游戏详情_新", "更新内容_历史版本", gameName)
val intent = HistoryApkListActivity.getIntent(mContext, mViewModel.game
?: GameEntity(), mEntrance, "更新内容")
?: GameEntity(), mEntrance, "游戏详情[${gameName}]:更新内容")
mContext.startActivity(intent)
}
holder.binding.historyVersionTv.visibility = if (updateContent?.historyApkStatus == "on" && updateContent.historyApkCount != 0) View.VISIBLE else View.GONE
@ -470,7 +462,7 @@ class DescAdapter(context: Context,
adapter = serviceAdapter
val itemDecoration = HorizontalDividerItemDecoration.Builder(mContext)
.size(DisplayUtils.dip2px(12f))
.color(ContextCompat.getColor(mContext, R.color.white)).build()
.color(ContextCompat.getColor(mContext, R.color.transparent)).build()
addItemDecoration(itemDecoration)
}
}
@ -534,15 +526,15 @@ class DescAdapter(context: Context,
viewHolder.binding.containerPaddingBottom = itemData.paddingBottom
viewHolder.binding.galleryRv.isNestedScrollingEnabled = false
viewHolder.binding.galleryRv.apply {
background = ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5)
background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
layoutManager = LinearLayoutManager(mContext)
val libaoAdapter = GameLibaoAdapter(mContext, libao!!, gameName ?: "", mListListener)
adapter = libaoAdapter
if (itemDecorationCount == 0) {
val itemDecoration = HorizontalDividerItemDecoration.Builder(mContext)
.size(DisplayUtils.dip2px(1f))
.size(DisplayUtils.dip2px(0.5f))
.margin(DisplayUtils.dip2px(16f))
.color(ContextCompat.getColor(mContext, R.color.text_eeeeee)).build()
.color(ContextCompat.getColor(mContext, R.color.text_f5f5f5)).build()
addItemDecoration(itemDecoration)
}
}
@ -598,13 +590,13 @@ class DescAdapter(context: Context,
private fun updateBoundableContainerBackground(container: View, shouldBoundTogetherWithPreviousItem: Boolean, shouldBoundTogetherWithNextItem: Boolean) {
container.background = if (shouldBoundTogetherWithPreviousItem && shouldBoundTogetherWithNextItem) {
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8)
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white)
} else if (shouldBoundTogetherWithPreviousItem) {
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5_bottom_only)
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5_bottm_only)
} else if (shouldBoundTogetherWithNextItem) {
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5_top_only)
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5_top_only)
} else {
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5)
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
}
}
@ -616,9 +608,10 @@ class DescAdapter(context: Context,
linkImageIv: View,
linkHintIv: View,
linkHintTv: View,
linkHintArrowIv: View) {
linkHintArrowIv: View,
expandTagsHint: View) {
val tags = if (customColumn.showInfoTag == true) customColumn.infoTag else arrayListOf()
val maxDesLines = if (mExpandSparseBooleanArray.get(position)) {
val maxDesLines = if (mExpandableTextExpandStatusSparseBooleanArray.get(position)) {
Int.MAX_VALUE
} else {
when {
@ -626,27 +619,42 @@ class DescAdapter(context: Context,
else -> customColumn.showDesRowNum!!
}
}
val layoutManager = if (customColumn.showInfoTagDesType == "expand" || mCustomColumnTagsExpandStatusSparseBooleanArray.get(position)) {
if (customColumn.showInfoTagDes == false) {
GridLayoutManager(mContext, 3)
} else {
mCustomColumnTagsExpandStatusSparseBooleanArray.put(position, true)
LinearLayoutManager(mContext)
}
} else {
GridLayoutManager(mContext, 3)
}
titleHintTv.paint?.isUnderlineText = true
contentTv.setExpandMaxLines(maxDesLines)
contentTv.setIsExpanded(Int.MAX_VALUE == maxDesLines)
contentTv.setTextWithHighlightedTextWrappedInsideWrapper(customColumn.des
?: "")
contentTv.setTextWithHighlightedTextWrappedInsideWrapper(customColumn.des ?: "")
recyclerView.isNestedScrollingEnabled = false
recyclerView.layoutManager = if (customColumn.showInfoTagDes == true) {
LinearLayoutManager(mContext)
} else {
GridLayoutManager(mContext, 3)
recyclerView.layoutManager = layoutManager
recyclerView.setOnClickListener {
if (customColumn.showInfoTagDes == true) {
customColumn.showExpandTagsHint = false
SPUtils.setBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT, true)
mCustomColumnTagsExpandStatusSparseBooleanArray.put(position, true)
notifyItemChanged(position)
}
}
expandTagsHint.goneIf(customColumn.showExpandTagsHint == false)
if (recyclerView.adapter == null) {
recyclerView.adapter = GameDetailCustomColumnAdapter(mContext)
}
(recyclerView.adapter as GameDetailCustomColumnAdapter)
.updateData(ArrayList(tags!!), customColumn.showInfoTagDes ?: false)
.updateData(ArrayList(tags!!), mCustomColumnTagsExpandStatusSparseBooleanArray.get(position))
contentTv.setExpandCallback {
mExpandSparseBooleanArray.put(position, true)
mExpandableTextExpandStatusSparseBooleanArray.put(position, true)
if (customColumn.name == "游戏简介") {
MtaHelper.onEvent("游戏详情_新", "展开游戏介绍", gameName)
} else {
@ -659,7 +667,7 @@ class DescAdapter(context: Context,
titleHintTv.performClick()
}
val linkClosure: (LinkEntity) -> Unit = {
val linkClosure: (LinkEntity) -> Unit = {
// 当配置的是不需要 id 也能跳转的时候直接跳转,否则都得根据是否有 ID 判断跳不跳
if (it.type == "top_game_comment"
|| it.type == "server"
@ -702,7 +710,6 @@ class DescAdapter(context: Context,
companion object {
const val CUSTOM_COLUMN = 64 // 自定义栏目
const val INFERIOR_CUSTOM_COLUMN = 92 // 低权重自定义栏目
const val RELATED_VERSION = 128//其他相关版本
const val COMMENTS = 8//评论
const val IMAGE = 3//图片推荐
@ -726,8 +733,6 @@ class DescAdapter(context: Context,
class GameDetailCustomColumnViewHolder(var binding: GamedetailItemCustomColumnBinding) : RecyclerView.ViewHolder(binding.root)
class GameDetailInferiorCustomColumnViewHolder(var binding: GamedetailItemInferiorCustomColumnBinding) : RecyclerView.ViewHolder(binding.root)
class GameDetailRelatedVersionViewHolder(var binding: GameGalleryListBinding) : RecyclerView.ViewHolder(binding.root)
class GameVideoGalleryViewHolder(var binding: GameGalleryListBinding) : RecyclerView.ViewHolder(binding.root)

View File

@ -60,6 +60,7 @@ class DescCommentsAdapter(context: Context,
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameDetailRatingCommentViewHolder) {
val commentData = comments[position]
var isChildLongClick = false
holder.binding.run {
data = commentData
val p = Pattern.compile(RatingEditActivity.LABEL_REGEX)
@ -116,6 +117,10 @@ class DescCommentsAdapter(context: Context,
tvBadgeName.setOnClickListener { sdvUserBadge.performClick() }
commentItem.setOnClickListener {
if (isChildLongClick) {
isChildLongClick = false
return@setOnClickListener
}
val intent = RatingReplyActivity.getIntent(mContext, mViewModel.game!!, commentData, mEntrance, path)
SyncDataBetweenPageHelper.startActivityForResult(mContext, intent, RATING_REPLY_REQUEST, position)
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击评论", mViewModel.game?.name)
@ -123,6 +128,12 @@ class DescCommentsAdapter(context: Context,
content.setExpandCallback {
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击全文", mViewModel.game?.name)
}
content.setOnLongClickListener(View.OnLongClickListener {
isChildLongClick = true
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "").copyTextAndToast()
return@OnLongClickListener true
})
more.setOnClickListener {
showMorePopWindow(it, commentData.user.id == UserManager.getInstance().userId) { text ->
when (text) {

View File

@ -10,6 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import com.gh.base.fragment.BaseFragment
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.gamecenter.LibaoDetailActivity
import com.gh.gamecenter.R
@ -23,9 +24,11 @@ import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.video.detail.VideoDetailActivity
import com.halo.assistant.HaloApp
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlin.math.abs
class DescFragment : BaseFragment<Any>() {
@ -33,8 +36,8 @@ class DescFragment : BaseFragment<Any>() {
private var layoutManager: LinearLayoutManager? = null
private var mGameEntity: GameEntity? = null
// private var mDetailEntity: GameDetailEntity? = null
private var mNewDetailEntity: NewGameDetailEntity? = null
private var mDisplayHintDisposable: Disposable? = null
private lateinit var mViewModel: DescViewModel
@ -125,14 +128,29 @@ class DescFragment : BaseFragment<Any>() {
mRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val position = layoutManager!!.findFirstCompletelyVisibleItemPosition()
if (position == 0 && Math.abs(dy) > 10) {
val firstCompletelyVisibleItemPosition = layoutManager!!.findFirstCompletelyVisibleItemPosition()
val lastCompletelyVisibleItemPosition = layoutManager!!.findLastCompletelyVisibleItemPosition()
if (firstCompletelyVisibleItemPosition == 0 && abs(dy) > 10) {
EventBus.getDefault().post(EBReuse(OPEN_APPBAR))
}
for (i in firstCompletelyVisibleItemPosition..lastCompletelyVisibleItemPosition) {
if (i < 0) continue
if (mAdapter.getItemViewType(i) == DescAdapter.CUSTOM_COLUMN
&& mAdapter.descItemList[i].customColumn?.showExpandTagsHint == true) {
SPUtils.setBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT, true)
}
}
}
})
}
override fun onDestroy() {
super.onDestroy()
mDisplayHintDisposable?.dispose()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(reuse: EBReuse) {
if (SKIP_DESC == reuse.type) {
@ -159,5 +177,4 @@ class DescFragment : BaseFragment<Any>() {
}
}
}

View File

@ -3,11 +3,13 @@ package com.gh.gamecenter.gamedetail.desc
import android.annotation.SuppressLint
import android.app.Application
import android.os.Build
import android.text.TextUtils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.facebook.common.util.UriUtil
import com.gh.common.constant.Constants
import com.gh.common.repository.RemenkapaiRepository
import com.gh.common.util.*
import com.gh.gamecenter.R
@ -195,19 +197,12 @@ class DescViewModel(application: Application,
// 装饰列表数据
fun decorateList(detailEntityList: ArrayList<DetailEntity>): ArrayList<DetailEntity> {
// // A 把低权重的自定义栏目转化为新的低权重自定义栏目 item // DEPRECATED
// for (rawItem in detailEntityList) {
// if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
// if (rawItem.customColumn?.order ?: -1 <= 0) {
// rawItem.type = DetailEntity.Type.INFERIOR_CUSTOM_COLUMN.value
// }
// }
// }
val specialPadding = DisplayUtils.dip2px(12F)
val defaultPadding = DisplayUtils.dip2px(15F)
var containsFirstTimeExpandCustomColumnTags = false
var hasShownCustomColumnTagsExpandHint = SPUtils.getBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT)
// A 确定每个 item 的上下内边距
for ((index, rawItem) in detailEntityList.withIndex()) {
rawItem.paddingTop = defaultPadding
@ -247,6 +242,38 @@ class DescViewModel(application: Application,
}
}
// D 处理自定义栏目相关的东西
for (rawItem in detailEntityList) {
if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
// 判断自定义栏目的标签是否需要进入就自动展开
if (rawItem.customColumn?.showInfoTagDesType == "first_expand"
&& !SPUtils.getBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS)) {
containsFirstTimeExpandCustomColumnTags = true
rawItem.customColumn?.showInfoTagDesType = "expand"
}
// 正文内容为空,但是后台配置了标签展开的默认展开
if (rawItem.customColumn?.showInfoTag == true
&& TextUtils.isEmpty(rawItem.customColumn?.des)) {
rawItem.customColumn?.showInfoTagDesType = "expand"
}
// 判断是否显示标签展开提示
if (rawItem.customColumn?.showInfoTagDes == true
&& rawItem.customColumn?.infoTag?.size != 0
&& rawItem.customColumn?.showInfoTagDesType != "expand"
&& !hasShownCustomColumnTagsExpandHint) {
rawItem.customColumn?.showExpandTagsHint = true
// 内存置为 true 避免出现多个提示
hasShownCustomColumnTagsExpandHint = true
}
}
}
if (containsFirstTimeExpandCustomColumnTags) {
SPUtils.setBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS, true)
}
loadCustomColumnImageInAdvance(detailEntityList)
return detailEntityList

View File

@ -85,6 +85,7 @@ class GameGalleryAdapter(var context: Context,
}
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
params.leftMargin = DisplayUtils.dip2px(if (position == 0) 20f else 8f)
params.rightMargin = DisplayUtils.dip2px(if (position == itemCount - 1) 20f else 0f)
holder.itemView.layoutParams = params
}

View File

@ -21,6 +21,7 @@ class GameRaidersAdapter(val context: Context, val articles: ArrayList<NewsEntit
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
params.leftMargin = DisplayUtils.dip2px(if (position == 0) 20f else 12f)
params.rightMargin = DisplayUtils.dip2px(if (position == itemCount - 1) 20f else 0f)
holder.itemView.layoutParams = params
val newsEntity = articles[position]
if (holder is RaidersViewHolder) {

View File

@ -6,10 +6,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.GameViewUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.StringUtils
import com.gh.common.util.*
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.ItemGameDetailRelatedVersionBinding
@ -55,10 +52,13 @@ class GameRelatedVersionAdapter(val context: Context, val gameName: String, val
}
}
is MoreViewHolder -> {
holder.itemView.setOnClickListener {
MtaHelper.onEvent("游戏详情_新", "相关游戏版本_展开", gameName)
isExpand = true
notifyItemRangeInserted(mShowItemCount + 1, datas.size - mShowItemCount)
holder.itemView.apply {
setPadding(0, 0, 0, 0)
setOnClickListener {
MtaHelper.onEvent("游戏详情_新", "相关游戏版本_展开", gameName)
isExpand = true
notifyItemRangeInserted(mShowItemCount + 1, datas.size - mShowItemCount)
}
}
}
}

View File

@ -10,6 +10,7 @@ import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.dialog.TrackableDialog
import com.gh.common.util.DisplayUtils
import com.gh.common.util.MtaHelper
import com.gh.common.view.VerticalItemDecoration
import com.gh.gamecenter.R
@ -17,12 +18,18 @@ import com.gh.gamecenter.gamedetail.entity.BigEvent
class GameBigEventDialog(context: Context, val gameName: String, val bigEvents: List<BigEvent>, val mEntrance: String, mEvent: String, mKey: String, mValue: String) :
TrackableDialog(context, R.style.GhAlertDialog, mEvent, mKey, mValue) {
override fun onStart() {
super.onStart()
if (window != null) {
window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val params = window!!.attributes
params.width = context.resources.displayMetrics.widthPixels - DisplayUtils.dip2px(40f)
window!!.attributes = params
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (window != null) {
window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
requestWindowFeature(Window.FEATURE_NO_TITLE)
val contentView = LayoutInflater.from(context).inflate(R.layout.dialog_game_big_event, null)

View File

@ -93,9 +93,13 @@ data class CustomColumn(
var showInfoTag: Boolean? = false,
@SerializedName("show_info_tag_des")
var showInfoTagDes: Boolean? = false,
@SerializedName("show_info_tag_des_type")
var showInfoTagDesType: String? = "", // first_expand (用于默认展开), collapse, expand
@SerializedName("info_tag")
var infoTag: List<TagEntity>? = listOf(),
var time: Long? = 0)
var time: Long? = 0,
// 是否显示自定义栏目的提示浮窗 (本地字段)
var showExpandTagsHint: Boolean? = false)
@Keep
data class Title(var icon: String, var value: String, var color: String)

View File

@ -107,11 +107,13 @@ class FuLiAdapter(context: Context,
private fun initAnswerViewHolder(holder: GameDetailAnswerViewHolder, position: Int) {
holder.binding.run {
val isShowAnswerHint = mSharedPreferences.getBoolean(mAnswerHintKey, true)
if (isShowAnswerHint) {
answerItemHint.visibility = View.VISIBLE
}
holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.transparent))
answerItemList.background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
answerItemList.layoutManager = LinearLayoutManager(mContext)
answerAdapter = GameDetailAnswerAdapter(mContext, mFuLiViewModel!!, itemList?.get(position)?.answer!!, mEntrance)
mFuLiViewModel.gameCommunity = itemList?.get(position)?.community
@ -155,6 +157,7 @@ class FuLiAdapter(context: Context,
viewHolder.binding.galleryRv.apply {
layoutManager = LinearLayoutManager(mContext)
val toolkitAdapter = GameDetailToolsAdapter(mContext, mFuLiViewModel?.game?.name, tools)
toolkitAdapter.setItemColor(R.color.transparent)
adapter = toolkitAdapter
}
}

View File

@ -37,8 +37,8 @@ class GameDetailAnswerAdapter(context: Context,
override fun onBindViewHolder(holder: CommunityAnswerItemViewHolder, position: Int) {
holder.binding.contentContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
holder.binding.commentCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
holder.binding.voteCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
holder.commentCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
holder.voteCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
holder.binding.contentContainer.setPadding(DisplayUtils.dip2px(12f),0,DisplayUtils.dip2px(12f),0)
holder.binding.topLine.visibleIf(position > 0)

View File

@ -9,8 +9,8 @@ import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.MeEntity
import com.gh.gamecenter.entity.ServerCalendarEntity
import com.gh.gamecenter.gamedetail.fuli.FuLiFragment
import com.gh.gamecenter.servers.patch.PatchKaifuActivity.Companion.getIntent
import com.gh.gamecenter.servers.patch.PatchKaifuActivity
import com.lightgame.utils.Utils
class ServersDetailViewHolder(val binding: DialogServersCalendearDetailItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
@ -28,11 +28,15 @@ class ServersDetailViewHolder(val binding: DialogServersCalendearDetailItemBindi
binding.name.paint.isAntiAlias = true
binding.name.setOnClickListener {
val context = binding.root.context
(context as Activity).startActivityForResult(getIntent(
context,
data,
gameEntity.id),
ServersCalendarActivity.GAME_DETAIL_PATCH_KAIFU_REQUEST)
if ("删档内测" == data.type || "不删档内测" == data.type || "公测" == data.type) {
Utils.toast(context, "开测信息不可编辑");
} else {
(context as Activity).startActivityForResult(PatchKaifuActivity.getIntent(
context,
data,
gameEntity.id),
ServersCalendarActivity.GAME_DETAIL_PATCH_KAIFU_REQUEST)
}
}
}
}

View File

@ -20,7 +20,9 @@ import com.lightgame.adapter.BaseRecyclerAdapter;
import java.util.List;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
/**
@ -34,6 +36,11 @@ public class GameDetailToolsAdapter extends BaseRecyclerAdapter {
private String mGameName;
private final int MORE = 0;
private final int TOOLBOX = 1;
private int mItemColor = R.color.white;
public void setItemColor(@ColorRes int color) {
mItemColor = color;
}
public GameDetailToolsAdapter(Context context, String gameName, List<ToolBoxEntity> toolBoxList) {
super(context);
@ -86,6 +93,7 @@ public class GameDetailToolsAdapter extends BaseRecyclerAdapter {
}
private void initToolBoxViewHolder(ToolBoxViewHolder viewHolder, final ToolBoxEntity toolBoxEntity) {
viewHolder.itemView.setBackground(ContextCompat.getDrawable(mContext, mItemColor));
viewHolder.itemView.setPadding(0, DisplayUtils.dip2px(mContext, 10), 0, DisplayUtils.dip2px(mContext, 10));
viewHolder.mDes.setText(toolBoxEntity.getDes());

View File

@ -25,7 +25,9 @@ import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.utils.Utils
class HistoryApkListAdapter(context: Context, private var mViewModel: HistoryApkListViewModel) : ListAdapter<GameEntity>(context) {
class HistoryApkListAdapter(context: Context,
private var mViewModel: HistoryApkListViewModel,
private var mEntrance: String) : ListAdapter<GameEntity>(context) {
private var mExpandSparseBooleanArray = SparseBooleanArray()
private var mDescExpandedMarginRight = -1
@ -74,8 +76,8 @@ class HistoryApkListAdapter(context: Context, private var mViewModel: HistoryApk
gameEntity,
0,
this@HistoryApkListAdapter,
"$mEntrance+(历史版本)",
"历史版本",
"",
null,
object : EmptyCallback {
override fun onCallback() {
@ -155,10 +157,10 @@ class HistoryApkListAdapter(context: Context, private var mViewModel: HistoryApk
private fun showDowngradeToastIfNeed(apkEntity: ApkEntity, btnText: CharSequence) {
when (btnText) {
"下载" -> MtaHelper.onEvent("历史版本", "下载", mViewModel.game.name)
"下载中" -> MtaHelper.onEvent("历史版本", "下载中", mViewModel.game.name)
"安装" -> MtaHelper.onEvent("历史版本", "安装", mViewModel.game.name)
"启动" -> MtaHelper.onEvent("历史版本", "启动", mViewModel.game.name)
"下载" -> MtaHelper.onEvent("历史版本", "下载", "${mViewModel.game.name}_${apkEntity.version}")
"下载中" -> MtaHelper.onEvent("历史版本", "下载中", "${mViewModel.game.name}_${apkEntity.version}")
"安装" -> MtaHelper.onEvent("历史版本", "安装", "${mViewModel.game.name}_${apkEntity.version}")
"启动" -> MtaHelper.onEvent("历史版本", "启动", "${mViewModel.game.name}_${apkEntity.version}")
}
if (btnText == "安装" || btnText == "下载") {
if (PackageUtils.isInstalled(mContext, apkEntity.packageName)) {

View File

@ -84,7 +84,7 @@ class HistoryApkListFragment : ListFragment<GameEntity, HistoryApkListViewModel>
override fun provideListAdapter(): ListAdapter<*> {
if (mAdapter == null) {
mAdapter = HistoryApkListAdapter(requireContext(), mViewModel!!)
mAdapter = HistoryApkListAdapter(requireContext(), mViewModel!!, mEntrance)
}
return mAdapter!!
}

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