Compare commits

...

353 Commits

Author SHA1 Message Date
0dcf86ce1c tinker_base 4.0.0-bugfix 2020-05-20 11:43:01 +08:00
961d4ebb5c 修复空指针问题 2020-05-20 11:12:34 +08:00
54b947504c 1.修改游戏大事件超过15天不显示时间 2.修改礼包进度条显示 2020-05-20 10:19:05 +08:00
ee7f102d34 游戏详情自定义栏目图片添加占位图,避免详情列表加载抖动 2020-05-19 17:15:24 +08:00
135b55f6f9 修改礼包详情按钮UI 2020-05-19 15:05:38 +08:00
17782a500f 更换所有礼包领取按钮样式 2020-05-19 10:42:24 +08:00
64a64960ac 尝试修复初始化闪退 2020-05-19 10:29:27 +08:00
d4be850e68 1.修改标签弹窗重构闪退问题 2.修改获取求更新开关空指针问题 2020-05-19 10:15:55 +08:00
414064699a 修改DownloadDialog传参方式 2020-05-18 15:18:44 +08:00
99878606d5 修复多版本下载弹窗页面重构时的闪退问题 2020-05-18 10:41:19 +08:00
e1cfccfcc0 修复游戏详情页标签后台返回为空时的闪退 2020-05-18 10:40:30 +08:00
4c2a46875d tinker_base-4.0.0 2020-05-15 19:01:45 +08:00
6ce64892e4 处理游戏礼包换行 2020-05-15 18:51:19 +08:00
92e1c55913 优化游戏详情礼包UI 2020-05-15 18:42:34 +08:00
b0a4aa66f6 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-15 15:58:17 +08:00
aad92e529e 去掉延迟播放视频逻辑 2020-05-15 15:58:13 +08:00
6e03e75110 修复问答-全部页面无法显示问题 2020-05-15 15:51:44 +08:00
cc53a1f3d6 tinker_base-4.0.0 2020-05-15 14:19:10 +08:00
25cd086298 默认的checkRetryDownload(重试下载)放到initDownloadService(初始化下载)里面 2020-05-15 13:32:01 +08:00
b27ecab969 tinker_base-4.0.0 2020-05-15 12:27:51 +08:00
db1c0d954f 修改获取baseActivity不是本应用包名 2020-05-15 12:15:58 +08:00
03d20aed61 tinker_base-4.0.0 2020-05-15 11:01:14 +08:00
c2fb1a58db 修改礼包剩余百分比 2020-05-14 15:54:40 +08:00
55998c3c4d 礼包详情剩余百分比改为四舍五入 2020-05-14 14:59:32 +08:00
1ef8fa5deb 把初始化下载服务放到主线程执行 2020-05-14 11:05:16 +08:00
d0a2868e5a Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-14 10:31:15 +08:00
49c2366a89 修改游戏标签样式 2020-05-14 10:31:08 +08:00
cb7d985195 修复自定义栏目跳转反馈页面的异常 2020-05-14 10:22:23 +08:00
bead0bded1 修复自定义栏目跳转反馈页面的异常 2020-05-13 17:58:46 +08:00
cc92d5f639 修改游戏详情-相关游戏标签样式 2020-05-13 17:34:43 +08:00
84c281122e Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/res/layout/item_game_detail_related_version.xml
2020-05-13 17:28:08 +08:00
bb4a35a6a9 调整游戏详情板块之间的边距 2020-05-13 17:25:26 +08:00
71ae36fbf0 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-13 16:27:50 +08:00
04864e059c 光环助手V4.0.0补充需求:游戏列表优化(后台尚未完成,标签颜色暂且写死) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/862 2020-05-13 16:27:41 +08:00
7a47184af3 去掉游戏详情倒数第二个栏目的特殊底边距 2020-05-13 15:22:15 +08:00
48e2831e96 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-13 12:29:05 +08:00
c1caa23b10 恢复webview实现NestedScrollingChild接口 2020-05-13 12:29:00 +08:00
443cc6007d Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-13 11:18:40 +08:00
7d99923960 整理多平台下载弹窗代码 2020-05-13 11:18:18 +08:00
7342d0706f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-13 11:12:28 +08:00
c15c194feb 再次修改游戏详情礼包UI 2020-05-13 11:12:23 +08:00
3b6a5b5a20 更换引导图 2020-05-13 11:04:39 +08:00
f9028ea8a5 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-13 10:56:39 +08:00
8cd06a80ba 多版本下载面板优化20200512测试3 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/819 2020-05-13 10:56:34 +08:00
6c80266abb 修复多平台面板无法读取链接图标问题 2020-05-13 10:53:44 +08:00
ca3c1fa8c2 修改游戏详情礼包UI 2020-05-12 22:18:53 +08:00
2b7deaef2c 完成4.0测试问题汇总(0511)的0512UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/859 2020-05-12 21:10:55 +08:00
42f1898bd1 整理游戏详情页列表间距 2020-05-12 20:38:03 +08:00
0bdff3eac7 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-12 19:46:43 +08:00
a00f6660a1 修改徽章中心不显示问题 2020-05-12 19:46:38 +08:00
67d1ad497f 完成4.0.0测试问题汇总(0511)的 2, 3, 4, 8 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/859 2020-05-12 18:03:58 +08:00
f1bbf4e9fc 专区网页二级页面点击右上角返回按钮直接关闭页面 2020-05-12 17:35:13 +08:00
00ff5e6a94 视频流底部添加渐变背景 2020-05-12 16:05:00 +08:00
7f77a8fd63 详细信息功能标签增加分割线 2020-05-12 15:17:22 +08:00
7c1267148b 光环助手V4.0.0-测试问题汇总(20200511)(5,6,7,9) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/859 2020-05-12 12:12:33 +08:00
2dbb7b67cb 调整游戏详情板块间距 2020-05-12 11:14:33 +08:00
c41db52b05 网页控制分享新加url参数 2020-05-12 11:13:46 +08:00
72f3a262ca 评论页面评论过少时不展示评分区域 2020-05-11 16:55:48 +08:00
2fbe6a4937 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-11 16:44:32 +08:00
c6fb63afe6 专区网页跳转二级页面使用原生页面打开 2020-05-11 16:44:28 +08:00
2e05320ddf 优化详情页公告/自定义栏目的初始化显示样式 2020-05-11 16:40:57 +08:00
a3f86ab604 避免数组越界 2020-05-11 16:38:48 +08:00
5d2efda925 修复历史版本页面下载游戏时文字抖动的问题 2020-05-11 15:14:07 +08:00
4a30ac04b7 修复可展开文字在触摸全部按钮是高度会变更的问题 2020-05-11 15:13:33 +08:00
1097068393 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-11 14:05:00 +08:00
df88502c3d 光环助手V4.0-前端测试问题汇总(0509)1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/849 2020-05-11 14:04:55 +08:00
b8df485a7e 历史安装包列表没包时隐藏下载按钮 2020-05-11 11:41:50 +08:00
a8a66a7b1e 开服日历开服说明支持换行符 2020-05-11 10:47:29 +08:00
a1548faeda 补充从 APK 中读签名公钥的细节 2020-05-11 10:01:22 +08:00
34f452be6e 调整专区空数据占位图位置 2020-05-10 19:24:46 +08:00
bef04854e3 尝试修复从APK文件中读取公钥耗时过长的问题 2020-05-09 21:29:51 +08:00
757782e43b 尝试修复从APK文件中读取公钥耗时过长的问题 2020-05-09 21:11:13 +08:00
8a69f565a3 修复自定义栏目跳转问题 2020-05-09 21:07:27 +08:00
be20d1fec6 尝试修复从APK文件中读取公钥耗时过长的问题 2020-05-09 20:52:35 +08:00
7a71e457ef 历史版本更新的介绍文字调整为最多三行 2020-05-09 20:49:56 +08:00
3af9fa0a10 修复点击下载闪退问题 2020-05-09 18:45:53 +08:00
ff8b3efde9 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-09 17:56:45 +08:00
161f63a664 多平台弹窗增加游戏图标展位符 2020-05-09 17:56:38 +08:00
3206e04639 微调自定栏目UI 2020-05-09 17:47:28 +08:00
f1dea0f200 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-09 17:39:51 +08:00
d94a83a7c3 修改插件化显示规则 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/838 (三) 2020-05-09 17:39:40 +08:00
6bbc7104d9 修复在 MIUI 上首页顶部会出现空白区域的问题 2020-05-09 17:10:59 +08:00
a2180196ee Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-09 16:51:51 +08:00
a6dc4c7891 暴力处理顶部视频静音问题 2020-05-09 16:51:30 +08:00
fa7355c5c6 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-09 15:28:26 +08:00
0140c10f15 20200508测试(1,2,3,4) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/819 2020-05-09 15:28:12 +08:00
796da0e673 完成游戏详情自定义栏目的0509测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/829 2020-05-09 14:43:07 +08:00
743f78096a 光环助手V4.0.0-游戏评论Tab20200509测试问题:1https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/834 2020-05-09 14:38:30 +08:00
52d726b6f3 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-09 12:02:24 +08:00
bed4450900 光环助手V4.0.0-游戏评论Tab20200509测试问题:2 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/834 2020-05-09 12:01:56 +08:00
c2ab369d0c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-09 11:48:51 +08:00
32a7f37b6a 20200508补充规则(1,2,3)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/838 2020-05-09 11:48:45 +08:00
b299199579 光环助手V4.0.0-游戏详情Tab202200509测试问题1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/827 2020-05-09 11:13:27 +08:00
7091ea179d 游戏详情历史版本入口判断 2020-05-09 09:59:54 +08:00
dceb582bb1 游戏详情视频点赞数 2020-05-09 09:03:23 +08:00
6e2e9f7dcf Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-08 20:44:23 +08:00
c27025269e 游戏详情视频添加背景 2020-05-08 20:44:01 +08:00
cf1411b412 完成首页弹窗 0508 测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/821 2020-05-08 19:03:02 +08:00
b167f5bb8b 完成光环助手V4.0-前端优化汇总(视频相关)20200508评论 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/842 2020-05-08 18:32:10 +08:00
87d0fd9edb Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-08 18:09:06 +08:00
b59a169e10 完成实名认证弹窗20200505补充 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/847 2020-05-08 18:08:47 +08:00
941e3985b0 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-08 16:59:36 +08:00
127fb76c19 尝试修复某些设备出现的下载红点位置异常问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/824 (3) 2020-05-08 16:59:28 +08:00
5f3028f795 完成游戏详情自定义栏目 20200508 测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/829 2020-05-08 16:50:35 +08:00
b596f04dba Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-08 16:19:53 +08:00
0bb96ecf12 尝试修复下载通知跳转问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/824 (2) 2020-05-08 16:19:38 +08:00
60f21f6113 光环助手V4.0.0-游戏大事件功能20200508测试问题1,2 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/828 2020-05-08 15:12:13 +08:00
051000e4a8 光环助手V4.0.0-游戏历史版本功能20200508测试问题2 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/832 2020-05-08 11:47:43 +08:00
14e8020147 游戏详情新增低权重的自定义栏目样式 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/829 2020-05-07 18:54:10 +08:00
a99b1499a2 微调使用帮助UI 2020-05-07 18:30:04 +08:00
6a1c01556b 微调使用帮助UI 2020-05-07 18:21:22 +08:00
c41327640b [使用帮助]功能升级为[Q&A管理](0507测试3/4)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/837 2020-05-07 17:10:44 +08:00
7df5834ebc Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-07 15:25:17 +08:00
ebafc2f98f 多版本下载面板优化(20200507测试1)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/819 2020-05-07 15:24:53 +08:00
92c9d81171 视频预加载大小根据设备内存大小决定 2020-05-07 15:04:59 +08:00
7d34a3972d 修复游戏详情简介不显示的问题 2020-05-07 12:11:04 +08:00
90f1254c6c 完成首页UI调整的0430测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/820 2020-05-07 11:57:16 +08:00
8b71d68749 更换答案/文章详情底部分享按钮 2020-05-07 11:37:23 +08:00
17c0cf52b6 修复游戏历史版本功能的部分测试bug https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/832 2020-05-07 11:06:58 +08:00
045be4ff09 游戏详情自定义栏目内容支持富文本 2020-05-07 10:58:06 +08:00
af7948fcb5 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-07 10:26:50 +08:00
e1c12d5007 优化游戏详情触摸事件 2020-05-07 10:26:29 +08:00
8676b20fbb 增加试玩开关判断 2020-05-07 10:24:00 +08:00
54db9fb910 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-07 10:16:00 +08:00
0eaee1ae63 修复下载弹窗重复弹出问题 2020-05-07 10:15:46 +08:00
e141dfb6b5 修复部分游戏详情自定义栏目的问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/829 2020-05-06 19:02:49 +08:00
b14b8c9f66 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-06 18:26:42 +08:00
b4b589f307 光环助手V4.0.0-游戏详情Tab20200506测试1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/827 2020-05-06 18:26:21 +08:00
7a74bc0d04 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-06 17:59:47 +08:00
b826c0a9ad 移除旧版多平台弹窗相关代码 2020-05-06 17:59:39 +08:00
a197b59200 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-06 17:16:36 +08:00
c25503d7f8 设备弹窗逻辑修改 2020-05-06 17:16:15 +08:00
2c0449dcf6 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-06 15:43:18 +08:00
59655daa3b MTA事件ID,Q&A改为QA 2020-05-06 15:43:11 +08:00
1c36d7b923 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-06 15:22:45 +08:00
a51175620c 光环助手V4.0.0-游戏详情Tab 20200505测试问题4,5,7 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/827 2020-05-06 15:22:25 +08:00
7b95c265df Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-06 15:12:47 +08:00
a11bb9c210 [使用帮助]功能升级为[Q&A管理](0430测试5/7/8)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/837 2020-05-06 15:12:30 +08:00
72227a5591 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-05-06 14:17:49 +08:00
f9f2eb4c05 光环助手V4.0.0-游戏大事件功能20200501测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/828 2020-05-06 14:17:25 +08:00
e9c57df5fb 视频预加载捕抓 OutOfMemoryError 2020-05-06 11:25:52 +08:00
158c47d94b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-05-06 11:04:54 +08:00
7616435098 开服日历表开服信息弹窗增加滚动条 2020-05-06 11:04:41 +08:00
69443ff457 光环助手V4.0.0-游戏详情数据统计(MTA)20200505测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/846 2020-05-06 10:22:55 +08:00
6a257c0a9f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-30 18:29:43 +08:00
eddd56e53a 对接游戏详情视频流接口 2020-04-30 18:29:11 +08:00
de6648867b 调整游戏详情的更新栏目和自定义栏目UI https://gitlab.ghzs.com/pm/halo-app-issues/issues/829 2020-04-30 18:22:05 +08:00
567a6ceda5 设备新增/删除/覆盖已安装的应用,接口和loghub都各发送一份数据
https://gitlab.ghzs.com/stats/stats-issues/issues/135
2020-04-30 16:35:04 +08:00
59330bcd7e Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-30 16:27:42 +08:00
36803f24bc 修改游戏详情开服日历表相关UI 2020-04-30 16:27:32 +08:00
46458e2667 Merge remote-tracking branch 'origin/dev' into dev 2020-04-30 15:23:23 +08:00
d0aa6e1fe5 字体大小不随系统设置变更 2020-04-30 15:23:13 +08:00
9bef919123 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-30 15:22:12 +08:00
88a0603d50 修改数据统计上传格式
https://gitlab.ghzs.com/stats/stats-issues/-/issues/130#note_45881
2020-04-30 15:21:48 +08:00
106dbb3d8d 修改展开更多不流畅 2020-04-30 15:04:57 +08:00
4214d924a4 游戏详情UI优化 2020-04-30 11:18:08 +08:00
c3b40f9264 光环助手V4.0.0-游戏详细信息内容20200429UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/issues/830 2020-04-29 20:42:11 +08:00
69f00626a2 光环助手V4.0.0-游戏评论Tab0429UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/issues/834 2020-04-29 20:32:44 +08:00
c485b1f7f8 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-29 18:26:12 +08:00
7186c73a64 游戏详情专区UI优化 2020-04-29 18:25:47 +08:00
88f9f65fb6 完成自定义栏目UI调整(20200428UI测试) https://gitlab.ghzs.com/pm/halo-app-issues/issues/829 2020-04-29 18:19:13 +08:00
714573ec6b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-29 17:54:14 +08:00
a979445ffc 多平台下载弹窗安装/卸载后即时刷新数据 2020-04-29 17:54:00 +08:00
3cf38eb3fc Merge remote-tracking branch 'origin/dev' into dev 2020-04-29 17:19:59 +08:00
94ceca35bf 提前 Loghub 初始化避免提交时的异常 2020-04-29 17:19:47 +08:00
2bd4eb2004 修复首页游戏替换的逻辑错误 2020-04-29 17:19:10 +08:00
355e71e620 修改编辑问题的标题显示规则 2020-04-29 17:19:09 +08:00
7d9520d97b 修改游戏详情下载进度条UI 2020-04-29 17:11:24 +08:00
ce0957cea7 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-29 16:29:09 +08:00
c93169fe97 游戏详情开服日历表更改数据来源 2020-04-29 16:29:01 +08:00
485dd96e93 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-29 16:01:42 +08:00
9b0f0892ff 光环助手V4.0-前端优化汇总(视频相关)11-13 https://gitlab.ghzs.com/pm/halo-app-issues/issues/842 2020-04-29 16:01:18 +08:00
9a04f3ae38 调整首页间距,修复首页下拉刷新无法替换已安装游戏的问题 2020-04-29 15:53:12 +08:00
968d668afa 处理Loghub数据包裹问题 2020-04-29 15:22:38 +08:00
85d19ed2bd 修复回答数同步异常问题 2020-04-29 15:10:48 +08:00
28e490f8d4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-29 11:23:08 +08:00
298ae7f657 光环助手V4.0.0-游戏详情Tab0428UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/issues/827 2020-04-29 11:22:46 +08:00
d50f29b3dc 修复游戏详情自定义栏目行数设置为0会闪退的问题 2020-04-29 10:00:40 +08:00
f167eff21c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-28 18:57:58 +08:00
69d4f00807 [使用帮助]功能升级为[Q&A管理] (二)https://gitlab.ghzs.com/pm/halo-app-issues/issues/837 2020-04-28 18:57:37 +08:00
904dc4fe2e 光环助手V4.0.0-游戏详细信息内容20200428测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/issues/830 2020-04-28 17:59:00 +08:00
c870cc683d Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-28 15:00:23 +08:00
deb29fd2e4 去掉首页tab按下时状态 2020-04-28 14:59:50 +08:00
19f1bc947a 前台服务的通知 ID 改为 1 2020-04-28 14:33:20 +08:00
60d1b47c66 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-28 11:41:01 +08:00
d67b845dfd 光环助手V4.0.0-游戏评论Tab0427测试问题:1-4 https://gitlab.ghzs.com/pm/halo-app-issues/issues/834 2020-04-28 11:40:37 +08:00
6f1c7c7ded Merge remote-tracking branch 'origin/dev' into dev 2020-04-27 20:39:19 +08:00
46e9118d73 光环助手V4.0-前端优化汇总(视频相关)10 https://gitlab.ghzs.com/pm/halo-app-issues/issues/842 2020-04-27 20:05:30 +08:00
8aa1557b7a 调整首页分割线粗细 2020-04-27 18:26:08 +08:00
6058c3f8c1 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-27 18:23:51 +08:00
d409e6f2a9 游戏详情ui优化 2020-04-27 18:23:19 +08:00
a4d272c556 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-27 18:10:48 +08:00
911d7c04ec 处理Loghub数据包裹问题 2020-04-27 18:10:41 +08:00
afc379d449 完成游戏历史版本功能 https://gitlab.ghzs.com/pm/halo-app-issues/issues/832 2020-04-27 17:05:11 +08:00
18feca49e2 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-27 16:45:19 +08:00
792b19d40d 多版本下载面板优化(UI测试问题补充)https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-27 16:44:29 +08:00
108d05edea 20200426补充4 https://gitlab.ghzs.com/pm/halo-app-issues/issues/833 2020-04-27 16:06:56 +08:00
d8882da17b 去掉游戏详情横向列表滑动padding 2020-04-27 15:55:22 +08:00
f120dfda15 修复游戏详情文字展开按钮换行时的错位问题 2020-04-27 15:23:03 +08:00
dd60ed7abd Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-27 14:53:13 +08:00
d0b478c743 添加游戏详情展开遮罩 2020-04-27 14:52:50 +08:00
defe69ba18 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-27 14:26:34 +08:00
32d748efae 多版本下载面板优化(三)https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-27 14:26:12 +08:00
f194dc9bf6 20200426测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/issues/826 2020-04-27 11:53:41 +08:00
075fbd77b2 完成游戏详情的展开按钮遮罩效果 2020-04-27 11:17:17 +08:00
edb3e3713a Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-27 10:45:51 +08:00
c70648e038 更换评论标签样式 2020-04-27 10:45:26 +08:00
966f4ee57d Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-26 17:14:13 +08:00
f90ced4c31 下载弹窗扩大手势拖拽关闭区域 2020-04-26 17:14:04 +08:00
6bda4d80bf 自定义栏目MTA数据统计 2020-04-26 16:53:36 +08:00
3ecb6b30c9 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescAdapter.kt
2020-04-26 16:39:34 +08:00
3c337b618c 光环助手V4.0.0-游戏详情数据统计(MTA)https://gitlab.ghzs.com/pm/halo-app-issues/issues/846 2020-04-26 16:36:53 +08:00
40a90bbcfa 完成游戏详情自定义栏目的UI https://gitlab.ghzs.com/pm/halo-app-issues/issues/829 2020-04-26 16:09:04 +08:00
e54b124252 完成游戏详情自定义栏目的UI https://gitlab.ghzs.com/pm/halo-app-issues/issues/829 2020-04-26 16:07:05 +08:00
18923efe23 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-26 15:39:22 +08:00
5c5ad63cc6 多版本下载面板优化(UI测试问题汇总) https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-26 15:39:10 +08:00
d5fd444ae5 优化游戏详情视频UI 2020-04-26 11:09:06 +08:00
4a22f70e30 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-26 11:03:20 +08:00
9805bd4caa 修改图片压缩格式(防止部分Webp图片无法缩放) 2020-04-26 11:03:00 +08:00
0690f13bea 处理游戏详情标签显示不全和切换状态栏颜色 2020-04-26 09:43:23 +08:00
da8faea4c8 处理视频流顶部标题小红点显示问题 2020-04-26 09:27:57 +08:00
ff927bab09 调整游戏详情自定义栏目的部分UI https://gitlab.ghzs.com/pm/halo-app-issues/issues/829 2020-04-24 18:28:29 +08:00
e3e5def3b6 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-24 18:00:39 +08:00
ba246585ad 完成游戏大事件(后台无数据还未测试) 2020-04-24 18:00:11 +08:00
f242a6a3bc Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-24 17:21:34 +08:00
0c89e76b39 光环前端优化汇总(2020年4月第3周) (3)https://gitlab.ghzs.com/pm/halo-app-issues/issues/845 2020-04-24 17:21:23 +08:00
1fa82e72f1 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-24 16:10:38 +08:00
b4e6b04e47 完成实名认证弹窗 https://gitlab.ghzs.com/pm/halo-app-issues/issues/847 2020-04-24 16:10:21 +08:00
002f824f5c 光环前端优化汇总(2020年4月第1周) (4.5)https://gitlab.ghzs.com/pm/halo-app-issues/issues/824 2020-04-24 15:45:25 +08:00
1aaf7f8de1 修复下载多平台弹窗合集和链接Item内容无法显示问题 2020-04-24 15:14:34 +08:00
82ba19842c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-24 14:20:06 +08:00
32ed1bf622 修改游戏开服日历表反馈跳转 2020-04-24 14:19:50 +08:00
0d4838c536 修改退出登录我的光环未恢复默认页面 2020-04-24 11:18:16 +08:00
11527b46f9 版权说明时间换成服务器时间 2020-04-24 09:58:20 +08:00
20c1957b59 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-23 17:57:45 +08:00
ed2630e016 光环助手V4.0.0-游戏详情数据统计(MTA)2-8 https://gitlab.ghzs.com/pm/halo-app-issues/issues/846 2020-04-23 17:57:21 +08:00
8cc2ac2cad 转换光环用户按照app列表数据的埋点方式 https://gitlab.ghzs.com/stats/stats-issues/issues/135 2020-04-23 17:50:41 +08:00
37745ca548 1.转换下载(旧)及相关数据的埋点方式 https://gitlab.ghzs.com/stats/stats-issues/issues/130
2.移除DataService相关代码
 - 相关接口部分移到ApiService部分用LogHub代替
2020-04-23 17:24:47 +08:00
29edcdca4b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-23 11:25:16 +08:00
92669d6974 光环前端优化汇总(2020年4月第3周)(8.9)https://gitlab.ghzs.com/pm/halo-app-issues/issues/845 2020-04-23 11:24:49 +08:00
351a64f592 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-22 18:55:19 +08:00
a29e56543b 实名认证弹窗(未完) 2020-04-22 18:55:05 +08:00
6db3e8c671 完成部分粗糙的游戏详情自定义栏目UI(暂毫无细节) https://gitlab.ghzs.com/pm/halo-app-issues/issues/829 2020-04-22 18:21:36 +08:00
20c4d24698 正式环境接口切换到 4.0.0 2020-04-22 18:18:45 +08:00
114e185bcb Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-22 18:14:57 +08:00
a293bff964 光环助手V4.0.0-游戏开服信息内容(三)https://gitlab.ghzs.com/pm/halo-app-issues/issues/831 2020-04-22 18:14:44 +08:00
98b4d9f95d Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-22 09:37:02 +08:00
8489e87586 光环前端优化汇总(2020年4月第3周)4-6 https://gitlab.ghzs.com/pm/halo-app-issues/issues/845 2020-04-22 09:36:36 +08:00
6f7ee2179d 修复编译失败问题 2020-04-22 09:23:00 +08:00
ea6b442a48 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-21 18:35:28 +08:00
12d26edd76 光环助手V4.0.0-游戏开服信息内容(三)https://gitlab.ghzs.com/pm/halo-app-issues/issues/831 2020-04-21 18:35:14 +08:00
27053eecd7 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-21 18:31:50 +08:00
151d5b9c1f 游戏详情评论点赞按钮已点赞显示 2020-04-21 18:31:30 +08:00
d35c558658 完成首页弹窗优化 https://gitlab.ghzs.com/pm/halo-app-issues/issues/821 2020-04-21 18:23:05 +08:00
baa4dc7a23 完成个人主页-玩过的游戏&我的游戏-玩过整体优化 https://gitlab.ghzs.com/pm/halo-app-issues/issues/839 2020-04-21 18:09:00 +08:00
9b565c32d1 修改开服时间显示 2020-04-21 17:25:53 +08:00
243dd26d73 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-21 16:11:36 +08:00
263234fecb 光环助手V4.0.0-游戏评论Tab https://gitlab.ghzs.com/pm/halo-app-issues/issues/834 2020-04-21 16:11:14 +08:00
0ba598ee67 删除无用代码,临时修复下载插件化判断错误问题 2020-04-21 10:25:42 +08:00
29430b9967 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-20 18:38:29 +08:00
2038b16dce 修改下载按钮样式 2020-04-20 18:38:12 +08:00
9ea793397b 光环助手V4.0-前端优化汇总(视频相关)1-3,5,6,7 https://gitlab.ghzs.com/pm/halo-app-issues/issues/842 2020-04-20 18:26:41 +08:00
6061938129 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-20 12:35:43 +08:00
62277aa525 光环前端优化汇总(2020年4月第3周)5 https://gitlab.ghzs.com/pm/halo-app-issues/issues/845 2020-04-20 12:35:22 +08:00
1c118b06c9 Merge remote-tracking branch 'origin/dev' into dev 2020-04-20 12:16:15 +08:00
a41c315e36 修复打包异常 2020-04-20 12:11:07 +08:00
40576e0012 光环前端优化汇总(2020年4月第3周)1,4 https://gitlab.ghzs.com/pm/halo-app-issues/issues/845 2020-04-20 11:58:12 +08:00
a582db52f4 游戏详情实体添加@Keep注解 2020-04-20 11:12:18 +08:00
cb2656ad85 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-19 17:59:19 +08:00
da1c686d42 尝试解决长时间处于后台视频流页面控件为空的问题 2020-04-19 17:58:41 +08:00
b613fe2ba0 修复由于延迟问答tab和我的光环tab加载引起的问题 2020-04-19 17:00:52 +08:00
83e29b1cf3 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-17 18:56:04 +08:00
5bbd23bf33 游戏详情游戏详细信息显示问题 2020-04-17 18:55:59 +08:00
9f69b83b51 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/common/util/GameUtils.java
2020-04-17 18:54:13 +08:00
4f77781e24 下载按钮状态优化(三) https://gitlab.ghzs.com/pm/halo-app-issues/issues/838 2020-04-17 18:50:28 +08:00
b23d589a29 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-17 17:49:33 +08:00
7f16a69301 完成游戏详情专区tab https://gitlab.ghzs.com/pm/halo-app-issues/issues/833 2020-04-17 17:49:08 +08:00
006da73737 基本完成游戏历史版本功能(部分UI细节待完善) https://gitlab.ghzs.com/pm/halo-app-issues/issues/832 2020-04-17 17:44:47 +08:00
3f998cdf75 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-17 16:38:13 +08:00
3e94cd9d8c 下载按钮状态优化(一,二) https://gitlab.ghzs.com/pm/halo-app-issues/issues/838 2020-04-17 16:38:06 +08:00
5922f92caf 游戏详情详细信息,版本求更新 https://gitlab.ghzs.com/pm/halo-app-issues/issues/830 2020-04-17 11:11:19 +08:00
f5f5909fde Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-16 19:00:58 +08:00
7e67357887 多版本下载面板UI跳转 2020-04-16 19:00:49 +08:00
d5750c6cb8 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-16 18:59:35 +08:00
b2983d5c96 游戏详情专区支持显示webview页面 2020-04-16 18:59:30 +08:00
5a19e46d26 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-16 18:44:04 +08:00
8456a5a1d6 多版本下载面板增加"其它版本"跳转按钮 2020-04-16 18:43:51 +08:00
b9329a092e 大致完成游戏详情详情tab(除自定义栏目) 2020-04-16 18:20:05 +08:00
6ecad9eebd Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-16 15:45:52 +08:00
f32dd9efee 多版本下载面板优化(添加相关交互动画) https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-16 15:45:44 +08:00
48cbaf03b7 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-15 18:57:51 +08:00
7f23cda97a 对接游戏详情数据(未完) 2020-04-15 18:57:46 +08:00
49c1809aa2 多版本下载面板优化(增加链接弹窗) https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-15 17:45:57 +08:00
173aa82134 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-15 15:49:01 +08:00
c57e8b2c76 多版本下载面板优化(细节补充) https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-15 15:48:35 +08:00
bb741013d4 Merge remote-tracking branch 'origin/dev' into dev 2020-04-15 10:33:21 +08:00
5b014a5a1d 更正版块曝光路径 https://gitlab.ghzs.com/pm/halo-app-issues/issues/843 2020-04-15 10:33:12 +08:00
a85548ac33 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-14 19:15:16 +08:00
77e689fec4 游戏详情UI 2020-04-14 19:15:11 +08:00
fe942dcf73 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-04-14 19:14:49 +08:00
da3b700403 多版本下载面板优化(合计页面基本完成)https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-14 19:13:57 +08:00
fcd46cb2ea 延迟加载我的光环 (部分问题后续处理 2020-04-14 12:10:01 +08:00
e918b19e2e 延迟渲染问答tab 2020-04-13 20:48:14 +08:00
afb8badc74 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-13 19:10:12 +08:00
4e22a5c7bb 游戏详情UI 2020-04-13 19:10:08 +08:00
b5d2e02606 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-13 18:57:32 +08:00
28afb4f14c 多版本下载面板优化(一级页面基本完成)https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-13 18:57:17 +08:00
165659a664 Merge branch 'optimise-startup' into 'dev'
Optimise startup

See merge request !14
2020-04-13 17:16:26 +08:00
7b3d910b10 优化首页启动速度 https://gitlab.ghzs.com/pm/halo-app-issues/issues/820 2020-04-13 17:12:12 +08:00
1e4a85719a Merge branch '3.7.5-bugfix' into 'dev'
3.7.5 bugfix

See merge request !13
2020-04-13 15:16:49 +08:00
4269cb37d2 Merge branch 'dev' into '3.7.5-bugfix'
# Conflicts:
#   dependencies.gradle
2020-04-13 15:16:32 +08:00
b7ce3e8c20 延迟初始化部分变量 2020-04-13 12:29:54 +08:00
15a0240808 游戏详情(未完) 2020-04-12 16:29:22 +08:00
0aa68ea04b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-10 19:03:44 +08:00
2d9b69fd1e 重新整理检查是否可以更新/插件化的方法 2020-04-10 19:03:37 +08:00
48d6023e0d 游戏下载弹窗:试玩提醒与设备提醒 20200409补充 https://gitlab.ghzs.com/pm/halo-app-issues/issues/818 2020-04-10 17:20:57 +08:00
0612582a46 支持应用内/外跳转社区专题 2020-04-10 11:34:05 +08:00
a3d0d91dd7 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-09 21:52:06 +08:00
982e8f67bf 游戏详情顶部区域UI 2020-04-09 21:51:41 +08:00
0bb871bff2 完成首页轮播图优化 https://gitlab.ghzs.com/pm/halo-app-issues/issues/820 2020-04-09 17:41:10 +08:00
0eb43d6552 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-09 17:24:42 +08:00
b4f29f4856 多版本下载面板优化(Item的数据填充)https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-09 17:24:20 +08:00
4fd68565d2 更换游戏详情标题栏icon 2020-04-09 11:12:11 +08:00
8241551438 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-09 10:42:04 +08:00
d7bb45f287 光环前端优化汇总(2020年4月第1周)11 https://gitlab.ghzs.com/pm/halo-app-issues/issues/824 2020-04-09 10:41:28 +08:00
dbb3078300 版本号改为 4.0.0 2020-04-09 10:07:35 +08:00
a7d141efcc Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-08 18:25:06 +08:00
31c404021c 多版本下载面板优化(初步完成UI相关)https://gitlab.ghzs.com/pm/halo-app-issues/issues/819 2020-04-08 18:24:48 +08:00
631cec2fc6 游戏详情顶部区域 2020-04-08 17:51:07 +08:00
be6eab0cae 首页专题支持游戏替换 https://gitlab.ghzs.com/pm/halo-app-issues/issues/820 2020-04-08 11:36:28 +08:00
71ee8bfd29 Merge remote-tracking branch 'origin/dev' into dev 2020-04-07 18:23:32 +08:00
66c9c02dc6 完成游戏大图UI优化 https://gitlab.ghzs.com/pm/halo-app-issues/issues/820 2020-04-07 18:23:21 +08:00
7880ee4aef 游戏详情Tab位置调整 2020-04-07 18:19:16 +08:00
6274d1f778 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2020-04-07 11:55:37 +08:00
5e98813f92 顶部Tab栏统一样式(补充:开服表)https://gitlab.ghzs.com/pm/halo-app-issues/issues/825 2020-04-07 11:55:21 +08:00
1a30800fb4 光环前端优化汇总(2020年4月第1周)9,10 https://gitlab.ghzs.com/pm/halo-app-issues/issues/824 2020-04-07 10:47:00 +08:00
454e6933f4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-06 17:51:19 +08:00
e3072071b7 完成游戏设备弹窗 https://gitlab.ghzs.com/pm/halo-app-issues/issues/818 2020-04-06 17:50:57 +08:00
83a88326f0 完成光环前端优化汇总(4月第1周)8 https://gitlab.ghzs.com/pm/halo-app-issues/issues/824 2020-04-06 10:36:19 +08:00
27109a810f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-06 10:20:26 +08:00
3d5bd424c5 游戏下载弹窗:试玩提醒 https://gitlab.ghzs.com/pm/halo-app-issues/issues/818 2020-04-06 10:20:02 +08:00
c7cd56e7be 完成光环前端优化汇总(4月第1周)的7,8,12 https://gitlab.ghzs.com/pm/halo-app-issues/issues/824 2020-04-06 10:05:17 +08:00
860769c44a 删除无用代码 2020-04-04 18:25:37 +08:00
a83761b88d 顶部Tab栏统一样式(除了开服表,其它的已完成)https://gitlab.ghzs.com/pm/halo-app-issues/issues/825 2020-04-04 18:11:53 +08:00
a79fc9c0b1 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-02 18:33:56 +08:00
877bd63d9d add DownloadDialog 2020-04-02 18:33:48 +08:00
bb9d0582c4 修改游戏试玩弹窗 2020-04-02 17:46:55 +08:00
df7e89e7e4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-02 16:45:54 +08:00
a12593ea51 游戏试玩弹窗 https://gitlab.ghzs.com/pm/halo-app-issues/issues/818 2020-04-02 16:45:16 +08:00
5ca0af4285 关闭TooLargeTool 2020-04-02 15:55:59 +08:00
89e72a0fea 下载按钮状态新增“试玩”(未完) 2020-04-02 14:13:02 +08:00
fc25ad7ddb Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-04-02 10:27:25 +08:00
6b656cf446 add todo 2020-04-02 10:27:06 +08:00
557 changed files with 16041 additions and 8651 deletions

View File

@ -122,7 +122,6 @@ android {
dimension "nonsense"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${COMMENT_HOST}\""
buildConfigField "String", "DATA_HOST", "\"${DATA_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
@ -140,7 +139,6 @@ android {
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
buildConfigField "String", "DATA_HOST", "\"${DEV_DATA_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
@ -273,8 +271,6 @@ dependencies {
exclude module: "gsyvideoplayer-androidvideocache"
})
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
// implementation "com.shuyu:gsyVideoPlayer-armv7a:$gsyVideo"
// implementation "com.shuyu:gsyVideoPlayer-x86:$gsyVideo"
implementation "com.github.wendux:DSBridge-Android:$dsBridge"

View File

@ -4,7 +4,6 @@ import android.app.Application;
import com.facebook.stetho.Stetho;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.gu.toolargetool.TooLargeTool;
import com.squareup.leakcanary.LeakCanary;
import okhttp3.OkHttpClient;
@ -30,7 +29,9 @@ public class Injection {
// init stetho
Stetho.initializeWithDefaults(application);
TooLargeTool.startLogging(application);
// 监控Bundle大小,预防溢出(需要调试的时候再开启吧!)
// TooLargeTool.startLogging(application);
return true;
}

View File

@ -115,6 +115,10 @@
android:name="com.gh.gamecenter.ShellActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.history.HistoryApkListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation="portrait" />
@ -458,8 +462,8 @@
<activity
android:name="com.gh.gamecenter.HelpAndFeedbackActivity"
android:windowSoftInputMode="stateHidden"
android:screenOrientation="portrait" />
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.help.HelpDetailActivity"
@ -480,6 +484,14 @@
android:name=".gamedetail.myrating.MyRatingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.QaActivity"
android:screenOrientation="portrait" />
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
<activity
android:name="com.gh.gamecenter.PushProxyActivity"

View File

@ -1,6 +1,8 @@
package com.gh.base;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@ -93,8 +95,8 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
ButterKnife.bind(this);
if (useEventBus()) EventBus.getDefault().register(this);
if (useButterKnife()) ButterKnife.bind(this);
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
if (TextUtils.isEmpty(mEntrance)) {
mEntrance = Constants.ENTRANCE_UNKNOWN;
@ -107,7 +109,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
if (useEventBus()) EventBus.getDefault().unregister(this);
mBaseHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
@ -187,13 +189,12 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
protected void onResume() {
super.onResume();
}
/**
* 可凭借此回调确定当前 activity 已经执行了 finish() 处于 isFinishing 状态
* 可在后续进行
* 此回调可用于确认当前 activity 已经执行了 finish() 方法并处于 isFinishing 状态
*/
protected void onFinish() {
}
@Override
@ -246,4 +247,22 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
return StringUtils.buildString(entrance, "+(", path, ")");
}
protected boolean useEventBus() {
return true;
}
protected boolean useButterKnife() {
return true;
}
@Override
public Resources getResources() {
Resources resources = super.getResources();
if (resources.getConfiguration().fontScale != 1.0f) {
Configuration configuration = resources.getConfiguration();
configuration.fontScale = 1.0f;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
return resources;
}
}

View File

@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import com.gh.base.adapter.FragmentAdapter;
import com.gh.base.fragment.BaseFragment_TabLayout;
import com.gh.common.view.TabIndicatorView;
import com.gh.gamecenter.R;
import com.google.android.material.tabs.TabLayout;
@ -45,7 +46,7 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
protected abstract void initTabTitleList(List<String> tabTitleList);
protected int provideIndicatorWidth() {
return 65;
return 20;
}
protected View provideTabView(int position, String tabTitle) {
@ -89,11 +90,14 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
TabLayout.Tab tab = mTabLayout.getTabAt(i);
if (tab == null) continue;
View tabView = provideTabView(i, tab.getText() != null ? tab.getText().toString() : "");
if (tabView == null) continue;
String tabTitle = tab.getText() != null ? tab.getText().toString() : "";
View tabView = provideTabView(i, tabTitle);
if (tabView == null)
tabView = BaseFragment_TabLayout.createDefaultTabCustomView(tabTitle);
tab.setCustomView(tabView);
}
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex);
}
@Override

View File

@ -145,7 +145,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
} else {
mCachedView = View.inflate(getContext(), getLayoutId(), null);
}
ButterKnife.bind(this, mCachedView);
if (useButterKnife()) {
ButterKnife.bind(this, mCachedView);
}
initView(mCachedView);
@ -309,4 +312,8 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
protected boolean addSyncPageObserver() {
return false;
}
protected boolean useButterKnife() {
return true;
}
}

View File

@ -1,18 +1,28 @@
package com.gh.base.fragment;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckedTextView;
import android.widget.TextView;
import com.gh.base.adapter.FragmentAdapter;
import com.gh.common.view.TabIndicatorView;
import com.gh.gamecenter.R;
import com.gh.gamecenter.normal.NormalFragment;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import com.lightgame.view.NoScrollableViewPager;
import java.util.ArrayList;
@ -46,7 +56,7 @@ public abstract class BaseFragment_TabLayout extends NormalFragment implements V
protected abstract void initTabTitleList(List<String> tabTitleList);
protected int provideIndicatorWidth() {
return 65;
return 20;
}
protected View provideTabView(int position, String tabTitle) {
@ -94,11 +104,71 @@ public abstract class BaseFragment_TabLayout extends NormalFragment implements V
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
TabLayout.Tab tab = mTabLayout.getTabAt(i);
if (tab == null) continue;
View tabView = provideTabView(i, tab.getText() != null ? tab.getText().toString() : "");
if (tabView == null) continue;
String tabTitle = tab.getText() != null ? tab.getText().toString() : "";
View tabView = provideTabView(i, tabTitle);
if (tabView == null) tabView = createDefaultTabCustomView(tabTitle);
tab.setCustomView(tabView);
}
initTabStyle(mTabLayout, mCheckedIndex);
}
public static void initTabStyle(TabLayout tabLayout, int currentItem) {
// 默认选择addOnTabSelectedListener不会回调
int tabCount = tabLayout.getTabCount();
if (tabCount > 0) {
TabLayout.Tab tab = tabLayout.getTabAt(currentItem);
if (tab != null) updateTabStyle(tab, true);
}
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
updateTabStyle(tab, true);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
updateTabStyle(tab, false);
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
updateTabStyle(tab, true);
}
});
}
private static void updateTabStyle(TabLayout.Tab tab, boolean isChecked) {
View tabView = tab.getCustomView();
if (tabView == null) {
Utils.log("TabLayout->Tab样式不是通用样式,请检查");
return;
}
TextView tabTitle;
if (tabView instanceof TextView) {
tabTitle = (TextView) tabView;
} else {
tabTitle = tabView.findViewById(R.id.tab_title);
}
if (tabTitle == null) {
Utils.log("TabLayout->Tab样式不是通用样式,请检查");
return;
}
tabTitle.setTypeface(isChecked ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
}
// 如果不设置View的话无法动态设置字体样式
@NonNull
public static View createDefaultTabCustomView(String title) {
View view = LayoutInflater.from(HaloApp.getInstance().getApplication().getBaseContext()).inflate(R.layout.tab_item, null);
View tabTitle = view.findViewById(R.id.tab_title);
if (tabTitle instanceof CheckedTextView) {
((CheckedTextView) tabTitle).setText(title);
}
return view;
}
@Override

View File

@ -2,6 +2,7 @@ package com.gh.base.fragment
import android.os.Bundle
import com.gh.gamecenter.normal.NormalFragment
import com.lightgame.utils.Utils
/**
* 懒加载(支持多层嵌套)
@ -104,7 +105,7 @@ abstract class BaseLazyFragment : NormalFragment() {
isSupportVisible = visible
if (visible) {
if (mIsFirstVisible) {
if (mIsFirstVisible && view != null) {
mIsFirstVisible = false
onFragmentFirstVisible()
}

View File

@ -0,0 +1,152 @@
package com.gh.base.fragment
import android.content.Intent
import android.graphics.Typeface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckedTextView
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import butterknife.BindView
import com.gh.base.adapter.FragmentAdapter
import com.gh.common.view.TabIndicatorView
import com.gh.gamecenter.R
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.lightgame.view.NoScrollableViewPager
abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeListener {
@BindView(R.id.fragment_tab_layout)
lateinit var mTabLayout: TabLayout
@BindView(R.id.fragment_view_pager)
lateinit var mViewPager: NoScrollableViewPager
@BindView(R.id.fragment_tab_indicator)
lateinit var mTabIndicatorView: TabIndicatorView
var mFragmentsList: MutableList<Fragment> = arrayListOf()
var mTabTitleList: MutableList<String> = arrayListOf()
var mCheckedIndex = 0
abstract fun initFragmentList(fragments: MutableList<Fragment>)
abstract fun initTabTitleList(tabTitleList: MutableList<String>)
protected open fun provideIndicatorWidth(): Int {
return 20
}
protected open fun provideTabView(position: Int, tabTitle: String?): View? {
return null
}
override fun getLayoutId(): Int {
return R.layout.fragment_tablayout_viewpager
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val fragments = childFragmentManager.fragments
if (fragments != null) {
for (fragment in fragments) {
fragment.onActivityResult(requestCode, resultCode, data)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) mCheckedIndex = requireArguments().getInt(PAGE_INDEX, 0)
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
initFragmentList(mFragmentsList)
initTabTitleList(mTabTitleList)
mViewPager.offscreenPageLimit = mFragmentsList.size
mViewPager.addOnPageChangeListener(this)
mViewPager.adapter = FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
mViewPager.currentItem = mCheckedIndex
mTabLayout.setupWithViewPager(mViewPager)
mTabIndicatorView.setupWithTabLayout(mTabLayout)
mTabIndicatorView.setupWithViewPager(mViewPager)
mTabIndicatorView.setIndicatorWidth(provideIndicatorWidth())
for (i in 0 until mTabLayout.tabCount) {
val tab = mTabLayout.getTabAt(i) ?: continue
val tabTitle = if (tab.text != null) tab.text.toString() else ""
var tabView = provideTabView(i, tabTitle)
if (tabView == null) tabView = createDefaultTabCustomView(tabTitle)
tab.customView = tabView
}
initTabStyle(mTabLayout, mCheckedIndex)
}
open fun initTabStyle(tabLayout: TabLayout?, currentItem: Int) { // 默认选择addOnTabSelectedListener不会回调
val tabCount = tabLayout!!.tabCount
if (tabCount > 0) {
val tab = tabLayout.getTabAt(currentItem)
if (tab != null) updateTabStyle(tab, true)
}
tabLayout.addOnTabSelectedListener(object : OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
updateTabStyle(tab, true)
}
override fun onTabUnselected(tab: TabLayout.Tab) {
updateTabStyle(tab, false)
}
override fun onTabReselected(tab: TabLayout.Tab) {
updateTabStyle(tab, true)
}
})
}
open fun updateTabStyle(tab: TabLayout.Tab, isChecked: Boolean) {
val tabView = tab.customView
if (tabView == null) {
Utils.log("TabLayout->Tab样式不是通用样式,请检查")
return
}
val tabTitle: TextView?
tabTitle = if (tabView is TextView) {
tabView
} else {
tabView.findViewById(R.id.tab_title)
}
if (tabTitle == null) {
Utils.log("TabLayout->Tab样式不是通用样式,请检查")
return
}
tabTitle.typeface = if (isChecked) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
}
// 如果不设置View的话无法动态设置字体样式
open fun createDefaultTabCustomView(title: String?): View {
val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item, null)
val tabTitle = view.findViewById<View>(R.id.tab_title)
if (tabTitle is CheckedTextView) {
tabTitle.text = title
}
return view
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {}
override fun onPageScrollStateChanged(state: Int) {}
companion object {
const val PAGE_INDEX = "PAGE_INDEX"
}
}

View File

@ -5,7 +5,8 @@ import android.os.Looper
import com.gh.common.AppExecutor.ioExecutor
import com.gh.common.AppExecutor.lightWeightIoExecutor
import com.gh.common.AppExecutor.uiExecutor
import java.util.concurrent.*
import java.util.concurrent.Executor
import java.util.concurrent.Executors
/**
* APP 线程池管理类
@ -18,11 +19,11 @@ import java.util.concurrent.*
object AppExecutor {
@JvmStatic
var uiExecutor = MainThreadExecutor()
val uiExecutor by lazy { MainThreadExecutor() }
@JvmStatic
var lightWeightIoExecutor = Executors.newSingleThreadExecutor()
val lightWeightIoExecutor by lazy { Executors.newSingleThreadExecutor() }
@JvmStatic
var ioExecutor = Executors.newCachedThreadPool()
val ioExecutor = Executors.newCachedThreadPool() // 用 by lazy 可能影响初始化速度
class MainThreadExecutor : Executor {
private val mainThreadHandler = Handler(Looper.getMainLooper())

View File

@ -8,7 +8,6 @@ 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.common.util.EntranceUtils.ENTRANCE_BROWSER
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.LibaoDetailActivity
import com.gh.gamecenter.NewsDetailActivity
@ -18,7 +17,6 @@ import com.gh.gamecenter.entity.VideoLinkEntity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.lightgame.utils.Utils
import com.moor.imkf.requesturl.RequestUrl.type
object DefaultWebViewUrlHandler {
@ -46,7 +44,7 @@ object DefaultWebViewUrlHandler {
"qq" -> try {
DirectUtils.directToQqConversation(context, id)
} catch (e: Exception) {
} catch (e: Throwable) {
Utils.toast(context, "请检查是否已经安装手机QQ")
e.printStackTrace()
}
@ -81,10 +79,18 @@ object DefaultWebViewUrlHandler {
"community" -> {
val community = CommunityEntity()
community.id = id
community.name = uri.getQueryParameter("name")
community.name = uri.getQueryParameter("name") ?: ""
DirectUtils.directToCommunity(context, community)
}
"community_column" -> {
val community = CommunityEntity()
community.id = uri.getQueryParameter("community_id") ?: ""
community.name = uri.getQueryParameter("community_name") ?: ""
val columnId = uri.getQueryParameter("column_id") ?: ""
DirectUtils.directToCommunityColumn(context, community, columnId, entrance, "文章链接")
}
"answer" -> DirectUtils.directToAnswerDetail(context, id, entrance, "文章链接")
"communities" -> {

View File

@ -8,6 +8,7 @@ import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.util.edit
import com.gh.common.util.toJson
import com.gh.common.util.toObject
import com.gh.common.util.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.AliasEntity
import com.gh.gamecenter.retrofit.RetrofitManager
@ -35,33 +36,34 @@ object PushManager {
@JvmStatic
fun init(channel: String) {
//初始化友盟推送
UMConfigure.init(mApplication,
Config.UMENG_APPKEY, channel,
UMConfigure.DEVICE_TYPE_PHONE,
Config.UMENG_MESSAGE_SECRET)
tryWithDefaultCatch {
//初始化友盟推送
UMConfigure.init(mApplication,
Config.UMENG_APPKEY, channel,
UMConfigure.DEVICE_TYPE_PHONE,
Config.UMENG_MESSAGE_SECRET)
// 注册小米、华为和魅族通道
MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
HuaWeiRegister.register(mApplication)
MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
// 注册小米、华为和魅族通道
MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
HuaWeiRegister.register(mApplication)
MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
//友盟推送
val pushAgent = PushAgent.getInstance(mApplication)
pushAgent.onAppStart() // 开启App统计
//友盟推送
val pushAgent = PushAgent.getInstance(mApplication)
//注册推送服务每次调用register方法都会回调该接口
registerDevice()
//注册推送服务每次调用register方法都会回调该接口
runOnIoThread { registerDevice() }
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
mPreviousAlias = aliasInSp?.toObject()
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
mPreviousAlias = aliasInSp?.toObject()
if (mPreviousAlias == null) {
getAndSetAlias()
if (mPreviousAlias == null) {
getAndSetAlias()
}
// 完全自定义处理(透传)
pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
}
// 完全自定义处理(透传)
pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
}
private fun registerDevice() {

View File

@ -6,6 +6,7 @@ import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.halo.assistant.HaloApp
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
/**
@ -113,7 +114,7 @@ class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
}
object TimeElapsedThreadHolder {
val threadService = Executors.newSingleThreadExecutor()
val threadService: ExecutorService by lazy { Executors.newSingleThreadExecutor() }
}
interface TimeoutCallback {

View File

@ -5,6 +5,8 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.gh.common.util.GsonUtils;
import com.gh.common.util.PackageHelper;
import com.gh.common.util.PackageUtils;
@ -23,7 +25,6 @@ import org.greenrobot.eventbus.EventBus;
import java.util.List;
import androidx.annotation.Nullable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -31,7 +32,6 @@ public class Config {
public static final String API_HOST = BuildConfig.API_HOST;
public static final String COMMENT_HOST = BuildConfig.COMMENT_HOST;
public static final String DATA_HOST = BuildConfig.DATA_HOST;
/**
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
@ -234,6 +234,10 @@ public class Config {
return false;
}
public static boolean isGameDomeSwitchOpen() {
return getSettings() != null && getSettings().getGameDomeSwitch().equals("on");
}
public static void fixHideFunction() {
SharedPreferences preferences = PreferenceManager.
getDefaultSharedPreferences(HaloApp.getInstance().getApplication());

View File

@ -29,6 +29,8 @@ public class Constants {
public static final String EB_QUIT_LOGIN = "quit_login";
public static final String GAME_ID_DIVIDER = ":"; // 用于避免历史下载掺和到普通下载状态的 ID 修饰符
// 最近显示的弹窗信息
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
public static final String SP_LAST_OPENING_TIME = "last_opening_dialog_time";
@ -64,6 +66,16 @@ public class Constants {
public static final String SP_NON_WIFI_TIPS = "non_wifi_tips";
//首页视频最新tab提示
public static final String SP_HOME_NEW_VIDEO_TIPS = "home_new_video";
//游戏设备弹窗提示
public static final String SP_DEVICE_REMIND = "device_remind";
//是否是第一次弹出游戏设备弹窗提示
public static final String SP_FIRST_DEVICE_REMIND = "first_device_remind";
//游戏设备弹窗不再提示
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_AUTH_DIALOG= "auth_dialog";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";

View File

@ -13,9 +13,16 @@ 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;
@ -36,10 +43,10 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.PermissionHelper;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.common.view.DownloadDialog;
import com.gh.common.view.DownloadProgressBar;
import com.gh.common.view.DrawableView;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -65,12 +72,6 @@ import java.text.SimpleDateFormat;
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.
*/
@ -198,6 +199,17 @@ public class BindingAdapters {
}
}
@BindingAdapter("textColorFromString")
public static void textColorFromString(TextView tv, String hexString) {
if (TextUtils.isEmpty(hexString)) return;
try {
tv.setTextColor(Color.parseColor(hexString));
} catch (Exception e) {
e.printStackTrace();
}
}
@BindingAdapter("visibleGone")
public static void showHide(View view, Boolean show) {
if (show != null && show) {
@ -207,6 +219,32 @@ public class BindingAdapters {
}
}
@BindingAdapter("goneIf")
public static void goneIf(View view, Boolean gone) {
if (gone != null && gone) {
view.setVisibility(View.GONE);
} else {
view.setVisibility(View.VISIBLE);
}
}
/**
* lazy 的 paddingTop
*/
@BindingAdapter("lazyPaddingTop")
public static void lazyPaddingTop(View view, int paddingTopInDp) {
view.setPadding(view.getPaddingLeft(), DisplayUtils.dip2px(paddingTopInDp), view.getPaddingRight(), view.getPaddingBottom());
}
@BindingAdapter("visibleInvisible")
public static void visibleInvisible(View view, Boolean show) {
if (show != null && show) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.INVISIBLE);
}
}
@BindingAdapter("messageUnread")
public static void setMessageUnread(TextView view, int unreadCount) {
if (unreadCount < 100) {
@ -358,17 +396,25 @@ public class BindingAdapters {
case PLUGIN:
if (gameEntity.getApk().size() == 1) {
ApkEntity apk = gameEntity.getApk().get(0);
DownloadDialogHelper.findAvailableDialogAndShow(
v.getContext(),
gameEntity,
apk,
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk,
() -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
});
});
});
} else {
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
entrance, location + gameEntity.getName(), traceEvent);
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
entrance,
location + ":" + gameEntity.getName());
});
});
}
break;
case LAUNCH_OR_OPEN:
@ -376,8 +422,11 @@ public class BindingAdapters {
DataUtils.onGameLaunchEvent(v.getContext(), gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
PackageUtils.launchApplicationByPackageName(v.getContext(), gameEntity.getApk().get(0).getPackageName());
} else {
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
entrance, location + gameEntity.getName(), traceEvent);
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
entrance,
location + ":" + gameEntity.getName());
}
break;
case INSTALL_PLUGIN:
@ -455,7 +504,7 @@ public class BindingAdapters {
}
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
}
} else {
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity, PluginLocation.only_game);
switch (status) {
@ -511,6 +560,23 @@ public class BindingAdapters {
}
}
/*private static void download(DownloadProgressBar progressBar, GameEntity gameEntity, ExposureEvent traceEvent, @Nullable String entrance, @Nullable String location, View v) {
if (gameEntity.getApk().size() == 1) {
ApkEntity apk = gameEntity.getApk().get(0);
DownloadDialogHelper.findAvailableDialogAndShow(
v.getContext(),
gameEntity,
apk,
() -> {
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
});
} else {
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
entrance, location + gameEntity.getName(), traceEvent);
}
}*/
private static void updateReservation(DownloadProgressBar progressBar, GameEntity gameEntity) {
// 显示预约
@ -546,10 +612,10 @@ public class BindingAdapters {
String msg = FileUtils.isCanDownload(progressBar.getContext(), apkEntity.getSize());
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,
@ -567,27 +633,9 @@ public class BindingAdapters {
}
}
@BindingAdapter({"gameLabelList", "subjectTag"})
public static void setGameLabelList(LinearLayout layout, GameEntity gameEntity, String subjectTag) {
if (gameEntity == null) return;
if (gameEntity.getTest() != null) {
layout.removeAllViews();
View testView = LayoutInflater.from(layout.getContext()).inflate(R.layout.game_test_label, null);
TextView testType = testView.findViewById(R.id.test_type);
TextView testTime = testView.findViewById(R.id.test_time);
testType.setText(gameEntity.getTest().getType());
testType.setBackgroundColor(ContextCompat.getColor(layout.getContext(), R.color.tag_yellow));
if (gameEntity.getTest().getStart() == 0) {
testTime.setVisibility(View.GONE);
} else {
testTime.setText(GameViewUtils.getGameTestDate(gameEntity.getTest().getStart()));
}
layout.addView(testView);
} else {
GameViewUtils.setLabelList(layout.getContext(), layout, gameEntity.getTag(), subjectTag, gameEntity.getTagStyle());
}
@BindingAdapter("gameLabelList")
public static void setGameLabelList(LinearLayout layout, List<TagStyleEntity> tagStyle) {
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
}
@BindingAdapter("isRefreshing")

View File

@ -15,6 +15,7 @@ abstract class BaseTrackableDialogFragment : BaseDialogFragment() {
abstract fun getEvent(): String
abstract fun getKey(): String
open fun getValue(): String = ""
// 区分此 dialog 是点击 dialog 外部取消的还是点击返回取消的
private val mIsCanceledByClickOutsideOfDialog = AtomicBoolean(true)
@ -47,6 +48,9 @@ abstract class BaseTrackableDialogFragment : BaseDialogFragment() {
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), value)
} else {
MtaHelper.onEvent(getEvent(), getKey(), value)
if (getValue().isNotEmpty()) {
MtaHelper.onEvent(getEvent(), value, getValue())
}
}
}

View File

@ -0,0 +1,196 @@
package com.gh.common.dialog
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckBox
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.avoidcallback.AvoidOnResultManager
import com.gh.common.avoidcallback.Callback
import com.gh.common.constant.Constants
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.DialogUtils
import com.gh.common.util.GsonUtils
import com.gh.common.util.SPUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.UserInfoEditActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.entity.AuthDialogEntity
import com.gh.gamecenter.entity.AuthDialogLevel
import com.gh.gamecenter.entity.DeviceDialogEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.user.UserViewModel
import com.google.gson.reflect.TypeToken
import com.halo.assistant.fragment.user.UserInfoEditFragment
import com.lightgame.utils.AppManager
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
class CertificationDialog(context: Context, private val authDialogEntity: AuthDialogEntity, val gameId: String, val listener: DialogUtils.ConfirmListener) :
Dialog(context, R.style.GhAlertDialog) {
private lateinit var view: View
private lateinit var detailedDesTv: TextView
private lateinit var noRemindAgainCb: CheckBox
private lateinit var actionLeftTv: TextView
private lateinit var actionRightTv: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
view = LayoutInflater.from(context).inflate(R.layout.dialog_sertification, null)
setContentView(view)
detailedDesTv = view.findViewById(R.id.detailedDesTv)
noRemindAgainCb = view.findViewById(R.id.noRemindAgainCb)
actionLeftTv = view.findViewById(R.id.actionLeftTv)
actionRightTv = view.findViewById(R.id.actionRightTv)
detailedDesTv.paint.flags = Paint.UNDERLINE_TEXT_FLAG
detailedDesTv.paint.isAntiAlias = true
detailedDesTv.setOnClickListener {
context.startActivity(WebActivity.getIntentByUrl(context, authDialogEntity.link))
}
when (authDialogEntity.level) {
AuthDialogLevel.MUST_PASS.value -> {
actionLeftTv.text = "暂不下载"
actionRightTv.text = "去实名认证"
noRemindAgainCb.visibility = View.GONE
actionLeftTv.setOnClickListener {
dismiss()
}
actionRightTv.setOnClickListener {
if (UserManager.getInstance().isLoggedIn) {
gotoAuthPage()
} else {
gotoLoginPage()
}
}
}
AuthDialogLevel.ALWAYS_HINT.value -> {
actionLeftTv.text = "去实名认证"
actionRightTv.text = "继续下载"
noRemindAgainCb.visibility = View.GONE
actionLeftTv.setOnClickListener {
if (UserManager.getInstance().isLoggedIn) {
gotoAuthPage()
} else {
gotoLoginPage()
}
}
actionRightTv.setOnClickListener {
listener.onConfirm()
dismiss()
}
}
AuthDialogLevel.OPTIONAL_HINT.value -> {
actionLeftTv.text = "去实名认证"
actionRightTv.text = "继续下载"
noRemindAgainCb.visibility = View.VISIBLE
actionLeftTv.setOnClickListener {
if (noRemindAgainCb.isChecked) {
SPUtils.setBoolean(gameId, true)
}
if (UserManager.getInstance().isLoggedIn) {
gotoAuthPage()
} else {
gotoLoginPage()
}
}
actionRightTv.setOnClickListener {
if (noRemindAgainCb.isChecked) {
SPUtils.getBoolean(gameId, true)
}
listener.onConfirm()
dismiss()
}
}
}
}
//跳转登录页面
private fun gotoLoginPage() {
CheckLoginUtils.checkLogin(AppManager.getInstance().currentActivity() as AppCompatActivity,
null, true, "实名认证弹窗") {
if (UserManager.getInstance().isAuth) {
listener.onConfirm()
dismiss()
}
}
}
//跳转实名认证页面
private fun gotoAuthPage() {
AvoidOnResultManager.getInstance(AppManager.getInstance().currentActivity() as AppCompatActivity)
.startForResult(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD), object : Callback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {
val isAuthSuccess = data.getBooleanExtra(UserInfoEditFragment.AUTH_SUCCESS, false)
if (isAuthSuccess) {
listener.onConfirm()
dismiss()
}
}
}
})
}
companion object {
@JvmStatic
fun showCertificationDialog(context: Context, game: GameEntity, listener: DialogUtils.ConfirmListener) {
//1.先判断是否登录 是执行2 否执行3
//2.判断是否实名认证 是终止 否执行3
//3.判断是否需要弹出认证弹窗接口
if (UserManager.getInstance().isLoggedIn) {
if (UserManager.getInstance().isAuth) {//已实名认证
listener.onConfirm()
} else {
authDialog(context, game, listener)
}
} else {
authDialog(context, game, listener)
}
}
@SuppressLint("CheckResult")
private fun authDialog(context: Context, game: GameEntity, listener: DialogUtils.ConfirmListener) {
var authDialog: AuthDialogEntity? = null
if (game.authDialog != null) {
authDialog = game.authDialog
}
if (authDialog == null) {
val datas = SPUtils.getString(Constants.SP_AUTH_DIALOG)
val type = object : TypeToken<List<AuthDialogEntity>>() {}.type
val authDialogs = GsonUtils.gson.fromJson<List<AuthDialogEntity>>(datas, type)
if (!authDialogs.isNullOrEmpty()) {
authDialog = authDialogs.find { it.gameCategory == game.category }
}
}
val isCloseAuthDialog = SPUtils.getBoolean(game.id, false)
if (authDialog != null && (authDialog.level != AuthDialogLevel.OPTIONAL_HINT.value || !isCloseAuthDialog)) {
val dialog = CertificationDialog(context, authDialog, game.id, listener)
dialog.show()
} else {
listener.onConfirm()
}
}
}
}

View File

@ -0,0 +1,234 @@
package com.gh.common.dialog
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
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.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.DeviceDialogEntity
import com.gh.gamecenter.entity.GameEntity
import com.google.gson.reflect.TypeToken
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
/**
* 设备提醒弹窗
*/
class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val gameEntity: GameEntity) : Dialog(context, R.style.GhAlertDialog) {
private lateinit var view: View
private var currentPage = 0
private var mSlideLooperInterval = 3000L
private lateinit var mLooperHandle: LooperHandle
private lateinit var mAdapter: BannerAdapter
private var mDatas: ArrayList<String> = ArrayList()
private val mSlideLooperKey = 100
private var disposable: Disposable? = null
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.status == DownloadStatus.done && downloadEntity.name == gameEntity.name) {
val sp = PreferenceManager.getDefaultSharedPreferences(getContext())
val autoInstall = sp.getBoolean(AUTO_INSTALL_SP_KEY, true)
if (autoInstall) {
dismiss()
}
}
}
}
companion object {
fun showDeviceRemindDialog(context: Context, gameEntity: GameEntity) {
val datas = SPUtils.getString(Constants.SP_DEVICE_REMIND)
if (datas.isNotEmpty()) {
val type = object : TypeToken<List<DeviceDialogEntity>>() {}.type
val entitys = GsonUtils.gson.fromJson<List<DeviceDialogEntity>>(datas, type)
//1.判断设备是否匹配
val entity = entitys.find { it.manufacturer.toLowerCase().startsWith(Build.MANUFACTURER.toLowerCase()) }
?: return
//2.判断游戏不含剔除标签
gameEntity.tagStyle.forEach {
if (entity.excludeTags.contains(it.name)) {
return
}
}
//3.不再弹出提示判断
val isNoRemindAgain = SPUtils.getBoolean(Constants.SP_NO_REMIND_AGAIN, false)
if (isNoRemindAgain) return
val dialog = DeviceRemindDialog(context, entity, gameEntity)
dialog.show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
view = LayoutInflater.from(context).inflate(R.layout.dialog_device_remind, null)
setContentView(view)
mDatas.addAll(entity.gallery)
view.titleTv.text = entity.title
view.contentTv.text = entity.content
view.bannerView.apply {
orientation = ViewPager2.ORIENTATION_HORIZONTAL
mAdapter = BannerAdapter()
val recyclerView = getChildAt(0) as RecyclerView
recyclerView.overScrollMode = RecyclerView.OVER_SCROLL_NEVER
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
currentPage = position
slideIndicator(currentPage % mDatas.size)
}
})
recyclerView.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
val isStop = e.action == MotionEvent.ACTION_DOWN || e.action == MotionEvent.ACTION_MOVE
if (isStop) mAdapter.stopScroll() else mAdapter.startScroll()
return false
}
})
adapter = mAdapter
mLooperHandle = LooperHandle(mAdapter)
currentPage = (adapter as BannerAdapter).getActualFirstPositionInCenter()
setCurrentItem(currentPage, false)
if (mDatas.size > 1) {
addIndicator()
slideIndicator(currentPage % mDatas.size)
autoPlay()
}
}
val isFirst = SPUtils.getBoolean(Constants.SP_FIRST_DEVICE_REMIND, false)
if (!isFirst) {
view.cancelTv.isEnabled = false
view.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_round_f5f5f5)
disposable = countDownTimer(3) { finish, time ->
if (finish) {
view.cancelTv.isEnabled = true
view.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
view.cancelTv.text = "我知道了"
view.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
} else {
view.cancelTv.text = "我知道了(${time}S)"
}
}
SPUtils.setBoolean(Constants.SP_FIRST_DEVICE_REMIND, true)
} else {
view.noRemindAgainCb.visibility = View.VISIBLE
view.cancelTv.text = "我知道了"
view.cancelTv.isEnabled = true
view.cancelTv.setTextColor(ContextCompat.getColor(context, R.color.white))
view.cancelTv.background = ContextCompat.getDrawable(context, R.drawable.button_blue_oval)
}
view.cancelTv.setOnClickListener {
SPUtils.setBoolean(Constants.SP_NO_REMIND_AGAIN, view.noRemindAgainCb.isChecked)
dismiss()
}
DownloadManager.getInstance(context).addObserver(dataWatcher)
}
private fun addIndicator() {
view.indicatorLl.removeAllViews()
mDatas.forEach { _ ->
val indicatorView = ImageView(context).apply {
setImageResource(R.drawable.selector_device_remind_indicator)
val params = LinearLayout.LayoutParams(DisplayUtils.dip2px(8F), LinearLayout.LayoutParams.WRAP_CONTENT)
params.leftMargin = DisplayUtils.dip2px(1F)
params.rightMargin = DisplayUtils.dip2px(1F)
layoutParams = params
}
view.indicatorLl.addView(indicatorView)
}
}
private fun slideIndicator(position: Int) {
for (i in 0 until view.indicatorLl.childCount) {
val childAt = view.indicatorLl.getChildAt(i)
childAt.isSelected = i == position
}
}
private fun autoPlay() {
mAdapter.startScroll()
}
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)) {}
}
override fun getItemCount(): Int = if (mDatas.size == 1) mDatas.size else Int.MAX_VALUE
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val data = mDatas[position % mDatas.size]
val view = holder.itemView as SimpleDraweeView
ImageUtils.display(view, data)
}
fun getActualFirstPositionInCenter(): Int {
if (mDatas.size == 1) return 0
var index = itemCount / 2
if (index % mDatas.size != 0) {
index -= (index % mDatas.size)
}
return index
}
fun scrollToNextPage() {
currentPage++
view.bannerView.setCurrentItem(currentPage, true)
}
fun startScroll() {
mLooperHandle.removeMessages(mSlideLooperKey)
mLooperHandle.sendEmptyMessageDelayed(mSlideLooperKey, mSlideLooperInterval)
}
fun stopScroll() {
mLooperHandle.removeMessages(mSlideLooperKey)
}
}
class LooperHandle(val mAdapter: BannerAdapter) : Handler() {
private val mWeakReference: WeakReference<BannerAdapter> = WeakReference(mAdapter)
override fun handleMessage(msg: Message?) {
val adapter = mWeakReference.get()
adapter?.scrollToNextPage()
adapter?.startScroll()
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
if (disposable != null && !disposable!!.isDisposed) {
disposable!!.dispose()
disposable = null
}
DownloadManager.getInstance(context).removeObserver(dataWatcher)
}
}

View File

@ -8,12 +8,13 @@ import com.gh.common.util.MtaHelper
import java.util.concurrent.atomic.AtomicBoolean
open class TrackableDialog(context: Context,
themeResId: Int,
private var mEvent: String,
private var mKey: String,
private var mCancelValue: String? = null,
private var mKeyBackValue: String? = null,
private var mLogShowEvent: Boolean = true)
themeResId: Int,
private var mEvent: String,
private var mKey: String,
private var mValue: String? = null,
private var mCancelValue: String? = null,
private var mKeyBackValue: String? = null,
private var mLogShowEvent: Boolean = true)
: Dialog(context, themeResId) {
// 区分此 dialog 是点击 dialog 外部取消的还是点击返回取消的
@ -25,6 +26,9 @@ open class TrackableDialog(context: Context,
setOnCancelListener {
if (mIsCanceledByClickOutsideOfDialog.get()) {
MtaHelper.onEvent(mEvent, mKey, mCancelValue ?: "点击空白")
if (!mValue.isNullOrEmpty()) {
MtaHelper.onEvent(mEvent, "点击空白", mValue)
}
}
}
@ -32,6 +36,9 @@ open class TrackableDialog(context: Context,
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
mIsCanceledByClickOutsideOfDialog.set(false)
MtaHelper.onEvent(mEvent, mKey, mKeyBackValue ?: "点击返回")
if (mValue != null) {
MtaHelper.onEvent(mEvent, "点击返回", mValue)
}
}
false
}
@ -41,6 +48,9 @@ open class TrackableDialog(context: Context,
super.show()
if (mLogShowEvent) {
MtaHelper.onEvent(mEvent, mKey, "出现弹窗")
if (!mValue.isNullOrEmpty()) {
MtaHelper.onEvent(mEvent, "出现弹窗", mValue)
}
}
}

View File

@ -31,9 +31,9 @@ object ExposureManager {
private val loghubHelper = LoghubHelper.getInstance()
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
private val exposureSet = hashSetOf<ExposureEvent>()
private val exposureExecutor = Executors.newSingleThreadExecutor()
private val exposureCache = FixedSizeLinkedHashSet<String>(300)
private val exposureSet by lazy { hashSetOf<ExposureEvent>() }
private val exposureExecutor by lazy { Executors.newSingleThreadExecutor() }
private val exposureCache by lazy { FixedSizeLinkedHashSet<String>(300) }
private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
@JvmStatic

View File

@ -15,7 +15,7 @@ object LoghubUtils {
private lateinit var mApplication: Application
private val loghubEventSet = hashSetOf<LoghubEvent>()
private val loghubEventSet by lazy { hashSetOf<LoghubEvent>() }
private val loghubEventExecutor by lazy { Executors.newSingleThreadExecutor() }
private val loghubEventDao by lazy { LoghubDatabase.buildDatabase(mApplication).logHubEventDao() }
@ -75,8 +75,16 @@ object LoghubUtils {
}
val log = Log()
log.PutContent("current time ", event.time)
log.PutContent("content", event.content)
// 特殊处理以下logStore不需要用content包裹数据
if (event.logStore == "collection" || event.logStore == "common" || event.logStore == "halo-api-device-installed") {
val contentJson = JSONObject(event.content)
for (key in contentJson.keys()) {
log.PutContent(key, contentJson.get(key).toString())
}
} else {
log.PutContent("current time ", event.time)
log.PutContent("content", event.content)
}
logGroupHashMap[event.logStore]?.PutLog(log)
}

View File

@ -14,4 +14,7 @@ object SyncFieldConstants {
const val ANSWER_COMMENT_COUNT = "ANSWER_COMMENT_COUNT"
const val ARTICLE_COMMENT_COUNT = "ARTICLE_COMMENT_COUNT"
// 回答数量
const val ANSWER_COUNT = "ANSWER_COUNT"
}

View File

@ -5,6 +5,7 @@ import android.graphics.BitmapFactory
import android.graphics.Matrix
import com.gh.common.constant.Config
import com.gh.gamecenter.entity.SettingsEntity
import com.github.piasy.biv.metadata.ImageInfoExtractor
import com.halo.assistant.HaloApp
import java.io.File
import java.io.FileOutputStream
@ -26,11 +27,16 @@ object CompressImageUtils {
* 压缩图片并保存到目标文件
* 该压缩方法是同步执行 请勿在主线程执行
* 返回源文件的三种情况:小于特定值,图片类型为GIF,压缩失败
* ---------------------------------------------------------------------------------------------
* 关于压缩格式问题:
* 1.图片详情对动态Webp/静态Webp的判断存在问题导致部分静态Webp图片误判为动态Webp而直接委托Fresco处理出现无法缩放问题
* 2.为了解决上述问题如果压缩是检测到是动态Webp时直接压缩为JPEG这样就能解决图片详情无法缩放问题todo 这样会导致动态Webp无法播放
*/
@Throws(Exception::class)
fun compressImageAndSaveToFile(imageFile: File, compressGif: Boolean): File {
val imageType = ImageInfoExtractor.getImageType(imageFile)
// 小于某一个设定的值时,直接返回原图
if (imageFile.length() < getImageSetting().processLimitSize) {
if (imageType != ImageInfoExtractor.TYPE_ANIMATED_WEBP && imageFile.length() < getImageSetting().processLimitSize) {
return imageFile
}
@ -49,7 +55,7 @@ object CompressImageUtils {
} else if (options.outMimeType.contains("gif") && !compressGif) { // gif直接返回原图
return imageFile
} else {
Bitmap.CompressFormat.WEBP
Bitmap.CompressFormat.JPEG
}
fileOutputStream = FileOutputStream(cacheDir)
@ -165,6 +171,7 @@ object CompressImageUtils {
enum class CompressType {
// 0: 短边等比压缩至1280 H:长边 W:短边
LIMIT_SHORT,
// 1: 取长边等比压缩至1280 H:短边 W: 长边
LIMIT_LONG
}

View File

@ -9,8 +9,6 @@ import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import org.json.JSONArray;
import java.util.HashMap;
import java.util.Map;
@ -169,24 +167,4 @@ public class DataCollectionUtils {
map.put("type", args[2]);
DataCollectionManager.onEvent(context, "concern", map);
}
//上传推荐位数据
public static void uploadPosition(Context context, String... args) {
if (args.length < 3) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("page", args[0]);
map.put("location", args[1]);
map.put("name", args[2]);
DataCollectionManager.onEvent(context, "position", map);
}
//上传应用列表
public static void uploadAppList(Context context, JSONArray applist) {
Map<String, Object> map = new HashMap<>();
map.put("applist", applist);
DataCollectionManager.onEvent(context, "applist", map);
}
}

View File

@ -2,8 +2,7 @@ package com.gh.common.util;
import android.content.Context;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.common.loghub.LoghubUtils;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Util_System_Phone_State;
@ -14,12 +13,6 @@ import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
/**
* Created by LGT on 2016/12/8.
* 日志上传工具类
@ -68,12 +61,7 @@ public class DataLogUtils {
params.put("time", String.valueOf(Utils.getTime(context)));
params.put("content", new JSONObject(map).toString());
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
new JSONObject(params).toString());
RetrofitManager.getInstance(context).getData().postLog(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());
LoghubUtils.log(new JSONObject(params), "common", true);
}
// 网络错误

View File

@ -13,6 +13,7 @@ import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Utils;
/**
* Created by khy on 27/06/17.
@ -22,6 +23,7 @@ import com.lightgame.download.DownloadEntity;
public class DetailDownloadUtils {
public static void detailInitDownload(DetailViewHolder viewHolder, boolean isCheck) {
String downloadAddWord = viewHolder.gameEntity.getDownloadAddWord();
if (viewHolder.gameEntity != null
&& Config.isShowDownload(viewHolder.gameEntity.getId())
@ -34,10 +36,11 @@ public class DetailDownloadUtils {
if (viewHolder.gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(viewHolder.gameEntity.getId())) {
if (TextUtils.isEmpty(viewHolder.downloadAddWord)) {
if (TextUtils.isEmpty(downloadAddWord)) {
viewHolder.mDownloadPb.setText(String.format("预约" + "《%s》", viewHolder.gameEntity.getName()));
} else {
viewHolder.mDownloadPb.setText(String.format("预约" + "《%s》%s", viewHolder.gameEntity.getName(), viewHolder.downloadAddWord));
viewHolder.mDownloadPb.setText(String.format("预约" + "《%s》%s", viewHolder.gameEntity.getName(), downloadAddWord));
}
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.RESERVABLE);
} else {
@ -49,10 +52,10 @@ public class DetailDownloadUtils {
if (viewHolder.gameEntity.getApk().isEmpty() || viewHolder.gameEntity.getDownloadOffStatus() != null) {
LinkEntity h5LinkEntity = viewHolder.gameEntity.getH5Link();
if (h5LinkEntity != null) {
if ("play".equals(h5LinkEntity.getType())) {
String defaultString = String.format("开始玩" + "《%s》", viewHolder.gameEntity.getName());
String defaultString = String.format("开始玩" + "《%s》", viewHolder.gameEntity.getName());
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(h5LinkEntity.getText()) ? defaultString : h5LinkEntity.getText());
} else {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(h5LinkEntity.getText()) ? "查看" : h5LinkEntity.getText());
@ -60,35 +63,39 @@ public class DetailDownloadUtils {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.H5_GAME);
} else {
if ("dialog".equals(viewHolder.gameEntity.getDownloadOffStatus())) {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.downloadOffText) ? "查看详情" : viewHolder.downloadOffText);
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.gameEntity.getDownloadOffText()) ? "查看详情" : viewHolder.gameEntity.getDownloadOffText());
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NONE_WITH_HINT);
} else {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.downloadOffText) ? "暂无下载" : viewHolder.downloadOffText);
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.gameEntity.getDownloadOffText()) ? "暂无下载" : viewHolder.gameEntity.getDownloadOffText());
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NONE);
}
}
} else {
} else if (viewHolder.gameEntity.getApk().size() == 1) {
String status = GameUtils.getDownloadBtnText(viewHolder.context, viewHolder.gameEntity, PluginLocation.only_game);
switch (status) {
case "插件化":
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN);
break;
case "打开":
case "启动":
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
break;
default:
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
break;
if (viewHolder.context.getString(R.string.pluggable).equals(status)) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN);
} else if (viewHolder.context.getString(R.string.launch).equals(status)) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
}
String downloadText;
if (viewHolder.isNewsDetail) {
viewHolder.mDownloadPb.setText(status);
} else if (TextUtils.isEmpty(viewHolder.downloadAddWord)) {
viewHolder.mDownloadPb.setText(String.format(status + "《%s》", viewHolder.gameEntity.getName()));
downloadText = status;
} else if (viewHolder.context.getString(R.string.pluggable).equals(status)) {
downloadText = "升级" + (TextUtils.isEmpty(downloadAddWord) ? "" : "" + downloadAddWord) + getDownloadSizeText(viewHolder);
} else if (viewHolder.context.getString(R.string.launch).equals(status)) {
downloadText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord);
} else if (viewHolder.context.getString(R.string.attempt).equals(status)) {
downloadText = status + getDownloadSizeText(viewHolder);
} else {
viewHolder.mDownloadPb.setText(String.format(status + "《%s》%s", viewHolder.gameEntity.getName(), viewHolder.downloadAddWord));
downloadText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
}
viewHolder.mDownloadPb.setText(downloadText);
} else {
viewHolder.mDownloadPb.setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord) + " >");
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
}
if (isCheck && viewHolder.gameEntity.getApk().size() == 1) {
String url = viewHolder.gameEntity.getApk().get(0).getUrl();
@ -100,6 +107,10 @@ public class DetailDownloadUtils {
}
}
private static String getDownloadSizeText(DetailViewHolder viewHolder) {
return String.format("%s", viewHolder.gameEntity.getApk().get(0).getSize());
}
public static void detailInvalidate(DetailViewHolder viewHolder) {
viewHolder.mDownloadPb.setProgress((int) (viewHolder.downloadEntity.getPercent() * 10));
DownloadEntity downloadEntity = viewHolder.downloadEntity;
@ -128,7 +139,7 @@ public class DetailDownloadUtils {
case done:
viewHolder.mDownloadPb.setText(R.string.install);
if (downloadEntity.isPluggable()
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
&& PackagesManager.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
@ -143,6 +154,4 @@ public class DetailDownloadUtils {
break;
}
}
}

View File

@ -8,6 +8,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.text.Html;
@ -29,23 +30,24 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Config;
import com.gh.common.dialog.TrackableDialog;
import com.gh.common.view.DrawableView;
import com.gh.common.view.FixLinearLayoutManager;
import com.gh.common.view.LimitHeightLinearLayout;
import com.gh.common.view.MaxHeightNestedScrollView;
import com.gh.gamecenter.AboutActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
import com.gh.gamecenter.databinding.PrivacyItemBinding;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.entity.TrackableEntity;
import com.halo.assistant.HaloApp;
import com.halo.assistant.fragment.SettingsFragment;
@ -53,9 +55,17 @@ import com.lightgame.adapter.BaseRecyclerAdapter;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
public class DialogUtils {
public static Dialog showWaitDialog(Context context, String msg) {
@ -1097,6 +1107,7 @@ public class DialogUtils {
R.style.GhAlertDialog,
trackableEntity.getEvent(),
trackableEntity.getKey(),
trackableEntity.getValue(),
trackableEntity.getCancelValue(),
trackableEntity.getKeyBackValue(),
trackableEntity.getLogShowEvent());
@ -1224,6 +1235,114 @@ public class DialogUtils {
dialog.show();
}
public static void showVersionNumberDialog(Context context, GameEntity gameEntity, @NonNull ConfirmListener listener) {
context = checkDialogContext(context);
if (!gameEntity.isShowVersionNumber()) {
listener.onConfirm();
} else {
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_version_number, null);
TextView contentTv = contentView.findViewById(R.id.contentTv);
TextView cancelTv = contentView.findViewById(R.id.cancelTv);
TextView continueTv = contentView.findViewById(R.id.continueTv);
contentTv.setText(gameEntity.getVersionNumberString());
cancelTv.setOnClickListener(v -> dialog.dismiss());
continueTv.setOnClickListener(v -> {
listener.onConfirm();
dialog.dismiss();
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
}
public static void showImprintDialog(Context context, GameEntity gameEntity, String titleName) {
context = checkDialogContext(context);
Dialog dialog = new Dialog(context, R.style.full_dialog);
View inflate = LayoutInflater.from(context).inflate(R.layout.imprint_dialog, null);
dialog.setContentView(inflate);
dialog.show();
Window window = dialog.getWindow();
WindowManager.LayoutParams params;
if (window != null) {
params = window.getAttributes();
params.width = (int) (context.getResources().getDisplayMetrics().widthPixels * 0.9);
window.setAttributes(params);
window.setBackgroundDrawableResource(R.drawable.full_dialog_background);
}
inflate.findViewById(R.id.imprint_close).setOnClickListener(v -> dialog.dismiss());
LinearLayout content = inflate.findViewById(R.id.imprint_content);
((TextView) inflate.findViewById(R.id.imprint_title)).setText(titleName);
View head = LayoutInflater.from(context).inflate(R.layout.imprint_content_item, null);
content.addView(head, LinearLayout.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(30));
LimitHeightLinearLayout imprintContainer = inflate.findViewById(R.id.imprint_container);
imprintContainer.setLimitHeight((int) (context.getResources().getDisplayMetrics().heightPixels * 0.8));
ArrayList<ApkEntity> list = gameEntity.getApk();
SettingsEntity settings = Config.getSettings();
for (int i = 0; i < list.size(); i++) {
ApkEntity apk = gameEntity.getApk().get(i);
if (settings != null && settings.getGameDownloadBlackList().contains(apk.getPackageName())) {
continue;
}
View item = LayoutInflater.from(context).inflate(R.layout.imprint_content_item, null);
ImprintContentItemBinding bind = DataBindingUtil.bind(item);
bind.setApk(apk);
bind.setPlatformName(PlatformUtils.getInstance(context).getPlatformName(apk.getPlatform()));
content.addView(item, LinearLayout.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(40));
}
// close line
View view = new View(context);
view.setBackgroundColor(context.getResources().getColor(R.color.text_5d5d5d));
view.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(1)));
content.addView(view);
}
public static void showKaifuRemindDialog(Context context, String content, String gameName) {
context = checkDialogContext(context);
final Dialog dialog = new TrackableDialog(context, R.style.GhAlertDialog, "开服说明弹窗", "弹窗", gameName, null, null, true);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_kaifu_remind, null);
TextView contentTv = contentView.findViewById(R.id.contentTv);
MaxHeightNestedScrollView scrollView = contentView.findViewById(R.id.scrollView);
contentTv.setText(Html.fromHtml(content));
TextView ok = contentView.findViewById(R.id.dialog_ok);
scrollView.setScrollChangedListener((l, t, oldl, oldt) -> {
MtaHelper.onEvent("开服说明弹窗", "滑动内容", gameName);
});
ok.setOnClickListener(v -> {
MtaHelper.onEvent("开服说明弹窗", "弹窗", "点击我知道了");
MtaHelper.onEvent("开服说明弹窗", "点击我知道了", gameName);
dialog.dismiss();
});
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
/**
* @param context may be is application context
* @return activity context

View File

@ -188,7 +188,7 @@ object DirectUtils {
"column_collection", "专题合集" -> directToColumnCollection(context, linkEntity.link!!, -1, entrance)
"server" -> {
"server", "game_server" -> {
context.startActivity(GameServersActivity.getIntent(context, entrance, path))
}
@ -204,6 +204,20 @@ object DirectUtils {
"game_video" -> directToGameVideo(context, linkEntity.link ?: "", entrance, path)
"libao" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, entrance)
"qa" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa_collection" -> directToQaCollection(context, linkEntity.text ?: "", linkEntity.link
?: "")
"anliwall" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
"" -> {
// do nothing
}
else -> {
if (unknownCallback != null) {
unknownCallback.invoke()
@ -214,11 +228,25 @@ object DirectUtils {
}
}
/**
* 跳转至QA
*/
fun directToQa(context: Context, text: String, id: String) {
context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaId = id))
}
/**
* 跳转至QA合集
*/
fun directToQaCollection(context: Context, text: String, id: String) {
context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaCollectionId = id))
}
/**
* 跳转至专题合集
*/
fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String) {
context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance))
fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String, columnName: String = "") {
context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance, columnName))
}
/**
@ -315,12 +343,21 @@ object DirectUtils {
// 反馈
@JvmStatic
fun directToFeedback(context: Context, content: String? = null, entrance: String? = null) {
directToFeedback(context, content, null, entrance)
}
@JvmStatic
fun directToFeedback(context: Context, content: String? = null, hintType: String? = null, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SuggestionActivity::class.java.simpleName)
bundle.putString(KEY_CONTENT, content)
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
bundle.putSerializable(EntranceUtils.KEY_SUGGESTTYPE, SuggestType.gameQuestion)
if (TextUtils.isEmpty(hintType)) {
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
} else {
bundle.putString(KEY_SUGGEST_HINT_TYPE, hintType)
}
bundle.putSerializable(KEY_SUGGESTTYPE, SuggestType.gameQuestion)
jumpActivity(context, bundle)
}
@ -449,6 +486,7 @@ object DirectUtils {
return true
} catch (e: Exception) {
// 未安装手Q或安装的版本不支持
Utils.toast(context, "请安装QQ客户端")
return false
}
}

View File

@ -8,13 +8,21 @@ 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.repository.ReservationRepository;
import com.gh.common.view.DownloadDialog;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -32,12 +40,9 @@ 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 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
*/
public class DownloadItemUtils {
// 更新下载进度条
@ -125,20 +130,20 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setTextColor(Color.WHITE);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_dn);
}
if (gameEntity.isLibaoExists()) {
holder.gameLibaoIcon.setVisibility(View.VISIBLE);
} else {
holder.gameLibaoIcon.setVisibility(View.GONE);
}
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform) {
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game);
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false);
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform, PluginLocation pluginLocation) {
boolean isShowPlatform, boolean hideDownloadBtnIfNoAvailableContent) {
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, hideDownloadBtnIfNoAvailableContent);
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform, PluginLocation pluginLocation, boolean hideDownloadBtnIfNoAvailableContent) {
// 控制是否显示下载按钮
if (!Config.isShowDownload(gameEntity.getId()) || context.getString(R.string.app_name).equals(gameEntity.getName())) {
@ -147,12 +152,6 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setVisibility(View.VISIBLE);
}
if (gameEntity.isLibaoExists()) {
holder.gameLibaoIcon.setVisibility(View.VISIBLE);
} else {
holder.gameLibaoIcon.setVisibility(View.GONE);
}
// 显示预约
if (gameEntity.isReservable()) {
holder.gameDes.setVisibility(View.VISIBLE);
@ -171,14 +170,14 @@ public class DownloadItemUtils {
}
if (gameEntity.getApk().isEmpty()
|| gameEntity.getDownloadOffStatus() != null) {
|| gameEntity.getDownloadOffStatus() != null) {
LinkEntity h5LinkEntity = gameEntity.getH5Link();
String offStatus = gameEntity.getDownloadOffStatus();
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
if (h5LinkEntity != null) {
if ("play".equals(h5LinkEntity.getType())) {
holder.gameDownloadBtn.setText("开始玩");
@ -195,6 +194,9 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setText("暂无");
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(context, R.color.button_gray));
holder.gameDownloadBtn.setBackgroundResource(R.drawable.news_detail_comment);
if (hideDownloadBtnIfNoAvailableContent) {
holder.gameDownloadBtn.setVisibility(View.GONE);
}
}
holder.gameDownloadBtn.setClickable(false);
}
@ -334,10 +336,10 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setText(R.string.install);
holder.gameDownloadBtn.setTextColor(Color.WHITE);
if (downloadEntity.isPluggable()
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
&& PackagesManager.isInstalled(downloadEntity.getPackageName())) {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.download_button_pluggable_style);
} else {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.download_button_normal_style);
}
}
}
@ -420,7 +422,7 @@ public class DownloadItemUtils {
}
return;
}
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
downloadBtn.setOnClickListener(v -> {
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
@ -449,7 +451,15 @@ public class DownloadItemUtils {
clickCallback.onCallback();
}
PermissionHelper.checkStoragePermissionBeforeAction(context, () -> {
DownloadDialog.getInstance(context).showPopupWindow(v, gameEntity, entrance, location, traceEvent);
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DownloadDialog.showDownloadDialog(
v.getContext(),
gameEntity,
entrance,
location);
});
});
});
});
}
@ -480,19 +490,38 @@ public class DownloadItemUtils {
if (str.equals(context.getString(R.string.download))) {
// 先弹下载弹窗(如果需要的话)
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
} else if (str.equals(context.getString(R.string.pluggable))) {
} else if (str.equals(context.getString(R.string.attempt))) {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
});
DataLogUtils.uploadGameLog(context, gameEntity.getId(), gameEntity.getName(), entrance);
} else if (str.contains("")) {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "插件化", gameEntity.getName());
}
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> plugin(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
if (gameEntity.getPluggableCollection() != null) {
DownloadDialog.showDownloadDialog(context, gameEntity, entrance, location);
} else {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
DialogUtils.checkDownload(context, apk.getSize(),
isSubscribe -> plugin(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
});
});
}
} else if (str.equals(context.getString(R.string.install))) {
install(context, gameEntity, position, adapter);
} else if (str.equals(context.getString(R.string.launch))) {
@ -536,6 +565,7 @@ public class DownloadItemUtils {
downloadBtn.setText(R.string.downloading);
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
downloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
DeviceRemindDialog.Companion.showDeviceRemindDialog(context, gameEntity);
} else {
Utils.toast(context, msg);
}
@ -575,6 +605,8 @@ public class DownloadItemUtils {
gameEntity.getEntryMap().remove(apkEntity.getPlatform());
}
adapter.notifyItemChanged(position);
} else if (PackageUtils.isCanPluggable(apkEntity)) {
DialogUtils.showPluginDialog(context, () -> context.startActivity(PackageUtils.getUninstallIntent(context, path)));
} else {
PackageUtils.launchSetup(context, downloadEntity);
}
@ -584,12 +616,12 @@ 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);
.getPlatform(), traceEvent, downloadType);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, downloadExposureEvent);
}

View File

@ -35,13 +35,15 @@ import org.json.JSONObject
import java.util.*
object DownloadObserver {
private val mApplication = HaloApp.getInstance().application
@JvmStatic
fun initObserver() {
val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
val gameId = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
if (downloadEntity.status != DownloadStatus.downloading) {
LogUtils.uploadDownloadEvent(downloadEntity)
}
@ -51,7 +53,7 @@ object DownloadObserver {
processHijack(downloadEntity)
val nameAndPlatform = (downloadEntity.name + ":"
+ PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
MtaHelper.onEvent( "下载劫持",
MtaHelper.onEvent("下载劫持",
"游戏名字", nameAndPlatform,
"网络状态", DeviceUtils.getNetwork(mApplication))
return
@ -70,7 +72,7 @@ object DownloadObserver {
SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
SuggestType.gameQuestion, "notfound",
StringUtils.buildString(downloadEntity.name, ",问题反馈:下载链接失效"),
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, ""))
SimpleGameEntity(gameId, downloadEntity.name, ""))
}, null)
return
} else if (DownloadStatus.neterror == downloadEntity.status || DownloadStatus.timeout == downloadEntity.status) {
@ -126,7 +128,7 @@ object DownloadObserver {
}
// 统计下载完成
uploadData(downloadEntity.gameId, downloadEntity.platform)
uploadData(gameId, downloadEntity.platform)
}
// 下载过程分析统计
@ -142,7 +144,7 @@ object DownloadObserver {
}
if (downloadEntity.status == DownloadStatus.done) {
EventBus.getDefault().post(EBDownloadStatus("done", "", "", "", "", ""))
EventBus.getDefault().post(EBDownloadStatus("done", "", "", "", downloadEntity.packageName, ""))
}
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
@ -188,7 +190,7 @@ object DownloadObserver {
val kv3 = HashMap<String, Any>()
kv3["下载"] = "下载完成"
kv3["版本"] = downloadEntity.platform
kv3["位置"] = downloadEntity.entrance ?: "null"
kv3["位置"] = downloadEntity.entrance ?: "null"
type = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD
DataUtils.onEvent(mApplication, "插件化", downloadEntity.name, kv3)
@ -201,7 +203,7 @@ object DownloadObserver {
}
ExposureUtils.logADownloadCompleteExposureEvent(
GameEntity(downloadEntity.gameId, downloadEntity.name),
GameEntity(downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), downloadEntity.name),
downloadEntity.platform,
downloadEntity.exposureTrace,
type)

View File

@ -86,6 +86,7 @@ public class EntranceUtils {
public static final String KEY_OLDERUSER = "isOldUser";
public static final String KEY_SEARCHKEY = "searchKey";
public static final String KEY_HINT = "hint";
public static final String KEY_GAME = "game";
public static final String KEY_GAME_ICON_URL = "gameIconUrl";
public static final String KEY_SHARECONTENT = "shareContent";
public static final String KEY_SUGGESTTYPE = "suggestType";
@ -138,6 +139,7 @@ public class EntranceUtils {
public static final String KEY_DIRECT_COMMENT = "directComment";
public static final String KEY_SORT = "sort";
public static final String KEY_AMWAY = "amway";
public static final String KEY_SKIP_SUCCESS_PAGE = "skipSuccessPage";
public static final String KEY_COLLECTION_ID = "collectionId";
public static final String KEY_NAVIGATION_TITLE = "navigationTitle";
public static final String KEY_IMAGE_CROP_RATIO = "imageCropRatio";
@ -149,6 +151,9 @@ public class EntranceUtils {
public static final String KEY_WEB_SHARE = "webShare";
public static final String KEY_ACTIVITY_NAME = "activityName";//活动名称
public static final String KEY_REQUIRE_REDIRECT = "require_redirect"; // 标记需要再跳转
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 void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -237,6 +237,15 @@ inline fun tryCatchInRelease(action: (() -> Unit)) {
}
}
/**
* 在 debug 状态下抛出异常
*/
fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) {
if (predicate && BuildConfig.DEBUG) {
throw RuntimeException(message)
}
}
/**
* String related
*/

View File

@ -82,11 +82,70 @@ object GameRepositoryHelper {
return null
}
fun replaceInstalledApp(gameList: MutableList<GameEntity>,
alreadyDisplayedGameIdSet: HashSet<String>,
relatedCollectionId: String,
shouldLogReplaceEvent: Boolean) {
val positionOfTheGameToReplaceList = arrayListOf<Int>()
// 标记需要替换的已安装游戏
for ((index, game) in gameList.withIndex()) {
// 是大图形式的游戏时不标记替换
if ((index == 0 && !gameList[0].image.isNullOrEmpty())) {
continue
}
var isThisPositionAdded = false
// 检查是否已安装该游戏里同包名的 APK
for (apk in game.getApk()) {
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
// 将该位置的游戏标记为需要替换
positionOfTheGameToReplaceList.add(index)
isThisPositionAdded = true
break
}
}
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
if (!isThisPositionAdded) {
var relatedPackageList = arrayListOf<String>()
for (entity in PackageHelper.relatedPackageList) {
if (entity.gameId == game.id) {
relatedPackageList = ArrayList(entity.packages)
break
}
}
for (packageName in relatedPackageList) {
if (PackageHelper.validLocalPackageNameSet.contains(packageName)) {
positionOfTheGameToReplaceList.add(index)
break
}
}
}
}
if (positionOfTheGameToReplaceList.isNotEmpty()) {
if (shouldLogReplaceEvent) {
MtaHelper.onEvent("首页_加载", "启动光环", "替换游戏")
}
for (position in positionOfTheGameToReplaceList) {
val replacingGame = getOneUniqueGame(relatedCollectionId, alreadyDisplayedGameIdSet)
replacingGame?.let {
gameList[position] = replacingGame
}
}
}
}
private fun isThisGameUnique(game: GameEntity, gameIdList: HashSet<String>): Boolean {
// 若该补充游戏已经存在关联关系,判定为非唯一
for (relatedId in game.relatedGameIds!!) {
gameIdList.contains(relatedId)
return false
if (gameIdList.contains(relatedId)) {
return false
}
}
for (apk in game.getApk()) {
// 检查本地是否已安装该游戏,已过滤那部分框架服务的包名

View File

@ -5,12 +5,12 @@ import android.graphics.Color;
import android.text.TextUtils;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.gh.common.constant.Config;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.ApkLink;
import com.gh.gamecenter.entity.GameCollectionEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.entity.PluginLocation;
@ -19,8 +19,11 @@ import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
public class GameUtils {
@ -53,13 +56,13 @@ public class GameUtils {
String status = getDownloadBtnText(context, gameEntity, pluginLocation);
downloadBtn.setTextColor(Color.WHITE);
downloadBtn.setText(status);
if ("插件化".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else if ("打开".equals(status) || "启动".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.detail_download_open_style);
downloadBtn.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
if (context.getString(R.string.pluggable).equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.download_button_pluggable_style);
String pluginDesc = gameEntity.getPluginDesc();
if (pluginDesc.length() > 3) pluginDesc = pluginDesc.substring(0, 3);
downloadBtn.setText((pluginDesc + ""));
} else {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
downloadBtn.setBackgroundResource(R.drawable.download_button_normal_style);
}
}
@ -67,6 +70,10 @@ public class GameUtils {
* 获取下载按钮文案
*/
public static String getDownloadBtnText(Context context, GameEntity gameEntity, PluginLocation pluginLocation) {
if (gameEntity.getApk().size() > 1) {
return context.getString(R.string.expand);
}
int doneCount = 0; // 下载完成数量
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
@ -118,18 +125,59 @@ public class GameUtils {
} else if (updateCount != 0) {
return context.getString(R.string.update);
} else if (installCount != 0) {
if (gameEntity.getApk().size() == 1) {
return context.getString(R.string.launch);
} else {
return context.getString(R.string.open);
}
return context.getString(R.string.launch);
} else if (gameEntity.getVersionNumber().contains("无版号") && Config.isGameDomeSwitchOpen()) {
return context.getString(R.string.attempt);
} else {
return context.getString(R.string.download);
}
}
/**
* 获取GameUpdateEntity
* 获取简单的下载按钮文案,只需要知道是否已下载,是否已安装
*/
public static String getSimpleDownloadBtnText(Context context, GameEntity gameEntity) {
int doneCount = 0; // 下载完成数量
int installCount = 0; // 已安装数量
DownloadEntity downloadEntity;
Object gh_id;
apkFor:
for (ApkEntity apkEntity : gameEntity.getApk()) {
// filter by packageName
SettingsEntity settings = Config.getSettings();
if (settings != null && gameEntity.getApk().size() > 1) {
for (String pkgName : settings.getGameDownloadBlackList()) {
if (pkgName.equals(apkEntity.getPackageName())) {
continue apkFor;
}
}
}
downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity != null) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
doneCount++;
}
}
if (PackagesManager.INSTANCE.isInstalled(apkEntity.getPackageName())) {
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gh_id == null || gh_id.equals(gameEntity.getId())) {
installCount++;
}
}
}
if (doneCount != 0) {
return context.getString(R.string.install);
} else if (installCount != 0) {
return context.getString(R.string.launch);
} else {
return context.getString(R.string.download);
}
}
/**
* 获取GameUpdateEntity(插件化)
*/
public static GameUpdateEntity getGameUpdateEntity(GameEntity gameEntity, ApkEntity apkEntity) {
GameUpdateEntity gameUpdateEntity = new GameUpdateEntity();
@ -150,7 +198,50 @@ public class GameUtils {
gameUpdateEntity.setPlugin(apkEntity.getPlugin());
gameUpdateEntity.setDownload(gameEntity.getDownload());
gameUpdateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
gameUpdateEntity.setPluginDesc(gameEntity.getPluginDesc());
GameCollectionEntity pluggableCollection = getPluggableCollectionFromGameEntity(gameEntity, apkEntity.getPackageName());
if (pluggableCollection != null) {
gameUpdateEntity.setPluggableCollection(pluggableCollection);
}
return gameUpdateEntity;
}
@Nullable
public static GameCollectionEntity getPluggableCollectionFromGameEntity(GameEntity gameEntity, String targetPkg) {
// 添加插件化包所在的合集
for (GameCollectionEntity collectionEntity : gameEntity.getCollection()) {
if (collectionEntity.getPackages().contains(targetPkg)) {
ArrayList<ApkEntity> saveApkEntity = new ArrayList<>();
for (String pkg : collectionEntity.getPackages()) {
for (ApkEntity apk : gameEntity.getApk()) {
if (pkg.equals(apk.getPackageName())) {
saveApkEntity.add(apk);
break;
}
}
}
ArrayList<ApkLink> apkLinks = gameEntity.getApkLink();
if (apkLinks != null) {
for (ApkLink apkLink : apkLinks) {
if (apkLink.getCollection().equals(collectionEntity.getId())) {
ApkEntity element = new ApkEntity();
element.setApkLink(apkLink);
if (saveApkEntity.size() > apkLink.getSort()) {
saveApkEntity.add(apkLink.getSort(), element);
} else {
saveApkEntity.add(element);
}
}
}
}
collectionEntity.setSaveApkEntity(saveApkEntity);
return collectionEntity;
}
}
return null;
}
}

View File

@ -10,6 +10,9 @@ import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.gh.common.view.DrawableView;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.TagStyleEntity;
@ -21,8 +24,6 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import androidx.core.content.ContextCompat;
/**
* @author 温冠超
* @email 294299195@qq.com
@ -32,21 +33,16 @@ import androidx.core.content.ContextCompat;
*/
public class GameViewUtils {
public static void setLabelList(Context context, LinearLayout labelLayout, List<String> tag, String tagType, List<TagStyleEntity> tagStyle) {
public static void setLabelList(Context context, LinearLayout labelLayout, List<TagStyleEntity> tagStyle) {
labelLayout.removeAllViews();
if (tag == null || tag.isEmpty()) {
labelLayout.addView(getGameTagView(context, "官方版", 0, tagType, null));
if (tagStyle == null || tagStyle.isEmpty()) {
TagStyleEntity tagEntity = new TagStyleEntity();
tagEntity.setName("官方版");
labelLayout.addView(getNewGameTagView(context, tagEntity, 0));
} else {
for (int i = 0, size = tag.size(); i < size; i++) {
View view;
if (i == size - 1) {
view = getGameTagView(context, tag.get(i), 0, tagType, tagStyle.size() > i ? tagStyle.get(i) : null);
} else {
view = getGameTagView(context, tag.get(i), DisplayUtils.dip2px(context, 8), tagType, tagStyle.size() > i ? tagStyle.get(i) : null);
}
if (view != null) {
labelLayout.addView(view);
}
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));
labelLayout.addView(view);
if (labelLayout.getChildCount() == 3) {
break;
}
@ -76,6 +72,32 @@ public class GameViewUtils {
}
}
// 新的游戏标签样式 version>=4.0.0
private static TextView getNewGameTagView(Context context, TagStyleEntity tagEntity, int rightMargin) {
// 参数不全,用旧样式实现
if (TextUtils.isEmpty(tagEntity.getBackground())) {
return getGameTagView(context, tagEntity.getName(), rightMargin, "type", tagEntity);
}
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lparams.rightMargin = rightMargin;
TextView tag = new TextView(context);
tag.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
tag.setSingleLine(true);
tag.setText(tagEntity.getName());
tag.setLayoutParams(lparams);
tag.setPadding(
DisplayUtils.dip2px(context, 4),
0,
DisplayUtils.dip2px(context, 4),
DisplayUtils.dip2px(context, 1));
tag.setTextColor(Color.parseColor("#" + tagEntity.getColor()));
tag.setBackground(DrawableView.getServerDrawable(Color.parseColor("#" + tagEntity.getBackground())));
return tag;
}
private static TextView getGameTagView(Context context, String tagStr, int rightMargin, String tagType, TagStyleEntity tagEntity) {
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

View File

@ -22,6 +22,12 @@ object GsonUtils {
return gson.fromJson(json.toString(), type)
}
@JvmStatic
fun <T> fromJsonList(json: String): List<T> {
val type = object : TypeToken<List<T>>() {}.type
return gson.fromJson(json, type)
}
@JvmStatic
fun toJson(any: Any?): String {
return gson.toJson(any)

View File

@ -16,12 +16,14 @@ import com.facebook.drawee.controller.ControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.core.ImagePipeline
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.ImageInfo
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.gh.common.constant.Config
import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
import java.io.ByteArrayOutputStream
@ -323,6 +325,14 @@ object ImageUtils {
draweeView.setImageURI("res:///" + res)
}
//预加载图片
@JvmStatic
fun prefetchToDiskCache(url: String){
val imagePipeline = Fresco.getImagePipeline()
val imageRequest = ImageRequest.fromUri(url)
imagePipeline.prefetchToDiskCache(imageRequest, HaloApp.getInstance().application)
}
public interface OnImageloadListener {
fun onLoadFinal(imageInfo: ImageInfo?)
}

View File

@ -68,7 +68,7 @@ public class InstallUtils {
if (!TextUtils.isEmpty(installVersion) && downloadEntity != null &&
installVersion.equals(downloadEntity.getVersionName())) {
if (!downloadEntity.isPluggable() || PackageUtils.isSignature(context, packageName)) {
EventBus.getDefault().post(new EBPackage("安装", packageName));
EventBus.getDefault().post(new EBPackage("安装", packageName, installVersion));
}
}
}
@ -85,7 +85,7 @@ public class InstallUtils {
keys.add(packageName);
} else if (!list.contains(packageName)) {
keys.add(packageName);
EventBus.getDefault().post(new EBPackage("卸载", packageName));
EventBus.getDefault().post(new EBPackage("卸载", packageName, ""));
}
}
for (String key : keys) {

View File

@ -11,8 +11,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
@ -37,6 +35,7 @@ import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import androidx.core.content.ContextCompat;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -151,76 +150,76 @@ public class LibaoUtils {
});
}
public static void setLiBaoBtnStatus(final TextView libaoBtn, String status, Context context) {
public static void setLiBaoBtnStatusRound(final TextView libaoBtn, String status, Context context) {
libaoBtn.setTextColor(Color.WHITE);
if (TextUtils.isEmpty(status)) return;
switch (status) {
case "ling":
libaoBtn.setText(R.string.libao_ling);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "tao":
libaoBtn.setText(R.string.libao_tao);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "coming":
libaoBtn.setText(R.string.libao_coming);
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "used_up":
libaoBtn.setText(R.string.libao_used_up);
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "finish":
libaoBtn.setText(R.string.libao_finish);
libaoBtn.setBackgroundResource(R.drawable.button_border_gray);
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
libaoBtn.setTextColor(context.getResources().getColor(R.color.button_gray));
break;
case "linged":
libaoBtn.setText(R.string.libao_linged);
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "taoed":
libaoBtn.setText(R.string.libao_taoed);
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "copy":
libaoBtn.setText(R.string.libao_copy);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "repeatLing":
libaoBtn.setText(R.string.libao_repeat_ling);
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "repeatLinged":
libaoBtn.setText(R.string.libao_repeat_ling);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "repeatTao":
libaoBtn.setText(R.string.libao_repeat_tao);
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_border);
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
break;
case "repeatTaoed":
libaoBtn.setText(R.string.libao_repeat_tao);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
case "unshelve":
libaoBtn.setBackgroundResource(R.drawable.button_border_gray);
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
libaoBtn.setText(R.string.libao_unshelve);
libaoBtn.setTextColor(context.getResources().getColor(R.color.button_gray));
break;
case "check":
libaoBtn.setText(R.string.libao_check);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
libaoBtn.setBackgroundResource(R.drawable.button_normal_round_style);
break;
default:
libaoBtn.setBackgroundResource(R.drawable.button_border_gray);
libaoBtn.setBackgroundResource(R.drawable.button_border_round_gray);
libaoBtn.setText("异常");
libaoBtn.setTextColor(context.getResources().getColor(R.color.button_gray));
break;
@ -230,7 +229,7 @@ public class LibaoUtils {
public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity,
final boolean isInstallRequired, final LibaoDetailAdapter adapter, final String entrance) {
String status = libaoEntity.getStatus();
setLiBaoBtnStatus(libaoBtn, status, context);
setLiBaoBtnStatusRound(libaoBtn, status, context);
libaoBtn.setOnClickListener(v -> {
String btnStatus = libaoBtn.getText().toString();

View File

@ -46,7 +46,7 @@ public class NewsUtils {
* 统计阅读量
*/
public static void statNewsViews(Context context, String news_id) {
RetrofitManager.getInstance(context).getData().postNewsViews(news_id)
RetrofitManager.getInstance(context).getApi().postArticleVisit(news_id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>());

View File

@ -8,7 +8,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
@ -21,6 +20,7 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.manager.PackagesManager;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Utils;
@ -31,12 +31,17 @@ import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
public class PackageUtils {
@ -46,47 +51,39 @@ public class PackageUtils {
/*
* 判断是否可以更新只判断gh_version的大小
*/
public static List<GameUpdateEntity> isCanUpdate(Context context, GameEntity gameEntity) {
public static List<GameUpdateEntity> getUpdateData(Context context, GameEntity gameEntity) {
List<GameUpdateEntity> updateList = new ArrayList<>();
boolean isAPluginGame = false;
// 插件更新
for (ApkEntity apkEntity : gameEntity.getApk()) {
// 判断是否gh_version是否存在
String gh_version = (String) PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_version");
Object gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gh_version != null && apkEntity.getGhVersion() != null && gh_id != null) {
// 确定这是一个插件游戏
if (!isAPluginGame) isAPluginGame = true;
gh_version = gh_version.substring(2);
if (Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity.getForce()
&& gh_id.equals(gameEntity.getId())) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTag(gameEntity.getTag());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setDownload(gameEntity.getDownload());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateList.add(updateEntity);
}
if (isCanUpdate(apkEntity, gameEntity.getId())) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTag(gameEntity.getTag());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setDownload(gameEntity.getDownload());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
updateList.add(updateEntity);
}
}
// 不是插件游戏
if (!isAPluginGame) {
for (ApkEntity apkEntity : gameEntity.getApkNormal()) {
// 插件游戏更新
for (ApkEntity apkEntity : gameEntity.getApkNormal()) {
// ghVersion 不存在即是非插件游戏
if (TextUtils.isEmpty(apkEntity.getGhVersion())) {
String versionFromRequest = apkEntity.getVersion();
String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName());
@ -114,6 +111,7 @@ public class PackageUtils {
updateEntity.setTag(gameEntity.getTag());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
updateList.add(updateEntity);
}
}
@ -139,6 +137,19 @@ public class PackageUtils {
return null;
}
/**
* 获取已安装游戏的光环ID(游戏ID)
*
* @param packageName
* @return
*/
@Nullable
public static Object getGhId(String packageName) {
return getMetaData(HaloApp.getInstance().getApplication(), packageName, "gh_id");
}
/*
* 判断是否是插件包
*/
@ -182,6 +193,28 @@ public class PackageUtils {
return false;
}
// 从 APK 中获取公钥(只支持包含 V1 签名的 APK
private static String getApkSignatureFromFile(String apkFilePath) {
try {
ZipFile apkFile = new ZipFile(apkFilePath);
Enumeration<?> entries = apkFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = ((ZipEntry) entries.nextElement());
String entryName = entry.getName();
if (entryName.contains("META-INF") && entryName.endsWith(".RSA")) {
InputStream is = apkFile.getInputStream(entry);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificates(is).toArray()[0];
return cert.getPublicKey().toString();
}
}
return "";
} catch (Exception e) {
return "";
}
}
/*
* 解析签名
*/
@ -197,7 +230,7 @@ public class PackageUtils {
}
return ret;
}
/*
* 启动安装应用程序
*/
@ -223,6 +256,7 @@ public class PackageUtils {
/**
* 根据 path 获取 apk 信息确定处理方式
*
* @return true 为直接唤起系统 PackageInstaller, false 为需要插件化
*/
public static boolean isCanLaunchSetup(Context context, String path) {
@ -231,7 +265,7 @@ public class PackageUtils {
if (TextUtils.isEmpty(packageName)) {
return true;
}
boolean isContain = com.gh.gamecenter.manager.PackagesManager.INSTANCE.isInstalled(packageName);
boolean isContain = PackagesManager.isInstalled(packageName);
if (!isContain) {
return true;
}
@ -246,6 +280,12 @@ public class PackageUtils {
return true;
}
// 从 APK 文件里读取公钥,与已安装的公钥比较判断是否一样
String signatureFromApk = getApkSignatureFromFile(path);
if (!TextUtils.isEmpty(signatureFromApk)) {
return signatureFromApk.equals(getApkSignatureByPackageName(context, packageName));
}
// 若已安装的应用的签名与即将要安装的签名一致也返回 true
return compareSignatureBetweenInstalledAppWithApk(context, packageName, path);
}
@ -458,4 +498,55 @@ public class PackageUtils {
return null;
}
/**
* todo 统一判断
* <p>
* 判断游戏包是否可以更新
*
* @param apkEntity apkEntity 必须是已安装的游戏
* @param gameId 游戏id
* @return true可以更新 false不可以更新
*/
public static boolean isCanUpdate(ApkEntity apkEntity, String gameId) {
// gh_version: gh + timestamp
String gh_version = (String) PackageUtils.getMetaData(
HaloApp.getInstance().getApplication(),
apkEntity.getPackageName(),
"gh_version");
// gh_version: game id
Object gh_id = PackageUtils.getMetaData(
HaloApp.getInstance().getApplication(),
apkEntity.getPackageName(),
"gh_id");
if (gh_version != null && apkEntity.getGhVersion() != null && gh_id != null) {
gh_version = gh_version.substring(2);
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion())
&& apkEntity.getForce()
&& gh_id.equals(gameId);
}
return false;
}
/**
* todo 统一判断
* <p>
* 判断游戏包是否可以插件化
*
* @param apkEntity apkEntity 必须是已安装的游戏
* @return true可以插件化 false不可以插件化
*/
public static boolean isCanPluggable(ApkEntity apkEntity) {
String gh_id = (String) PackageUtils.getMetaData(
HaloApp.getInstance().getApplication(),
apkEntity.getPackageName(),
"gh_id");
return PackageUtils.isInstalled(HaloApp.getInstance().getApplication(), apkEntity.getPackageName())
&& gh_id == null
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
}
}

View File

@ -1,102 +0,0 @@
package com.gh.common.util;
import android.util.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RSEUtils {
/**
* 公钥
*/
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQConqikyOCl5f/VO/vZ+s6wVOhFJcI7o7hYvaLQ5Lzt5/HXbozTeRrGonKFPJurapf9hzjkg0F4/BNFMGXRVlReVdwh+Px5rbXU/ceikF8Ouf67qxiGAuDVC+4e3eIHh+mH68DlqWFJ78sB80iSLXelflGuHkbTOTtaC5F2l+AgxQIDAQAB";
/**
* 加密算法RSA
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 使用公钥加密
*
* @param content
* @return
*/
public static String encryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
byte[] data = content.getBytes("UTF-8");
byte[] output = cipher.doFinal(data);
String s = new String(Base64.encode(output, Base64.DEFAULT));
return s;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 得到公钥
*
* @return PublicKey 公钥
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private static PublicKey getPublicKeyFromX509() throws Exception {
byte[] decodedKey = Base64.decode(PUBLIC_KEY, Base64.DEFAULT);
X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePublic(x509);
}
/**
* 使用公钥解密
*
* @param content 密文
* @return 解密后的字符串
*/
public static String decryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
InputStream ins = new ByteArrayInputStream(Base64.decode(content,
Base64.DEFAULT));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[128];
int len;
while ((len = ins.read(buffer)) != -1) {
byte[] block;
if (buffer.length == len) {
block = buffer;
} else {
block = new byte[len];
for (int i = 0; i < len; i++) {
block[i] = buffer[i];
}
}
baos.write(cipher.doFinal(block));
}
return new String(baos.toByteArray(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -206,9 +206,9 @@ public class ShareUtils {
arrLogo[7] = R.drawable.share_cancel_logo;
}
popupWindow = new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
popupWindow = new SharePopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
, LinearLayout.LayoutParams.MATCH_PARENT, true);
popupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);
popupWindow.setAnimationStyle(R.style.popwindow_exit_only_anim_style);
//解决PopupWindow无法覆盖状态栏
popupWindow.setClippingEnabled(false);
@ -655,5 +655,20 @@ public class ShareUtils {
void onCancel();
}
}
private static class SharePopupWindow extends PopupWindow {
SharePopupWindow(View contentView, int width, int height, boolean focusable) {
super(contentView, width, height, focusable);
}
@Override
public void dismiss() {
View backgroundView = getContentView().findViewById(R.id.share_container);
if (backgroundView != null) {
backgroundView.setBackgroundColor(Color.TRANSPARENT);
}
getContentView().postDelayed(super::dismiss, 0);
}
}
}

View File

@ -1,6 +1,7 @@
package com.gh.common.util
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.text.SpannableStringBuilder
import android.text.Spanned
@ -21,6 +22,14 @@ class SpanBuilder(content: String) {
return this
}
fun color(start: Int, end: Int, colorHexInString: String): SpanBuilder {
tryWithDefaultCatch {
val colorSpan = ForegroundColorSpan(Color.parseColor(colorHexInString))
spannableString.setSpan(colorSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
return this
}
fun size(start: Int, end: Int, dpSize: Int): SpanBuilder {
val s = AbsoluteSizeSpan(dpSize, true)
spannableString.setSpan(s, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

View File

@ -5,6 +5,7 @@ import android.content.Context
import android.graphics.Color
import android.text.*
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.view.View
import android.widget.EditText
@ -92,7 +93,8 @@ object TextHelper {
@JvmStatic
fun highlightTextThatIsWrappedInsideWrapperByDefault(textView: TextView, text: String?) {
textView.text = getHighlightedSpannableStringThatIsWrappedInsideWrapper(textView.context, text ?: "", "###", R.color.theme_font, object : SimpleCallback<String> {
textView.text = getHighlightedSpannableStringThatIsWrappedInsideWrapper(textView.context, text
?: "", "###", R.color.theme_font, object : SimpleCallback<String> {
override fun onCallback(arg: String) {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@ -185,8 +187,8 @@ object TextHelper {
*/
fun getCommentLabelSpannableStringBuilder(comment: CharSequence,
amwayStyle: Boolean = false,
tagStrokeColor: String = "#FFDAA2",
tagTextColor: String = "#FF9B06"): SpannableStringBuilder {
tagStrokeColor: String = "#FA8E00",
tagTextColor: String = "#FA8E00"): SpannableStringBuilder {
val contents = SpannableStringBuilder()
var count = 0
val splits = comment.split("<tag>")
@ -220,6 +222,35 @@ object TextHelper {
return contents
}
fun getCommentLabelSpannableStringBuilder(comment: CharSequence, colorRes: Int): SpannableStringBuilder {
val contents = SpannableStringBuilder()
var count = 0
val splits = comment.split("<tag>")
splits.forEachIndexed { index, s ->
if (index != 0) {
val item = "<tag>$s"
val pattern = Pattern.compile("<tag>(\\S+)</tag>([\\S\\s\n]+)")
val matcher = pattern.matcher(item)
if (matcher.find()) {
val label = matcher.group(1)
var content = item.substring(item.indexOf("</tag>") + 6)
if (index == splits.size - 1) content += " "
val newLabel = "#$label# "
contents.append(newLabel)
contents.setSpan(ForegroundColorSpan(ContextCompat.getColor(HaloApp.getInstance().application, colorRes)),
count, count + newLabel.length - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
count += newLabel.length
contents.append(content)
count += content.length
}
} else {
contents.append(s)
count += s.length
}
}
return contents
}
private fun getRoundStrokeBackgroundColorSpan(amwayStyle: Boolean,
tagStrokeColor: String,
tagTextColor: String): RoundStrokeBackgroundColorSpan {

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
@ -19,4 +20,57 @@ object TimeUtils {
val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
return formatter.format(date)
}
fun getFormatTime(time: Long, pattern: String = "yyyy-MM-dd"): String {
val f = SimpleDateFormat(pattern, Locale.CHINA)
return f.format(Date(time * 1000))
}
fun getFormatDate(timestamp: Long): String {
val format = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
format.timeZone = TimeZone.getTimeZone("Asia/Shanghai")
val testDate: String
val today = format.parse(format.format(Date())).time
val day = timestamp * 1000
val timeFormat = SimpleDateFormat("HH:mm", Locale.CHINA)
val time = timeFormat.format(day)
testDate = if (day >= today && day < today + 86400 * 1000) {
"今天 $time"
} else if (day >= today + 86400 * 1000 && day < today + 86400 * 1000 * 2) {
"明天 $time"
} else {
SimpleDateFormat("MM-dd HH:mm", Locale.CHINA).format(day)
}
return testDate
}
//判断是不是今天
fun isToday(timestamp: Long): Boolean {
val format = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
format.timeZone = TimeZone.getTimeZone("Asia/Shanghai")
val today = format.parse(format.format(Date())).time
val day = timestamp * 1000
if (day >= today && day < today + 86400 * 1000) {
return true
}
return false
}
/**
* 判断时间戳是多少天前
*/
fun getBeforeDays(timestamp: Long):Int{
var days: Long = 0
val format = SimpleDateFormat("yyyyMMdd HH:mm", Locale.getDefault())
try {
val today = format.parse(format.format(Date())).time
val day = timestamp * 1000
days = (today - day) / 86400000
} catch (e: ParseException) {
e.printStackTrace()
}
return days.toInt()
}
}

View File

@ -1,188 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.TrafficStats;
import java.util.Calendar;
import java.util.List;
public class TrafficUtils {
static TrafficUtils instance;
DB db;
Context context;
private TrafficUtils(Context context) {
this.context = context.getApplicationContext();
db = new DB(this.context);
}
public static TrafficUtils getInstance(Context context) {
return getInstance(context, false);
}
public static TrafficUtils getInstance(Context context, boolean update) {
if (instance == null) {
synchronized (TrafficUtils.class) {
if (instance == null) {
instance = new TrafficUtils(context);
}
}
}
if (update) {
instance.update();
}
return instance;
}
public void update() {
// 获取所有的安装在手机上的应用软件的信息,并且获取这些软件里面的权限信息
PackageManager pm = context.getPackageManager();// 获取系统应用包管理
// 获取每个包内的androidmanifest.xml信息它的权限等等
List<PackageInfo> pinfos = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
// 遍历每个应用包信息
for (PackageInfo info : pinfos) {
// 请求每个程序包对应的androidManifest.xml里面的权限
String[] premissions = info.requestedPermissions;
if (premissions != null && premissions.length > 0) {
// 找出需要网络服务的应用程序
for (String premission : premissions) {
if ("android.permission.INTERNET".equals(premission)) {
// 获取每个应用程序在操作系统内的进程id
int uId = info.applicationInfo.uid;
// 如果返回-1代表不支持使用该方法注意必须是2.2以上的
long rx = TrafficStats.getUidRxBytes(uId);
// 如果返回-1代表不支持使用该方法注意必须是2.2以上的
long tx = TrafficStats.getUidTxBytes(uId);
if (rx >= 0 && tx >= 0) {
db.update(info.packageName, rx + tx);
}
}
}
}
}
db.clean(Calendar.getInstance().getTimeInMillis() - 3600 * 24 * 30);
}
public long getTraffic(List<String> packageNameList) {
return this.getTraffic(packageNameList, Calendar.getInstance()
.getTimeInMillis() - 3600 * 24 * 7);
}
public long getTraffic(List<String> packageNameList, long from) {
return this.getTraffic(packageNameList, from, Calendar.getInstance()
.getTimeInMillis());
}
public long getTraffic(List<String> packageNameList, long from, long to) {
long traffic = 0;
for (String packageName : packageNameList) {
traffic += db.getTraffic(packageName, from, to);
}
return traffic;
}
public long getTraffice(String packageName) {
return db.getTraffic(packageName, Calendar.getInstance()
.getTimeInMillis() - 3600 * 24 * 7);
}
public long getTraffice(String packageName, long from) {
return db.getTraffic(packageName, from);
}
class DB extends SQLiteOpenHelper {
static final String name = "gh_traffic.db";
static final int version = 1;
String traffic = "CREATE TABLE traffic(" + "package text,"
+ "traffic integer not null," + "time integer not null" + ");";
public DB(Context context) {
super(context, name, null, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(traffic);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void update(String packageName, long traffic) {
String sql = "INSERT INTO traffic (package, traffic, time) VALUES (?, ?, ?)";
Object[] bindArgs = new Object[]{packageName, traffic,
Calendar.getInstance().getTimeInMillis()};
this.getWritableDatabase().execSQL(sql, bindArgs);
}
public void clean(long time) {
String sql = "DELETE FROM traffic WHERE time < ? ";
Object[] bindArgs = new Object[]{time};
this.getWritableDatabase().execSQL(sql, bindArgs);
}
public long getTraffic(String packageName, long from) {
return getTraffic(packageName, from, Calendar.getInstance()
.getTimeInMillis());
}
public long getTraffic(String packageName, long from, long to) {
long traffic = 0;
String sql = "SELECT * FROM traffic WHERE package = ? AND time >= ? AND time <= ? ORDER BY time DESC";
String selectionArgs[] = new String[]{packageName,
String.valueOf(from), String.valueOf(to)};
Cursor cursor = this.getReadableDatabase().rawQuery(sql,
selectionArgs);
if (cursor.getCount() > 1) {
cursor.moveToFirst();
long traffic1 = cursor
.getLong(cursor.getColumnIndex("traffic"));
// long time1 = cursor.getLong(cursor.getColumnIndex("time"));
cursor.moveToLast();
long traffic2 = cursor
.getLong(cursor.getColumnIndex("traffic"));
// long time2 = cursor.getLong(cursor.getColumnIndex("time"));
traffic = traffic1 - traffic2;
// long cha = traffic1 - traffic2;
// if(cha > 0){
// traffic = cha / (time2 - time1);
// }
} else if (cursor.getCount() == 1) {
sql = "SELECT * FROM traffic WHERE package = ? AND time < ? ORDER BY time DESC";
selectionArgs = new String[]{packageName,
String.valueOf(from)};
Cursor cursor2 = this.getReadableDatabase().rawQuery(sql,
selectionArgs);
if (cursor2.moveToNext()) {
cursor.moveToFirst();
long traffic1 = cursor.getLong(cursor
.getColumnIndex("traffic"));
// long time1 =
// cursor.getLong(cursor.getColumnIndex("time"));
long traffic2 = cursor2.getLong(cursor
.getColumnIndex("traffic"));
// long time2 =
// cursor2.getLong(cursor.getColumnIndex("time"));
traffic = traffic1 - traffic2;
// long cha = traffic1 - traffic2;
// if(cha > 0){
// traffic = cha / (time2 - time1);
// }
}
cursor2.close();
}
cursor.close();
return traffic;
}
}
}

View File

@ -68,7 +68,6 @@ class AdBannerView : LinearLayout {
val params = LayoutParams(LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(5F))
params.topMargin = DisplayUtils.dip2px(8f)
layoutParams = params
visibility = View.GONE
}
addView(mIndicatorLayout)
}
@ -191,13 +190,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.addLimitWidthAndLoad(view, ad.image, bannerWidth, object : ImageUtils.OnImageloadListener {
override fun onLoadFinal(imageInfo: ImageInfo?) {
if (mIndicatorLayout.visibility == View.GONE) {
mIndicatorLayout.visibility = View.VISIBLE
}
}
})
ImageUtils.display(view, ad.image)
holder.itemView.setOnClickListener {
onItemClick?.invoke(position % mDatas.size)
}

View File

@ -14,26 +14,26 @@ public class CenterImageSpan extends ImageSpan {
public CenterImageSpan(Context context, int resourceId) {
super(context, resourceId);
}
public CenterImageSpan(Drawable drawable) {
super( drawable);
super(drawable);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end,
Paint.FontMetricsInt fm) {
Drawable d = getDrawable();
Rect rect = d.getBounds();
if (fm != null) {
Paint.FontMetricsInt fontMetricsInt) {
Drawable drawable = getDrawable();
Rect rect = drawable.getBounds();
if (fontMetricsInt != null) {
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.bottom - fmPaint.top;
int fontHeight = fmPaint.descent - fmPaint.ascent;
int drHeight = rect.bottom - rect.top;
int centerY = fmPaint.ascent + fontHeight / 2;
int top = drHeight / 2 - fontHeight / 4;
int bottom = drHeight / 2 + fontHeight / 4;
fm.ascent = -bottom;
fm.top = -bottom;
fm.bottom = top;
fm.descent = top;
fontMetricsInt.ascent = centerY - drHeight / 2;
fontMetricsInt.top = fontMetricsInt.ascent;
fontMetricsInt.bottom = centerY + drHeight / 2 + 1; // fuck 这里不加 1px 会导致图片底部被截掉 1px
fontMetricsInt.descent = fontMetricsInt.bottom;
}
return rect.right;
}
@ -41,14 +41,14 @@ public class CenterImageSpan extends ImageSpan {
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end,
float x, int top, int y, int bottom, Paint paint) {
Drawable b = getDrawable();
Drawable drawable = getDrawable();
canvas.save();
int transY;
transY = ((bottom - top) - b.getBounds().bottom) / 2 + top;
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent - fmPaint.ascent;
int centerY = y + fmPaint.descent - fontHeight / 2;
int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
canvas.translate(x, transY);
if (b.isVisible()) {
b.draw(canvas);
}
drawable.draw(canvas);
canvas.restore();
}

View File

@ -0,0 +1,34 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Rect
import android.view.View
import android.widget.LinearLayout
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
class CustomDividerItemDecoration(
context: Context,
var onlyDecorateTheFirstItem: Boolean = false,
var notDecorateTheFirstItem: Boolean = false,
var notDecorateTheLastItem: Boolean = false,
var notDecorateTheFirstTwoItems: Boolean = false) : DividerItemDecoration(context, LinearLayout.VERTICAL) {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
if (onlyDecorateTheFirstItem) {
if (parent.getChildAdapterPosition(view) == 0) outRect[0, 0, 0] = drawable!!.intrinsicHeight
} else {
if (parent.getChildAdapterPosition(view) == 0
&& (notDecorateTheFirstItem || notDecorateTheFirstTwoItems)) {
outRect.set(0, 0, 0, 0)
} else if (parent.getChildAdapterPosition(view) == 1 && notDecorateTheFirstTwoItems) {
outRect.set(0, 0, 0, 0)
} else if (parent.getChildAdapterPosition(view) == parent.adapter!!.itemCount - 1 && notDecorateTheLastItem) {
outRect.set(0, 0, 0, 0)
} else {
outRect[0, 0, 0] = drawable!!.intrinsicHeight
}
}
}
}

View File

@ -1,25 +1,63 @@
package com.gh.common.view;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.TextView;
public class CustomLinkMovementMethod extends LinkMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
boolean b = super.onTouchEvent(widget, buffer, event);
int action = event.getAction();
boolean isTouchEventConsumed = false;
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);
if (links.length != 0) {
ClickableSpan link = links[0];
if (action == MotionEvent.ACTION_UP) {
link.onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
// 下面这行代码会造成触摸 clickbleSpan 时 RecyclerView 的 item 高度变更 : (
// 看起来像是跟文字选择相关的东西,反正我们的 clickSpan 也不让选,直接屏蔽掉了
// Selection.setSelection(buffer,
// buffer.getSpanStart(link),
// buffer.getSpanEnd(link));
}
isTouchEventConsumed = true;
} else {
Selection.removeSelection(buffer);
}
}
//解决点击事件冲突问题
if (!b && event.getAction() == MotionEvent.ACTION_UP) {
if (!isTouchEventConsumed && event.getAction() == MotionEvent.ACTION_UP) {
ViewParent parent = iterateViewParentForClicking(widget.getParent());//处理widget的父控件点击事件
if (parent != null && parent instanceof ViewGroup) {
if (parent instanceof ViewGroup) {
return ((ViewGroup) parent).performClick();
}
}
return b;
return false;
}
@ -33,14 +71,13 @@ public class CustomLinkMovementMethod extends LinkMovementMethod {
}
return null;
}
public static CustomLinkMovementMethod getInstance() {
if (sInstance == null) sInstance = new CustomLinkMovementMethod();
return sInstance;
}
private static CustomLinkMovementMethod sInstance;
}

View File

@ -1,662 +0,0 @@
package com.gh.common.view;
import android.app.Dialog;
import android.content.Context;
import androidx.databinding.DataBindingUtil;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.util.ClickUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.SPUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.OnCollectionCallBackListener;
import com.gh.gamecenter.adapter.PlatformPagerAdapter;
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.ApkLink;
import com.gh.gamecenter.entity.GameCollectionEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DataWatcher;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author 温冠超
* @email 294299195@qq.com
* @date 2015-8-12
* @update 2015-8-12
* @des 弹出游戏版本下载按钮,点击并添加到下载任务中
*/
public class DownloadDialog implements OnCollectionCallBackListener {
private Context mContext;
private PopupWindow popupWindow;
private ViewPager viewPager;
private ViewPager collectionViewPager;
private LinearLayout dialog_ll_collection_hint;
private LinearLayout dialog_ll_hint;
private LinearLayout dialog_ll_collection;
private View mDialogMorePlatformHint;
private List<ApkEntity> gameApk;
private GameEntity gameEntity;
private PlatformPagerAdapter adapter;
private PlatformPagerAdapter collectionAdapter;
private ExposureEvent traceEvent;
private static final String DOWNLOAD_PLATFORM_HINT = "download_platform_hint";
private String entrance;
private String location;
private String mAutoDownloadPlatform;
private final int row = 3;
private final int column = 3;
private boolean isLoadPlatform;
private DataWatcher dataWatcher = new DataWatcher() {
@Override
public void onDataChanged(DownloadEntity downloadEntity) {
if (downloadEntity.getName().equals(gameEntity.getName())
&& !DownloadStatus.delete.equals(DownloadManager.getInstance(mContext).getStatus(downloadEntity.getUrl()))) {
adapter.putDownloadEntity(downloadEntity);
if (collectionAdapter != null) {
collectionAdapter.putDownloadEntity(downloadEntity);
}
}
}
};
private DownloadDialog(Context context) {
mContext = context;
}
public static DownloadDialog getInstance(Context context) {
return new DownloadDialog(context);
}
// 自动下载并翻到相应页面
public void showPopupWindowAutoDownload(View view, GameEntity gameEntity, String autoDownloadPlatform,
String entrance, String location, ExposureEvent traceEvent) {
mAutoDownloadPlatform = autoDownloadPlatform;
showPopupWindow(view, gameEntity, entrance, location, traceEvent);
}
public void showPopupWindow(View view, GameEntity gameEntity, String entrance, String location) {
showPopupWindow(view, gameEntity, entrance, location, null);
}
public void showPopupWindow(View view, GameEntity gameEntity, String entrance, String location,
@Nullable ExposureEvent traceEvent) {
if (ClickUtils.isFastDoubleClick()) {
return;
}
this.gameEntity = gameEntity;
this.entrance = entrance;
this.location = location;
this.traceEvent = traceEvent;
gameApk = gameEntity.getApk();
if (gameEntity.getCollection() != null) {
mergeApkCollection(gameEntity);
}
if (gameEntity.getApkLink() != null) {
mergeApkLink(gameEntity);
}
sortApk();
// 一个自定义的布局,作为显示的内容
View contentView = View.inflate(mContext, R.layout.game_download_dialog, null);
TextView title = contentView.findViewById(R.id.dialog_title);
title.setText(gameEntity.getName());
viewPager = contentView.findViewById(R.id.dialog_viewPager);
dialog_ll_hint = contentView.findViewById(R.id.dialog_ll_hint);
dialog_ll_collection = contentView.findViewById(R.id.dialog_ll_collection);
dialog_ll_collection_hint = contentView.findViewById(R.id.dialog_ll_collection_hint);
collectionViewPager = contentView.findViewById(R.id.dialog_collection_viewPager);
mDialogMorePlatformHint = contentView.findViewById(R.id.dialog_more_platform_hit);
TextView dialogAd = contentView.findViewById(R.id.dialog_ad);
TextView dialogAdMirror = contentView.findViewById(R.id.dialog_ad_mirror);
mDialogMorePlatformHint.setOnClickListener(v -> {
mDialogMorePlatformHint.setVisibility(View.GONE);
SPUtils.setBoolean(DOWNLOAD_PLATFORM_HINT, false);
});
LinkEntity downloadAd = gameEntity.getDownloadAd();
if (downloadAd != null) {
dialogAd.setVisibility(View.VISIBLE);
dialogAd.setText(downloadAd.getTitle());
dialogAdMirror.setVisibility(View.INVISIBLE);
dialogAdMirror.setText(downloadAd.getTitle());
dialogAd.setOnClickListener(v -> {
if ("imprint".equals(downloadAd.getType())) {
showImprintDialog(downloadAd.getTitle());
} else {
DirectUtils.directToLinkPage(
mContext,
downloadAd,
entrance, "下载多平台弹窗");
}
});
}
isLoadPlatform = false;
init(new ArrayList<>(gameApk));
viewPager.addOnPageChangeListener(new MyPageChangeListener(dialog_ll_hint));
popupWindow = new PopupWindow(contentView, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, true);
contentView.setOnClickListener(v -> popupWindow.dismiss());
contentView.setFocusable(true);
contentView.setFocusableInTouchMode(true);
contentView.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0
&& popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
}
return false;
});
popupWindow.setOnDismissListener(() -> {
EventBus.getDefault().unregister(DownloadDialog.this);
DownloadManager.getInstance(mContext).removeObserver(dataWatcher);
});
popupWindow.setTouchable(true);
popupWindow.setFocusable(true);
// 设置popWindow的显示和消失动画
popupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);
// 设置好参数之后再show
popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
if (!EventBus.getDefault().isRegistered(DownloadDialog.this)) {
EventBus.getDefault().register(DownloadDialog.this);
}
DownloadManager.getInstance(mContext).addObserver(dataWatcher);
}
private void showImprintDialog(String titleName) {
Dialog dialog = new Dialog(mContext, R.style.full_dialog);
View inflate = LayoutInflater.from(mContext).inflate(R.layout.imprint_dialog, null);
dialog.setContentView(inflate);
dialog.show();
Window window = dialog.getWindow();
WindowManager.LayoutParams params;
if (window != null) {
params = window.getAttributes();
params.width = (int) (mContext.getResources().getDisplayMetrics().widthPixels * 0.9);
window.setAttributes(params);
window.setBackgroundDrawableResource(R.drawable.full_dialog_background);
}
inflate.findViewById(R.id.imprint_close).setOnClickListener(v -> dialog.dismiss());
LinearLayout content = inflate.findViewById(R.id.imprint_content);
((TextView) inflate.findViewById(R.id.imprint_title)).setText(titleName);
View head = LayoutInflater.from(mContext).inflate(R.layout.imprint_content_item, null);
content.addView(head, LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(30));
LimitHeightLinearLayout imprintContainer = inflate.findViewById(R.id.imprint_container);
imprintContainer.setLimitHeight((int) (mContext.getResources().getDisplayMetrics().heightPixels * 0.8));
ArrayList<ApkEntity> list = gameEntity.getApk();
SettingsEntity settings = Config.getSettings();
for (int i = 0; i < list.size(); i++) {
ApkEntity apk = gameEntity.getApk().get(i);
if (settings != null && settings.getGameDownloadBlackList().contains(apk.getPackageName())) {
continue;
}
View item = LayoutInflater.from(mContext).inflate(R.layout.imprint_content_item, null);
ImprintContentItemBinding bind = DataBindingUtil.bind(item);
bind.setApk(apk);
bind.setPlatformName(PlatformUtils.getInstance(mContext).getPlatformName(apk.getPlatform()));
content.addView(item, LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(40));
}
// close line
View view = new View(mContext);
view.setBackgroundColor(mContext.getResources().getColor(R.color.text_5d5d5d));
view.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(1)));
content.addView(view);
}
private void sortApk() {
for (ApkEntity apkEntity : gameApk) {
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (apkCollection != null) {
List<ApkEntity> saveApkEntity = apkCollection.getSaveApkEntity();
if (saveApkEntity != null) {
for (ApkEntity entity : saveApkEntity) {
int sortValue = getSortValue(entity);
if (apkEntity.getOrder() < sortValue) {
apkEntity.setOrder(sortValue);
}
}
}
continue;
}
apkEntity.setOrder(getSortValue(apkEntity));
}
Comparator<ApkEntity> comparator = (lhs, rhs) -> rhs.getOrder() - lhs.getOrder();
Collections.sort(gameApk, comparator);
}
private int getSortValue(ApkEntity apkEntity) {
/*
* 安装插件 10
* 插件化下载中 9
* 插件化 8
* 安装更新 7
* 更新下载中 6
* 更新 5
* 安装 4
* 下载中 3
* 启动 2
* 默认有图片1
* 默认无图片0
*/
Object gh_id;
String packageName = apkEntity.getPackageName();
DownloadEntity downloadEntity = DownloadManager.getInstance(mContext).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity == null) {
if (!TextUtils.isEmpty(packageName) && PackagesManager.INSTANCE.isInstalled(packageName)) {
gh_id = PackageUtils.getMetaData(mContext, packageName, "gh_id");
if (gh_id == null || gh_id.equals(gameEntity.getId())) {
if (!PackageUtils.isSignature(mContext, packageName)) {
return 8;
} else if (PackagesManager.INSTANCE.isCanUpdate(gameEntity.getId(), packageName)) {
return 5;
} else {
return 2;
}
}
}
if (apkEntity.getOrder() < 1) apkEntity.setOrder(1);
String platform = apkEntity.getPlatform();
int id = PlatformUtils.getInstance(mContext).getPlatformPic(platform);
if (id == 0) {
String path = PlatformUtils.getInstance(mContext).getPlatformPicUrl(platform);
if (path == null) {
return 0;
}
}
} else {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
if (downloadEntity.isPluggable()) {
return 10;
} else if (downloadEntity.isUpdate()) {
return 7;
} else {
return 4;
}
} else {
if (downloadEntity.isPluggable()) {
return 9;
} else if (downloadEntity.isUpdate()) {
return 6;
} else {
return 3;
}
}
}
return 0;
}
// 合并ApkLink
private void mergeApkLink(GameEntity gameEntity) {
for (ApkLink apkLink : gameEntity.getApkLink()) {
if (!TextUtils.isEmpty(apkLink.getCollection())) {
for (int i = 0; i < gameApk.size(); i++) {
ApkEntity apkEntity = gameApk.get(i);
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (apkCollection != null && apkCollection.getSaveApkEntity() != null) {
List<ApkEntity> saveApkEntity = apkCollection.getSaveApkEntity();
if (apkLink.getCollection().equals(apkCollection.getId())) {
ApkEntity element = new ApkEntity();
element.setApkLink(apkLink);
if (saveApkEntity.size() > apkLink.getSort()) {
saveApkEntity.add(apkLink.getSort(), element);
} else {
saveApkEntity.add(element);
}
}
}
}
} else {
ApkEntity element = new ApkEntity();
element.setApkLink(apkLink);
if (gameApk.size() > apkLink.getSort()) {
gameApk.add(apkLink.getSort(), element);
} else {
gameApk.add(element);
}
}
}
}
// 合并ApkCollection
private void mergeApkCollection(GameEntity gameEntity) {
List<ApkEntity> gameCollectionApk = new ArrayList<>();
ConcurrentHashMap<String, Integer> hashMap = new ConcurrentHashMap<>();
boolean isCollection;
for (ApkEntity apkEntity : gameApk) {
isCollection = false;
for (GameCollectionEntity gameCollectionEntity : gameEntity.getCollection()) {
for (String packageName : gameCollectionEntity.getPackage()) {
if (packageName.equals(apkEntity.getPackageName())) {
isCollection = true;
if (hashMap.get(gameCollectionEntity.getName()) != null) {
gameCollectionApk.get(hashMap.get(gameCollectionEntity.getName()))
.getApkCollection().getSaveApkEntity().add(apkEntity);
} else {
ApkEntity newApkEntity = new ApkEntity();
GameCollectionEntity collectionEntity = new GameCollectionEntity();
List<ApkEntity> saveApkList = new ArrayList<>();
saveApkList.add(apkEntity);
collectionEntity.setSaveApkEntity(saveApkList);
collectionEntity.setId(gameCollectionEntity.getId());
collectionEntity.setName(gameCollectionEntity.getName());
collectionEntity.setIcon(gameCollectionEntity.getIcon());
collectionEntity.setColor(gameCollectionEntity.getColor());
newApkEntity.setApkCollection(collectionEntity);
gameCollectionApk.add(newApkEntity);
hashMap.put(gameCollectionEntity.getName(), gameCollectionApk.size() - 1);
}
}
}
}
if (!isCollection) {
gameCollectionApk.add(apkEntity);
}
}
gameApk = gameCollectionApk;
}
private void init(List<ApkEntity> apkList) {
for (int i = 0; i < apkList.size(); i++) {
String platformName = PlatformUtils.getInstance(mContext)
.getPlatformName(apkList.get(i).getPlatform());
if (platformName == null) {
apkList.remove(i);
i--;
if (!isLoadPlatform) {
PlatformUtils.getInstance(mContext).getPlatform();
isLoadPlatform = true;
}
}
}
ApkEntity skipEntiy = new ApkEntity();
skipEntiy.setPackageName("求版本");
apkList.add(skipEntiy); // 添加一个跳转投票
dialog_ll_hint.removeAllViews();
int size = (int) Math.ceil(apkList.size() / (double) (row * column));
addHintPoint(dialog_ll_hint, size);
if (size >= 2) {
boolean isShowPlatformHint = SPUtils.getBoolean(DOWNLOAD_PLATFORM_HINT, true);
if (isShowPlatformHint) {
mDialogMorePlatformHint.setVisibility(View.VISIBLE);
}
}
int count = apkList.size();
int vpHeight;
if (count <= 3) {
vpHeight = 90;
} else if (count <= 6) {
vpHeight = 150;
} else {
vpHeight = 210;
}
ViewGroup.LayoutParams layoutParams = viewPager.getLayoutParams();
layoutParams.height = DisplayUtils.dip2px(mContext, vpHeight);
viewPager.setLayoutParams(layoutParams);
int currentItem = 0;
if (viewPager != null) {
currentItem = viewPager.getCurrentItem();
}
if (!TextUtils.isEmpty(mAutoDownloadPlatform)) {
for (int i = 0; i < apkList.size(); i++) {
ApkEntity apkEntity = apkList.get(i);
if (mAutoDownloadPlatform.equals(apkEntity.getPlatform())) {
currentItem = (i / 9);
break;
}
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (apkCollection != null) {
List<ApkEntity> saveApkEntity = apkCollection.getSaveApkEntity();
if (saveApkEntity != null) {
for (ApkEntity entity : saveApkEntity) {
if (mAutoDownloadPlatform.equals(entity.getPlatform())) {
currentItem = (i / 9);
break;
}
}
}
}
}
}
Utils.log("currentItem = " + currentItem);
adapter = new PlatformPagerAdapter(mContext, this,
gameEntity, apkList, mAutoDownloadPlatform, entrance, location, traceEvent);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(currentItem);
if (currentItem != 0) setDownloadOvalHint(dialog_ll_hint, currentItem);
}
private void addHintPoint(LinearLayout linearLayout, int size) {
if (size <= 1) {
return;
}
for (int i = 0; i < size; i++) {
ImageView imageView = new ImageView(mContext);
LayoutParams lparams = new LayoutParams(
DisplayUtils.dip2px(mContext, 6), DisplayUtils.dip2px(mContext, 6));
if (i == 0) {
lparams.leftMargin = 0;
imageView.setImageResource(R.drawable.download_oval_hint_up);
} else {
lparams.leftMargin = DisplayUtils.dip2px(mContext, 9);
imageView.setImageResource(R.drawable.oval_hint_gray_bg);
}
imageView.setLayoutParams(lparams);
linearLayout.addView(imageView);
}
}
// 接收安装成功的消息,更新界面
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(EBPackage busFour) {
if ("安装".equals(busFour.getType())) {
adapter.removeDownloadEntityByPackageName(busFour.getPackageName());
if (collectionAdapter != null) {
collectionAdapter.removeDownloadEntityByPackageName(busFour.getPackageName());
}
} else if ("卸载".equals(busFour.getType())) {
adapter.updateItem(busFour.getPackageName());
if (collectionAdapter != null) {
collectionAdapter.updateItem(busFour.getPackageName());
}
}
}
//接收下载被删除消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(EBDownloadStatus status) {
if ("delete".equals(status.getStatus())) {
String url = status.getUrl();
adapter.removeDownloadEntityByUrl(url);
if (collectionAdapter != null) {
collectionAdapter.removeDownloadEntityByUrl(url);
}
// DownloadManager.getInstance(mContext).putStatus(url, "delete");
}
}
// 接收platform数据改变消息更新界面
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(EBReuse reuse) {
if ("PlatformChanged".equals(reuse.getType())) {
DownloadManager.getInstance(mContext).removeObserver(dataWatcher);
init(new ArrayList<>(gameApk));
DownloadManager.getInstance(mContext).addObserver(dataWatcher);
}
}
// 显示合集
@Override
public void showCollection(GameCollectionEntity gameCollectionEntity) {
dialog_ll_collection.setVisibility(View.VISIBLE);
List<ApkEntity> saveApkList = gameCollectionEntity.getSaveApkEntity();
int count = saveApkList.size();
int vpHeight;
if (count <= 3) {
vpHeight = 82;
} else if (count <= 6) {
vpHeight = 142;
} else {
vpHeight = 202;
}
ViewGroup.LayoutParams layoutParams = collectionViewPager.getLayoutParams();
layoutParams.height = DisplayUtils.dip2px(mContext, vpHeight);
collectionViewPager.setLayoutParams(layoutParams);
dialog_ll_collection_hint.removeAllViews();
int size = (int) Math.ceil(count / (double) (row * column));
addHintPoint(dialog_ll_collection_hint, size);
collectionAdapter = new PlatformPagerAdapter(
mContext, null, gameEntity, saveApkList,
mAutoDownloadPlatform, entrance, location, traceEvent);
collectionViewPager.setAdapter(collectionAdapter);
collectionViewPager.addOnPageChangeListener(new MyPageChangeListener(dialog_ll_collection_hint));
int currentItem = 0;
if (!TextUtils.isEmpty(mAutoDownloadPlatform)) {
for (int i = 0; i < saveApkList.size(); i++) {
ApkEntity apkEntity = saveApkList.get(i);
if (mAutoDownloadPlatform.equals(apkEntity.getPlatform())) {
currentItem = (i / 9);
break;
}
}
}
if (currentItem != 0) {
collectionViewPager.setCurrentItem(currentItem);
setDownloadOvalHint(dialog_ll_collection_hint, currentItem);
}
mAutoDownloadPlatform = null;
}
// 隐藏合集
@Override
public void hideCollection() {
dialog_ll_collection.setVisibility(View.GONE);
collectionAdapter = null;
}
private class MyPageChangeListener implements OnPageChangeListener {
private LinearLayout linearLayout;
public MyPageChangeListener(LinearLayout linearLayout) {
this.linearLayout = linearLayout;
}
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int position) {
setDownloadOvalHint(linearLayout, position);
}
@Override
public void onPageScrollStateChanged(int i) {
}
}
private void setDownloadOvalHint(LinearLayout linearLayout, int position) {
for (int i = 0, size = linearLayout.getChildCount(); i < size; i++) {
if (i == position % size) {
((ImageView) linearLayout.getChildAt(i))
.setImageResource(R.drawable.download_oval_hint_up);
} else {
((ImageView) linearLayout.getChildAt(i))
.setImageResource(R.drawable.oval_hint_gray_bg);
}
}
}
}

View File

@ -24,9 +24,7 @@ import androidx.core.content.ContextCompat;
public class DownloadProgressBar extends ProgressBar {
public static final int MAX_LENGTH = 1000;
public static final int DOWNLOAD_NORMAL_STYLE = 0;
public static final int DOWNLOAD_RECT_STYLE = 1;
public static final int DOWNLOAD_IMAGE_STYLE = 2;
public static final int DOWNLOAD_SLIDE_STYLE = 3;
public enum DownloadType {
NORMAL,
@ -115,8 +113,6 @@ public class DownloadProgressBar extends ProgressBar {
int color = Color.WHITE;
if (DOWNLOAD_IMAGE_STYLE == mDownloadStyle) {
color = Color.BLACK;
} else if (DOWNLOAD_SLIDE_STYLE == mDownloadStyle) {
color = getResources().getColor(R.color.theme_font);
}
mPaint.setColor(color); // 反向颜色
}
@ -167,73 +163,48 @@ public class DownloadProgressBar extends ProgressBar {
case NONE_WITH_HINT:
case INSTALL_NORMAL:
case H5_GAME:
switch (mDownloadStyle) {
case DOWNLOAD_RECT_STYLE:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_normal_rect_style));
mDefaultColor = Color.WHITE;
break;
case DOWNLOAD_IMAGE_STYLE:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_normal_image_style));
mDefaultColor = Color.BLACK;
break;
default:
setProgressDrawable(getResources().getDrawable(R.drawable.game_item_btn_download_style));
mDefaultColor = Color.WHITE;
break;
if (mDownloadStyle == DOWNLOAD_IMAGE_STYLE) {
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_normal_image_style));
mDefaultColor = Color.BLACK;
} else {
setProgressDrawable(getResources().getDrawable(R.drawable.download_button_normal_style));
mDefaultColor = Color.WHITE;
}
setProgress(0);
break;
case PLUGIN:
case INSTALL_PLUGIN:
setProgressDrawable(getResources().getDrawable(mDownloadStyle == DOWNLOAD_RECT_STYLE
? R.drawable.detail_download_plugin_install_rect_style : R.drawable.game_item_btn_plugin_style));
setProgressDrawable(getResources().getDrawable(R.drawable.download_button_pluggable_style));
mDefaultColor = Color.WHITE;
setProgress(0);
break;
case NONE:
setProgressDrawable(getResources().getDrawable(mDownloadStyle == DOWNLOAD_RECT_STYLE
? R.drawable.detail_download_none_rect_style : R.drawable.news_detail_comment));
setProgressDrawable(getResources().getDrawable(R.drawable.news_detail_comment));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.hint);
setProgress(0);
break;
case LAUNCH_OR_OPEN:
switch (mDownloadStyle) {
case DOWNLOAD_RECT_STYLE:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_rect_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
break;
case DOWNLOAD_IMAGE_STYLE:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_image_style));
mDefaultColor = Color.WHITE;
break;
default:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
break;
if (mDownloadStyle == DOWNLOAD_IMAGE_STYLE) {
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_image_style));
mDefaultColor = Color.WHITE;
} else {
setProgressDrawable(getResources().getDrawable(R.drawable.download_button_normal_style));
mDefaultColor = Color.WHITE;
}
setProgress(0);
break;
case DOWNLOADING_NORMAL:
switch (mDownloadStyle) {
case DOWNLOAD_RECT_STYLE:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_rect_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
break;
case DOWNLOAD_IMAGE_STYLE:
case DOWNLOAD_SLIDE_STYLE:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_image_style));
mDefaultColor = Color.WHITE;
break;
default:
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
break;
if (mDownloadStyle == DOWNLOAD_IMAGE_STYLE) {
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_image_style));
mDefaultColor = Color.WHITE;
} else {
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
}
break;
case DOWNLOADING_PLUGIN:
setProgressDrawable(getResources().getDrawable(mDownloadStyle == DOWNLOAD_RECT_STYLE
? R.drawable.detail_downloading_plugin_rect_style : R.drawable.detail_downloading_plugin_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.btn_plugin);
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_plugin_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.text_00B8B8);
break;
case RESERVABLE:
setProgressDrawable(getResources().getDrawable(R.drawable.button_reserve));

View File

@ -97,6 +97,13 @@ object DrawableView {
return drawable
}
@JvmStatic
fun getCornerGradientDrawable(startColor: Int, endColor: Int, radius: Float = 999F): Drawable {
val drawable = GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, intArrayOf(startColor, endColor))
drawable.cornerRadius = DisplayUtils.dip2px(radius).toFloat()
return drawable
}
fun convertAlphaKey(percent: Int): String {
val hexString = Integer.toHexString(Math.round((255 * percent / 100).toFloat()))
return (if (hexString.length < 2) "0" else "") + hexString

View File

@ -1,33 +1,36 @@
package com.gh.common.view;
import android.content.Context;
import android.graphics.Color;
import android.content.res.TypedArray;
import android.os.Build;
import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import com.gh.common.util.DisplayUtils;
import com.gh.gamecenter.R;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
public class ExpandTextView extends AppCompatTextView {
private CharSequence mSnapshotText;
private String mExpendText = "...全文";
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 mOpenLayout = false;
private boolean mIsExpanded = false; // 位于 recyclerView 时需要自行在外层管理是否已展开
private ExpandCallback mExpandCallback;
@ -40,20 +43,25 @@ public class ExpandTextView extends AppCompatTextView {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mMaxLines = getMaxLines();
}
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);
ta.recycle();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mInitLayout && !mOpenLayout && getLineCount() > mMaxLines) {
if (mInitLayout && !mIsExpanded && getLineCount() > mMaxLines) {
mSnapshotText = getText();
mInitLayout = false;
showExpendButton();
showExpandButton();
}
}
public void setExpendText(String text) {
this.mExpendText = text;
this.mExpandText = text;
}
public void setExpandCallback(ExpandCallback callback) {
@ -66,7 +74,9 @@ public class ExpandTextView extends AppCompatTextView {
super.setText(text, type);
}
private void showExpendButton() {
private void showExpandButton() {
String finalEndText = "";
Layout layout = getLayout();
int start = layout.getLineStart(0);
int lastLineEnd = layout.getLineEnd(mMaxLines - 1);
@ -74,28 +84,59 @@ public class ExpandTextView extends AppCompatTextView {
float lastLineRight = layout.getLineRight(mMaxLines - 1);
int viewWidth = getWidth() - getPaddingRight() - getPaddingLeft();
int additionalEndTextCount = 0;
TextPaint paint = getPaint();
float expendTextWidth = paint.measureText(mExpendText);
float expandTextWidth;
if (mUseGradientAlphaEndText) {
additionalEndTextCount = DEFAULT_ADDITIONAL_END_TEXT_COUNT;
// 如果不加多个括号的话有可能算不对,惊了,明明是同样的 paint 同样的文字,长度却会略有不同
expandTextWidth = paint.measureText(mEndText + mExpandText + " ");
} else {
expandTextWidth = paint.measureText(mExpandText);
}
CharSequence content = mSnapshotText.subSequence(start, lastLineEnd);
if (viewWidth - lastLineRight > expendTextWidth) {
content = content.toString().trim() + mExpendText;
if (viewWidth - lastLineRight > expandTextWidth) {
if (mUseGradientAlphaEndText) {
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) > expendTextWidth) {
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpendText;
if (viewWidth - w - DisplayUtils.dip2px(5) > expandTextWidth) {
if (mUseGradientAlphaEndText) {
finalEndText = lastText.subSequence(i - additionalEndTextCount, i) + mEndText;
finalEndText = finalEndText.replace("\n", "");
content = mSnapshotText.subSequence(start, lastLineStart + i - additionalEndTextCount) + finalEndText + mExpandText;
} else {
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
}
break;
}
}
}
SpannableStringBuilder msp = new SpannableStringBuilder(mSnapshotText);
int length = msp.length();
int startPosition = content.length() - mExpendText.length();
startPosition = startPosition < 0 ? 0 : startPosition;
msp.replace(startPosition, length, mExpendText);
int startPosition = 0;
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) {
@ -106,7 +147,7 @@ public class ExpandTextView extends AppCompatTextView {
@Override
public void onClick(View widget) {
mOpenLayout = true;
mIsExpanded = true;
setMaxLines(Integer.MAX_VALUE);
setText(mSnapshotText);
@ -114,15 +155,21 @@ public class ExpandTextView extends AppCompatTextView {
mExpandCallback.onExpand();
}
}
}, startPosition + 3, msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
msp.setSpan(new BackgroundColorSpan(Color.WHITE), startPosition, msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}, 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());
}
/**
* 此方法仅更改标记,不做实际展开的操作
*/
public void setIsExpanded(boolean isExpanded) {
mIsExpanded = isExpanded;
}
public void setExpendMaxLines(int maxLines) {
public void setExpandMaxLines(int maxLines) {
mMaxLines = maxLines;
setMaxLines(maxLines);
}

View File

@ -0,0 +1,124 @@
package com.gh.common.view
import android.content.Context
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.gh.common.util.DisplayUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.TagStyleEntity
import kotlin.math.ceil
/**
* 标签最多显示一行,显示的个数由行宽决定
*/
class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {
private var mTotalCount = 0
private var mTags = ArrayList<TagStyleEntity>()
private var mItemHeight = DisplayUtils.dip2px(20F)
private var mPadding = DisplayUtils.dip2px(5F)
private var mMargin = DisplayUtils.dip2px(4F)
private var mTextSize = 10F
private var mLastItemWidth = DisplayUtils.dip2px(18F)//最后更多按钮宽度
private var mTotalWidth = 0
var onClickListener: OnItemClickListener? = null
init {
gravity = Gravity.CENTER_VERTICAL
}
fun setTags(tags: ArrayList<TagStyleEntity>) {
mTags.clear()
mTotalCount = tags.size
mTotalWidth = measuredWidth
val paint = Paint()
paint.textSize = DisplayUtils.sp2px(context, mTextSize).toFloat()
var currentWidth = mLastItemWidth.toFloat()
tags.forEach {
val strWidth = getTextWidth(paint, it.name)
if (currentWidth + strWidth + mPadding * 2 + mMargin <= mTotalWidth) {
currentWidth += strWidth + mPadding * 2 + mMargin
mTags.add(it)
}
}
if (mTags.isNotEmpty()) {
addTags()
}
}
private fun getTextWidth(paint: Paint, str: String?): Int {
var width = 0
if (str != null && str.isNotEmpty()) {
val len = str.length
val widths = FloatArray(len)
paint.getTextWidths(str, widths)
for (i in 0 until len) {
width += ceil(widths[i].toDouble()).toInt()
}
}
return width
}
private fun addTags() {
removeAllViews()
mTags.forEach {
addView(createView(it))
}
if (mTotalCount != mTags.size) {
val imageView = ImageView(context).apply {
val params = LayoutParams(mLastItemWidth, mItemHeight)
layoutParams = params
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_game_detail_label_more))
background = createBackgroundDrawable()
scaleType=ImageView.ScaleType.CENTER
}
imageView.setOnClickListener {
onClickListener?.onMoreClickListener()
}
addView(imageView)
}
}
private fun createView(tag: TagStyleEntity): View {
return TextView(context).apply {
text = tag.name
includeFontPadding = false
textSize = mTextSize
gravity = Gravity.CENTER
setTextColor(Color.parseColor("#333333"))
val params = LayoutParams(LayoutParams.WRAP_CONTENT, mItemHeight)
params.setMargins(0, 0, mMargin, 0)
setPadding(mPadding, 0, mPadding, 0)
layoutParams = params
val gradientDrawable = createBackgroundDrawable()
background = gradientDrawable
setOnClickListener {
onClickListener?.onItemClickListener(tag)
}
}
}
private fun createBackgroundDrawable(): GradientDrawable {
val gradientDrawable = GradientDrawable()
gradientDrawable.setColor(Color.TRANSPARENT)
gradientDrawable.setStroke(DisplayUtils.dip2px(context, 1f), Color.parseColor("#C2C6CC"))
gradientDrawable.cornerRadius = DisplayUtils.dip2px(2f).toFloat()
return gradientDrawable
}
interface OnItemClickListener {
fun onMoreClickListener()
fun onItemClickListener(tag: TagStyleEntity)
}
}

View File

@ -0,0 +1,31 @@
package com.gh.common.view
import android.graphics.Canvas
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Shader
import android.text.style.ReplacementSpan
import androidx.core.graphics.ColorUtils
class GradientAlphaTextSpan() : ReplacementSpan() {
override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
return paint.measureText(text, start, end).toInt()
}
override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
val originalColor = paint.color
val originalColorWithAlphaChanged = ColorUtils.setAlphaComponent(paint.color, 1)
val textWidth = paint.measureText(text, start, end).toInt()
val mShader = LinearGradient(x, 0F, x + textWidth - 10, 0F,
originalColor, originalColorWithAlphaChanged, Shader.TileMode.CLAMP)
paint.shader = mShader
canvas.drawText(text, start, end, x, y.toFloat(), paint)
paint.shader = null
}
}

View File

@ -0,0 +1,68 @@
package com.gh.common.view
import android.graphics.*
import android.text.style.ReplacementSpan
import androidx.annotation.Dimension
import com.gh.common.util.DisplayUtils
import com.halo.assistant.HaloApp
class GradientRoundBackgroundColorSpan(private val startColor: String,
private val endColor: String,
private val textColor: String,
@Dimension(unit = Dimension.SP)
private val textSize: Int = 0) : ReplacementSpan() {
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
return paint.measureText(text, start, end).toInt()
}
override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
val originalColor = paint.color
val originalTextSize = paint.textSize
paint.style = Paint.Style.FILL
val fontMetrics = paint.fontMetrics
// 原文字宽度
val originalTextWidth = paint.measureText(text, start, end).toInt()
// 当目标字体大小与原字体大小不一样时,需要先用目标字体大小测量字体宽度
if (textSize != 0) {
paint.textSize = DisplayUtils.sp2px(HaloApp.getInstance().application, textSize.toFloat()).toFloat()
}
// 目标文字宽度
val textWidth = paint.measureText(text, start, end).toInt()
// 用原字体大小画椭圆
paint.textSize = originalTextSize
//添加渐变Shader
val mShader = LinearGradient(0F, top.toFloat(), x + originalTextWidth, top + fontMetrics.bottom - fontMetrics.top,
Color.parseColor(startColor), Color.parseColor(endColor), Shader.TileMode.CLAMP)
paint.shader = mShader
canvas.drawRoundRect(RectF(
x,
top.toFloat(),
x + originalTextWidth,
top + fontMetrics.bottom - fontMetrics.top),
DisplayUtils.dip2px(HaloApp.getInstance().application, 5f).toFloat(),
DisplayUtils.dip2px(HaloApp.getInstance().application, 5f).toFloat(),
paint)
//重置paint
paint.color = Color.parseColor(this.textColor)
//移除渐变Shader否则绘制的文字也是渐变色
paint.shader = null
paint.style = Paint.Style.FILL
// 用目标字体大小画字
if (textSize != 0) {
paint.textSize = DisplayUtils.sp2px(HaloApp.getInstance().application, textSize.toFloat()).toFloat()
}
val offsetX = (originalTextWidth - textWidth) / 2
canvas.drawText(text, start, end, x + offsetX, y.toFloat(), paint)
paint.color = originalColor
}
}

View File

@ -0,0 +1,44 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewConfiguration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs
class InterceptRecyclerView : RecyclerView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var startX = 0F
private var startY = 0F
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
if (ev.action == MotionEvent.ACTION_DOWN) {
startX = ev.x
startY = ev.y
} else if (ev.action == MotionEvent.ACTION_MOVE) {
val dx = ev.x - startX
val dy = ev.y - startY
val scaledTouchSlop = ViewConfiguration.get(context).scaledTouchSlop
if (layoutManager != null && layoutManager is LinearLayoutManager) {
val orientation = (layoutManager as LinearLayoutManager).orientation
if (orientation == HORIZONTAL) {
if (abs(dx) > scaledTouchSlop && abs(dx) > abs(dy)) {
parent.requestDisallowInterceptTouchEvent(true)
} else if (abs(dy) > scaledTouchSlop && abs(dy) > abs(dx)) {
parent.requestDisallowInterceptTouchEvent(false)
}
}
}
}
return super.dispatchTouchEvent(ev)
}
}

View File

@ -30,6 +30,7 @@ public class MarqueeView extends ViewFlipper {
private int animDuration = 500;
private int textSize = 14;
private int textColor = 0xffffffff;
private boolean useSingleLineText = false;
public MarqueeView(Context context, AttributeSet attrs) {
super(context, attrs);
@ -51,6 +52,7 @@ public class MarqueeView extends ViewFlipper {
textSize = DisplayUtils.px2sp(mContext, textSize);
}
textColor = typedArray.getColor(R.styleable.MarqueeViewStyle_mvTextColor, textColor);
useSingleLineText = typedArray.getBoolean(R.styleable.MarqueeViewStyle_mvSingleLine, useSingleLineText);
typedArray.recycle();
setFlipInterval(interval);
@ -114,6 +116,10 @@ public class MarqueeView extends ViewFlipper {
// 创建ViewFlipper下的TextView
private TextView createTextView(String text) {
TextView tv = new TextView(mContext);
if (useSingleLineText) {
tv.setSingleLine(true);
tv.setEllipsize(TextUtils.TruncateAt.END);
}
tv.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
tv.setText(text);
tv.setTextColor(textColor);
@ -127,6 +133,10 @@ public class MarqueeView extends ViewFlipper {
start();
}
public void enableSingleLineText() {
useSingleLineText = true;
}
public List<String> getNotices() {
return notices;
}

View File

@ -4,9 +4,19 @@ import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.RelativeLayout
import com.gh.gamecenter.R
class MaterializedRelativeLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: RelativeLayout(context, attrs) {
class MaterializedRelativeLayout : RelativeLayout {
private var mConsumeWindowInset: Boolean = false
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
val ta = context.obtainStyledAttributes(attrs, R.styleable.MaterializedRelativeLayout)
mConsumeWindowInset = ta.getBoolean(R.styleable.MaterializedRelativeLayout_consumeWindowInsets, false)
ta.recycle()
}
/**
* 将 windowInsets 传递给子 view [https://medium.com/androiddevelopers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec#.raoa9t506]
@ -16,9 +26,16 @@ class MaterializedRelativeLayout @JvmOverloads constructor(context: Context, att
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setOnApplyWindowInsetsListener { _, insets ->
val childCount = childCount
for (index in 0 until childCount) {
getChildAt(index).dispatchApplyWindowInsets(insets)
if (mConsumeWindowInset) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
insets.replaceSystemWindowInsets(insets.systemWindowInsetLeft, 0, insets.systemWindowInsetRight, insets.systemWindowInsetBottom)
insets.consumeSystemWindowInsets()
}
} else {
val childCount = childCount
for (index in 0 until childCount) {
getChildAt(index).dispatchApplyWindowInsets(insets)
}
}
insets
}

View File

@ -0,0 +1,39 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import androidx.core.widget.NestedScrollView
import com.gh.gamecenter.R
class MaxHeightNestedScrollView(context: Context, attrs: AttributeSet? = null) : NestedScrollView(context, attrs) {
var maxHeight = 0F
var scrollChangedListener: ScrollScrollChangedListener? = null
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightNestedScrollView)
maxHeight = typedArray.getDimension(R.styleable.MaxHeightNestedScrollView_mMaxHeight, 0f)
typedArray.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var newHeightMeasureSpec = 0
try {
newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight.toInt(), MeasureSpec.AT_MOST)
} catch (e: Exception) {
e.printStackTrace()
}
//重新计算控件高、宽
super.onMeasure(widthMeasureSpec, newHeightMeasureSpec)
}
override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
super.onScrollChanged(l, t, oldl, oldt)
scrollChangedListener?.onScrollChanged(l, t, oldl, oldt)
}
interface ScrollScrollChangedListener {
fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int)
}
}

View File

@ -0,0 +1,38 @@
package com.gh.common.view
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
class MaxHeightRecyclerView : RecyclerView {
private var mMaxHeight: Int = 0
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initialize(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initialize(context, attrs)
}
private fun initialize(context: Context, attrs: AttributeSet) {
val arr = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightRecyclerView)
mMaxHeight = arr.getLayoutDimension(R.styleable.MaxHeightRecyclerView_mRvMaxHeight, mMaxHeight)
arr.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var heightMeasureSpec = heightMeasureSpec
if (mMaxHeight > 0) {
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST)
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}

View File

@ -0,0 +1,164 @@
package com.gh.common.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.core.view.MotionEventCompat;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.ViewCompat;
import wendu.dsbridge.DWebView;
public class NestedScrollWebView extends DWebView implements NestedScrollingChild {
public static final String TAG = NestedScrollWebView.class.getSimpleName();
private int mLastMotionY;
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private int mNestedYOffset;
private boolean mChange;
private NestedScrollingChildHelper mChildHelper;
public NestedScrollWebView(Context context) {
super(context);
init();
}
public NestedScrollWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = false;
MotionEvent trackedEvent = MotionEvent.obtain(event);
final int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_DOWN) {
mNestedYOffset = 0;
}
int y = (int) event.getY();
event.offsetLocation(0, mNestedYOffset);
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
result = super.onTouchEvent(event);
mChange = false;
break;
case MotionEvent.ACTION_MOVE:
int deltaY = mLastMotionY - y;
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
deltaY -= mScrollConsumed[1];
trackedEvent.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
}
int oldY = getScrollY();
mLastMotionY = y - mScrollOffset[1];
int newScrollY = Math.max(0, oldY + deltaY);
deltaY -= newScrollY - oldY;
if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
mLastMotionY -= mScrollOffset[1];
trackedEvent.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
}
if(mScrollConsumed[1]==0 && mScrollOffset[1]==0) {
if(mChange){
mChange =false;
trackedEvent.setAction(MotionEvent.ACTION_DOWN);
super.onTouchEvent(trackedEvent);
}else {
result = super.onTouchEvent(trackedEvent);
}
trackedEvent.recycle();
}else{
if(Math.abs(mLastMotionY - y) >= 10) {
if (!mChange) {
mChange = true;
super.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0));
}
}
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopNestedScroll();
result = super.onTouchEvent(event);
break;
}
return result;
}
// NestedScrollingChild
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return mChildHelper.isNestedScrollingEnabled();
}
@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);
}
}

View File

@ -4,13 +4,14 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import com.gh.common.util.DisplayUtils;
import com.gh.gamecenter.R;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
private Paint paint;
@ -18,13 +19,21 @@ public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
private int mIntervalLR;
private boolean mIsShowIntervalTop;
public VerticalItemDecoration(Context context, float interval, boolean isShowIntervalTop) {
public VerticalItemDecoration(Context context, float interval, boolean isShowIntervalTop, int colorRes) {
paint = new Paint();
paint.setColor(ContextCompat.getColor(context, R.color.background));
if (colorRes != 0) {
paint.setColor(ContextCompat.getColor(context, colorRes));
} else {
paint.setColor(ContextCompat.getColor(context, R.color.background));
}
mInterval = DisplayUtils.dip2px(context, interval);
mIsShowIntervalTop = isShowIntervalTop;
}
public VerticalItemDecoration(Context context, float interval, boolean isShowIntervalTop) {
this(context, interval, isShowIntervalTop, 0);
}
public VerticalItemDecoration(Context context, int interval, boolean isShowIntervalTop, int intervalLR) {
paint = new Paint();
paint.setColor(ContextCompat.getColor(context, R.color.background));

View File

@ -42,28 +42,28 @@ class WelcomeDialog : BaseDialogFragment() {
binding.ivOpeningCover.setOnClickListener {
when (mWelcomeEntity?.type) {
EntranceUtils.HOST_ARTICLE -> {
DirectUtils.directToArticle(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
DirectUtils.directToArticle(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
}
EntranceUtils.HOST_GAME -> {
DirectUtils.directToGameDetail(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
DirectUtils.directToGameDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
}
EntranceUtils.HOST_COLUMN -> {
DirectUtils.directToSubject(context!!, mWelcomeEntity?.link!!, null, EntranceUtils.ENTRANCE_WELCOME)
DirectUtils.directToSubject(requireContext(), mWelcomeEntity?.link!!, null, EntranceUtils.ENTRANCE_WELCOME)
}
EntranceUtils.HOST_QUESTION -> {
DirectUtils.directToQuestionDetail(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
DirectUtils.directToQuestionDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
}
EntranceUtils.HOST_ANSWER -> {
DirectUtils.directToAnswerDetail(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
DirectUtils.directToAnswerDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
}
EntranceUtils.HOST_WEB -> {
DirectUtils.directToWebView(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
DirectUtils.directToWebView(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
}
EntranceUtils.HOST_QQ -> {
DirectUtils.directToQqConversation(context!!, mWelcomeEntity?.link!!)
DirectUtils.directToQqConversation(requireContext(), mWelcomeEntity?.link!!)
}
EntranceUtils.HOST_COMMUNITY -> {
DirectUtils.directToCommunity(context!!, CommunityEntity(mWelcomeEntity?.link!!, mWelcomeEntity?.text!!))
DirectUtils.directToCommunity(requireContext(), CommunityEntity(mWelcomeEntity?.link!!, mWelcomeEntity?.text!!))
}
else -> DialogUtils.showLowVersionDialog(context)
}
@ -75,10 +75,19 @@ class WelcomeDialog : BaseDialogFragment() {
binding.ivOpeningCover.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
binding.ivClose.visibility = View.VISIBLE
binding.root.post {
if (binding.ivOpeningCover.measuredHeight > binding.root.resources.displayMetrics.heightPixels * .8) {
binding.ivCloseBackup.visibility = View.VISIBLE
} else {
binding.ivClose.visibility = View.VISIBLE
}
}
}
}
binding.ivCloseBackup.setOnClickListener {
dismiss()
}
binding.ivClose.setOnClickListener {
dismiss()
}

View File

@ -3,8 +3,8 @@ package com.gh.common.view
import android.content.Context
import android.graphics.drawable.Animatable
import android.net.Uri
import androidx.annotation.Nullable
import android.util.AttributeSet
import androidx.annotation.Nullable
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.view.SimpleDraweeView

View File

@ -0,0 +1,436 @@
package com.gh.common.view.divider;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
public abstract class FlexibleDividerDecoration extends RecyclerView.ItemDecoration {
private static final int DEFAULT_SIZE = 2;
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
protected enum DividerType {
DRAWABLE, PAINT, COLOR
}
protected DividerType mDividerType = DividerType.DRAWABLE;
protected VisibilityProvider mVisibilityProvider;
protected PaintProvider mPaintProvider;
protected ColorProvider mColorProvider;
protected DrawableProvider mDrawableProvider;
protected SizeProvider mSizeProvider;
protected boolean mShowLastDivider;
protected boolean mPositionInsideItem;
private Paint mPaint;
protected FlexibleDividerDecoration(Builder builder) {
if (builder.mPaintProvider != null) {
mDividerType = DividerType.PAINT;
mPaintProvider = builder.mPaintProvider;
} else if (builder.mColorProvider != null) {
mDividerType = DividerType.COLOR;
mColorProvider = builder.mColorProvider;
mPaint = new Paint();
setSizeProvider(builder);
} else {
mDividerType = DividerType.DRAWABLE;
if (builder.mDrawableProvider == null) {
TypedArray a = builder.mContext.obtainStyledAttributes(ATTRS);
final Drawable divider = a.getDrawable(0);
a.recycle();
mDrawableProvider = new DrawableProvider() {
@Override
public Drawable drawableProvider(int position, RecyclerView parent) {
return divider;
}
};
} else {
mDrawableProvider = builder.mDrawableProvider;
}
mSizeProvider = builder.mSizeProvider;
}
mVisibilityProvider = builder.mVisibilityProvider;
mShowLastDivider = builder.mShowLastDivider;
mPositionInsideItem = builder.mPositionInsideItem;
}
private void setSizeProvider(Builder builder) {
mSizeProvider = builder.mSizeProvider;
if (mSizeProvider == null) {
mSizeProvider = new SizeProvider() {
@Override
public int dividerSize(int position, RecyclerView parent) {
return DEFAULT_SIZE;
}
};
}
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
RecyclerView.Adapter adapter = parent.getAdapter();
if (adapter == null) {
return;
}
int itemCount = adapter.getItemCount();
int lastDividerOffset = getLastDividerOffset(parent);
int validChildCount = parent.getChildCount();
int lastChildPosition = -1;
for (int i = 0; i < validChildCount; i++) {
View child = parent.getChildAt(i);
int childPosition = parent.getChildAdapterPosition(child);
if (childPosition < lastChildPosition) {
// Avoid remaining divider when animation starts
continue;
}
lastChildPosition = childPosition;
if (!mShowLastDivider && childPosition >= itemCount - lastDividerOffset) {
// Don't draw divider for last line if mShowLastDivider = false
continue;
}
if (wasDividerAlreadyDrawn(childPosition, parent)) {
// No need to draw divider again as it was drawn already by previous column
continue;
}
int groupIndex = getGroupIndex(childPosition, parent);
if (mVisibilityProvider.shouldHideDivider(groupIndex, parent)) {
continue;
}
Rect bounds = getDividerBound(groupIndex, parent, child);
switch (mDividerType) {
case DRAWABLE:
Drawable drawable = mDrawableProvider.drawableProvider(groupIndex, parent);
drawable.setBounds(bounds);
drawable.draw(c);
break;
case PAINT:
mPaint = mPaintProvider.dividerPaint(groupIndex, parent);
c.drawLine(bounds.left, bounds.top, bounds.right, bounds.bottom, mPaint);
break;
case COLOR:
mPaint.setColor(mColorProvider.dividerColor(groupIndex, parent));
mPaint.setStrokeWidth(mSizeProvider.dividerSize(groupIndex, parent));
c.drawLine(bounds.left, bounds.top, bounds.right, bounds.bottom, mPaint);
break;
}
}
}
@Override
public void getItemOffsets(Rect rect, View v, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(v);
int itemCount = parent.getAdapter().getItemCount();
int lastDividerOffset = getLastDividerOffset(parent);
if (!mShowLastDivider && position >= itemCount - lastDividerOffset) {
// Don't set item offset for last line if mShowLastDivider = false
return;
}
int groupIndex = getGroupIndex(position, parent);
if (mVisibilityProvider.shouldHideDivider(groupIndex, parent)) {
return;
}
setItemOffsets(rect, groupIndex, parent);
}
/**
* Check if recyclerview is reverse layout
*
* @param parent RecyclerView
* @return true if recyclerview is reverse layout
*/
protected boolean isReverseLayout(RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
return ((LinearLayoutManager) layoutManager).getReverseLayout();
} else {
return false;
}
}
/**
* In the case mShowLastDivider = false,
* Returns offset for how many views we don't have to draw a divider for,
* for LinearLayoutManager it is as simple as not drawing the last child divider,
* but for a GridLayoutManager it needs to take the span count for the last items into account
* until we use the span count configured for the grid.
*
* @param parent RecyclerView
* @return offset for how many views we don't have to draw a divider or 1 if its a
* LinearLayoutManager
*/
private int getLastDividerOffset(RecyclerView parent) {
if (parent.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
GridLayoutManager.SpanSizeLookup spanSizeLookup = layoutManager.getSpanSizeLookup();
int spanCount = layoutManager.getSpanCount();
int itemCount = parent.getAdapter().getItemCount();
for (int i = itemCount - 1; i >= 0; i--) {
if (spanSizeLookup.getSpanIndex(i, spanCount) == 0) {
return itemCount - i;
}
}
}
return 1;
}
/**
* Determines whether divider was already drawn for the row the item is in,
* effectively only makes sense for a grid
*
* @param position current view position to draw divider
* @param parent RecyclerView
* @return true if the divider can be skipped as it is in the same row as the previous one.
*/
private boolean wasDividerAlreadyDrawn(int position, RecyclerView parent) {
if (parent.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
GridLayoutManager.SpanSizeLookup spanSizeLookup = layoutManager.getSpanSizeLookup();
int spanCount = layoutManager.getSpanCount();
return spanSizeLookup.getSpanIndex(position, spanCount) > 0;
}
return false;
}
/**
* Returns a group index for GridLayoutManager.
* for LinearLayoutManager, always returns position.
*
* @param position current view position to draw divider
* @param parent RecyclerView
* @return group index of items
*/
private int getGroupIndex(int position, RecyclerView parent) {
if (parent.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
GridLayoutManager.SpanSizeLookup spanSizeLookup = layoutManager.getSpanSizeLookup();
int spanCount = layoutManager.getSpanCount();
return spanSizeLookup.getSpanGroupIndex(position, spanCount);
}
return position;
}
protected abstract Rect getDividerBound(int position, RecyclerView parent, View child);
protected abstract void setItemOffsets(Rect outRect, int position, RecyclerView parent);
/**
* Interface for controlling divider visibility
*/
public interface VisibilityProvider {
/**
* Returns true if divider should be hidden.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return True if the divider at position should be hidden
*/
boolean shouldHideDivider(int position, RecyclerView parent);
}
/**
* Interface for controlling paint instance for divider drawing
*/
public interface PaintProvider {
/**
* Returns {@link Paint} for divider
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return Paint instance
*/
Paint dividerPaint(int position, RecyclerView parent);
}
/**
* Interface for controlling divider color
*/
public interface ColorProvider {
/**
* Returns {@link android.graphics.Color} value of divider
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return Color value
*/
int dividerColor(int position, RecyclerView parent);
}
/**
* Interface for controlling drawable object for divider drawing
*/
public interface DrawableProvider {
/**
* Returns drawable instance for divider
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return Drawable instance
*/
Drawable drawableProvider(int position, RecyclerView parent);
}
/**
* Interface for controlling divider size
*/
public interface SizeProvider {
/**
* Returns size value of divider.
* Height for horizontal divider, width for vertical divider
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return Size of divider
*/
int dividerSize(int position, RecyclerView parent);
}
public static class Builder<T extends Builder> {
private Context mContext;
protected Resources mResources;
private PaintProvider mPaintProvider;
private ColorProvider mColorProvider;
private DrawableProvider mDrawableProvider;
private SizeProvider mSizeProvider;
private VisibilityProvider mVisibilityProvider = new VisibilityProvider() {
@Override
public boolean shouldHideDivider(int position, RecyclerView parent) {
return false;
}
};
private boolean mShowLastDivider = false;
private boolean mPositionInsideItem = false;
public Builder(Context context) {
mContext = context;
mResources = context.getResources();
}
public T paint(final Paint paint) {
return paintProvider(new PaintProvider() {
@Override
public Paint dividerPaint(int position, RecyclerView parent) {
return paint;
}
});
}
public T paintProvider(PaintProvider provider) {
mPaintProvider = provider;
return (T) this;
}
public T color(final int color) {
return colorProvider(new ColorProvider() {
@Override
public int dividerColor(int position, RecyclerView parent) {
return color;
}
});
}
public T colorResId(@ColorRes int colorId) {
return color(ContextCompat.getColor(mContext, colorId));
}
public T colorProvider(ColorProvider provider) {
mColorProvider = provider;
return (T) this;
}
public T drawable(@DrawableRes int id) {
return drawable(ContextCompat.getDrawable(mContext, id));
}
public T drawable(final Drawable drawable) {
return drawableProvider(new DrawableProvider() {
@Override
public Drawable drawableProvider(int position, RecyclerView parent) {
return drawable;
}
});
}
public T drawableProvider(DrawableProvider provider) {
mDrawableProvider = provider;
return (T) this;
}
public T size(final int size) {
return sizeProvider(new SizeProvider() {
@Override
public int dividerSize(int position, RecyclerView parent) {
return size;
}
});
}
public T sizeResId(@DimenRes int sizeId) {
return size(mResources.getDimensionPixelSize(sizeId));
}
public T sizeProvider(SizeProvider provider) {
mSizeProvider = provider;
return (T) this;
}
public T visibilityProvider(VisibilityProvider provider) {
mVisibilityProvider = provider;
return (T) this;
}
public T showLastDivider() {
mShowLastDivider = true;
return (T) this;
}
public T positionInsideItem(boolean positionInsideItem) {
mPositionInsideItem = positionInsideItem;
return (T) this;
}
protected void checkBuilderParams() {
if (mPaintProvider != null) {
if (mColorProvider != null) {
throw new IllegalArgumentException(
"Use setColor method of Paint class to specify line color. Do not provider ColorProvider if you set PaintProvider.");
}
if (mSizeProvider != null) {
throw new IllegalArgumentException(
"Use setStrokeWidth method of Paint class to specify line size. Do not provider SizeProvider if you set PaintProvider.");
}
}
}
}
}

View File

@ -0,0 +1,171 @@
package com.gh.common.view.divider;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import androidx.annotation.DimenRes;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
public class HorizontalDividerItemDecoration extends FlexibleDividerDecoration {
private MarginProvider mMarginProvider;
protected HorizontalDividerItemDecoration(Builder builder) {
super(builder);
mMarginProvider = builder.mMarginProvider;
}
@Override
protected Rect getDividerBound(int position, RecyclerView parent, View child) {
Rect bounds = new Rect(0, 0, 0, 0);
int transitionX = (int) ViewCompat.getTranslationX(child);
int transitionY = (int) ViewCompat.getTranslationY(child);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
bounds.left = parent.getPaddingLeft() +
mMarginProvider.dividerLeftMargin(position, parent) + transitionX;
bounds.right = parent.getWidth() - parent.getPaddingRight() -
mMarginProvider.dividerRightMargin(position, parent) + transitionX;
int dividerSize = getDividerSize(position, parent);
boolean isReverseLayout = isReverseLayout(parent);
if (mDividerType == DividerType.DRAWABLE) {
// set top and bottom position of divider
if (isReverseLayout) {
bounds.bottom = child.getTop() - params.topMargin + transitionY;
bounds.top = bounds.bottom - dividerSize;
} else {
bounds.top = child.getBottom() + params.bottomMargin + transitionY;
bounds.bottom = bounds.top + dividerSize;
}
} else {
// set center point of divider
int halfSize = dividerSize / 2;
if (isReverseLayout) {
bounds.top = child.getTop() - params.topMargin - halfSize + transitionY;
} else {
bounds.top = child.getBottom() + params.bottomMargin + halfSize + transitionY;
}
bounds.bottom = bounds.top;
}
if (mPositionInsideItem) {
if (isReverseLayout) {
bounds.top += dividerSize;
bounds.bottom += dividerSize;
} else {
bounds.top -= dividerSize;
bounds.bottom -= dividerSize;
}
}
return bounds;
}
@Override
protected void setItemOffsets(Rect outRect, int position, RecyclerView parent) {
if (mPositionInsideItem) {
outRect.set(0, 0, 0, 0);
return;
}
if (isReverseLayout(parent)) {
outRect.set(0, getDividerSize(position, parent), 0, 0);
} else {
outRect.set(0, 0, 0, getDividerSize(position, parent));
}
}
private int getDividerSize(int position, RecyclerView parent) {
if (mPaintProvider != null) {
return (int) mPaintProvider.dividerPaint(position, parent).getStrokeWidth();
} else if (mSizeProvider != null) {
return mSizeProvider.dividerSize(position, parent);
} else if (mDrawableProvider != null) {
Drawable drawable = mDrawableProvider.drawableProvider(position, parent);
return drawable.getIntrinsicHeight();
}
throw new RuntimeException("failed to get size");
}
/**
* Interface for controlling divider margin
*/
public interface MarginProvider {
/**
* Returns left margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return left margin
*/
int dividerLeftMargin(int position, RecyclerView parent);
/**
* Returns right margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return right margin
*/
int dividerRightMargin(int position, RecyclerView parent);
}
public static class Builder extends FlexibleDividerDecoration.Builder<Builder> {
private MarginProvider mMarginProvider = new MarginProvider() {
@Override
public int dividerLeftMargin(int position, RecyclerView parent) {
return 0;
}
@Override
public int dividerRightMargin(int position, RecyclerView parent) {
return 0;
}
};
public Builder(Context context) {
super(context);
}
public Builder margin(final int leftMargin, final int rightMargin) {
return marginProvider(new MarginProvider() {
@Override
public int dividerLeftMargin(int position, RecyclerView parent) {
return leftMargin;
}
@Override
public int dividerRightMargin(int position, RecyclerView parent) {
return rightMargin;
}
});
}
public Builder margin(int horizontalMargin) {
return margin(horizontalMargin, horizontalMargin);
}
public Builder marginResId(@DimenRes int leftMarginId, @DimenRes int rightMarginId) {
return margin(mResources.getDimensionPixelSize(leftMarginId),
mResources.getDimensionPixelSize(rightMarginId));
}
public Builder marginResId(@DimenRes int horizontalMarginId) {
return marginResId(horizontalMarginId, horizontalMarginId);
}
public Builder marginProvider(MarginProvider provider) {
mMarginProvider = provider;
return this;
}
public HorizontalDividerItemDecoration build() {
checkBuilderParams();
return new HorizontalDividerItemDecoration(this);
}
}
}

View File

@ -0,0 +1,172 @@
package com.gh.common.view.divider;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import androidx.annotation.DimenRes;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
public class VerticalDividerItemDecoration extends FlexibleDividerDecoration {
private MarginProvider mMarginProvider;
protected VerticalDividerItemDecoration(Builder builder) {
super(builder);
mMarginProvider = builder.mMarginProvider;
}
@Override
protected Rect getDividerBound(int position, RecyclerView parent, View child) {
Rect bounds = new Rect(0, 0, 0, 0);
int transitionX = (int) ViewCompat.getTranslationX(child);
int transitionY = (int) ViewCompat.getTranslationY(child);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
bounds.top = parent.getPaddingTop() +
mMarginProvider.dividerTopMargin(position, parent) + transitionY;
bounds.bottom = parent.getHeight() - parent.getPaddingBottom() -
mMarginProvider.dividerBottomMargin(position, parent) + transitionY;
int dividerSize = getDividerSize(position, parent);
boolean isReverseLayout = isReverseLayout(parent);
if (mDividerType == DividerType.DRAWABLE) {
// set left and right position of divider
if (isReverseLayout) {
bounds.right = child.getLeft() - params.leftMargin + transitionX;
bounds.left = bounds.right - dividerSize;
} else {
bounds.left = child.getRight() + params.rightMargin + transitionX;
bounds.right = bounds.left + dividerSize;
}
} else {
// set center point of divider
int halfSize = dividerSize / 2;
if (isReverseLayout) {
bounds.left = child.getLeft() - params.leftMargin - halfSize + transitionX;
} else {
bounds.left = child.getRight() + params.rightMargin + halfSize + transitionX;
}
bounds.right = bounds.left;
}
if (mPositionInsideItem) {
if (isReverseLayout) {
bounds.left += dividerSize;
bounds.right += dividerSize;
} else {
bounds.left -= dividerSize;
bounds.right -= dividerSize;
}
}
return bounds;
}
@Override
protected void setItemOffsets(Rect outRect, int position, RecyclerView parent) {
if (mPositionInsideItem) {
outRect.set(0, 0, 0, 0);
return;
}
if (isReverseLayout(parent)) {
outRect.set(getDividerSize(position, parent), 0, 0, 0);
} else {
outRect.set(0, 0, getDividerSize(position, parent), 0);
}
}
private int getDividerSize(int position, RecyclerView parent) {
if (mPaintProvider != null) {
return (int) mPaintProvider.dividerPaint(position, parent).getStrokeWidth();
} else if (mSizeProvider != null) {
return mSizeProvider.dividerSize(position, parent);
} else if (mDrawableProvider != null) {
Drawable drawable = mDrawableProvider.drawableProvider(position, parent);
return drawable.getIntrinsicWidth();
}
throw new RuntimeException("failed to get size");
}
/**
* Interface for controlling divider margin
*/
public interface MarginProvider {
/**
* Returns top margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return top margin
*/
int dividerTopMargin(int position, RecyclerView parent);
/**
* Returns bottom margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return bottom margin
*/
int dividerBottomMargin(int position, RecyclerView parent);
}
public static class Builder extends FlexibleDividerDecoration.Builder<Builder> {
private MarginProvider mMarginProvider = new MarginProvider() {
@Override
public int dividerTopMargin(int position, RecyclerView parent) {
return 0;
}
@Override
public int dividerBottomMargin(int position, RecyclerView parent) {
return 0;
}
};
public Builder(Context context) {
super(context);
}
public Builder margin(final int topMargin, final int bottomMargin) {
return marginProvider(new MarginProvider() {
@Override
public int dividerTopMargin(int position, RecyclerView parent) {
return topMargin;
}
@Override
public int dividerBottomMargin(int position, RecyclerView parent) {
return bottomMargin;
}
});
}
public Builder margin(int verticalMargin) {
return margin(verticalMargin, verticalMargin);
}
public Builder marginResId(@DimenRes int topMarginId, @DimenRes int bottomMarginId) {
return margin(mResources.getDimensionPixelSize(topMarginId),
mResources.getDimensionPixelSize(bottomMarginId));
}
public Builder marginResId(@DimenRes int verticalMarginId) {
return marginResId(verticalMarginId, verticalMarginId);
}
public Builder marginProvider(MarginProvider provider) {
mMarginProvider = provider;
return this;
}
public VerticalDividerItemDecoration build() {
checkBuilderParams();
return new VerticalDividerItemDecoration(this);
}
}
}

View File

@ -23,15 +23,15 @@ public class MaterialRatingDrawable extends LayerDrawable {
public MaterialRatingDrawable(Context context, boolean fillBackgroundStars) {
super(new Drawable[]{
createLayerDrawableWithTintAttrRes(fillBackgroundStars ?
R.drawable.ic_star
: R.drawable.ic_star_border, fillBackgroundStars ?
R.drawable.ic_icon_star_ratting
: R.drawable.ic_icon_star_ratting_gray, fillBackgroundStars ?
R.attr.colorControlHighlight : R.attr.colorControlNormal, context),
fillBackgroundStars ? createClippedLayerDrawableWithTintColor(
R.drawable.ic_star, Color.TRANSPARENT, context)
R.drawable.ic_icon_star_ratting, Color.TRANSPARENT, context)
: createClippedLayerDrawableWithTintAttrRes(
R.drawable.ic_star_border, R.attr.colorControlActivated,
R.drawable.ic_icon_star_ratting_gray, R.attr.colorControlActivated,
context),
createClippedLayerDrawableWithTintAttrRes(R.drawable.ic_star,
createClippedLayerDrawableWithTintAttrRes(R.drawable.ic_icon_star_ratting,
R.attr.colorControlActivated, context)
});

View File

@ -2,14 +2,15 @@ package com.gh.download;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
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.util.AppDebugConfig;
@ -55,11 +56,6 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import static android.os.Build.MANUFACTURER;
public class DownloadManager implements DownloadStatusListener {
private static DownloadManager mInstance;
@ -229,7 +225,7 @@ public class DownloadManager implements DownloadStatusListener {
@Nullable ExposureEvent traceEvent) {
// 安装指引
if ("Huawei".equalsIgnoreCase(MANUFACTURER) || "Oppo".equalsIgnoreCase(MANUFACTURER)) {
/*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)) {
@ -241,7 +237,7 @@ public class DownloadManager implements DownloadStatusListener {
edit.putBoolean("InstallHint" + PackageUtils.getVersionName(), false).apply();
}
}
}
}*/
// 插件版本下载互斥弹窗
List<String> mutexPackage = gameEntity.getMutexPackage();
@ -275,12 +271,15 @@ public class DownloadManager implements DownloadStatusListener {
}
}
downloadEntity.setInstalled(installed);
if ("更新".equals(method)) {
downloadEntity.setUpdate(true);
} else if ("插件化".equals(method)) {
// todo 不是应该实时判断吗?
if (PackageUtils.isCanPluggable(apkEntity)) {
downloadEntity.setPluggable(true);
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.getId())) {
downloadEntity.setUpdate(true);
}
downloadEntity.setPlugin(gameEntity.getTag() != null && gameEntity.getTag().size() != 0);
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
if (isSubscribe) {
DownloadManager.getInstance(context).subscribe(downloadEntity);
@ -634,6 +633,7 @@ public class DownloadManager implements DownloadStatusListener {
// 开启下载服务, Fuck me, 即便是在启动页调用的方法,依然有可能触发 `unable is in background`
startDownloadService();
checkRetryDownload();
}
public void addObserver(DataWatcher dataWatcher) {

View File

@ -2,6 +2,7 @@ package com.gh.download.cache
import android.net.Uri
import com.gh.common.runOnIoThread
import com.gh.common.util.DeviceUtils
import com.gh.common.util.NetworkUtils
import com.gh.gamecenter.BuildConfig
import com.google.android.exoplayer2.upstream.DataSpec
@ -20,11 +21,18 @@ import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSourceFactory
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
object ExoCacheManager {
private val threads = ConcurrentHashMap<String, AtomicBoolean>()
private const val preLength = 50 * 1024 * 1024L //预加载视频大小
private val preLength by lazy {
val totalRamSizeOfDevice = DeviceUtils.getTotalRamSizeOfDevice(HaloApp.getInstance().application)
if (totalRamSizeOfDevice <= 2 * 1024) {
10 * 1024 * 1024L
} else {
50 * 1024 * 1024L
}
}
fun preload(videoUri: String) {
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
@ -48,7 +56,7 @@ object ExoCacheManager {
Utils.log("$requestLength--$bytesCached--$newBytesCached")
}
}, threads[videoUri])
} catch (e: Exception) {
} catch (e: Throwable) {
threads.remove(videoUri)
e.printStackTrace()
}

View File

@ -0,0 +1,423 @@
package com.gh.download.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.*
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
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.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogDownloadBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.utils.AppManager
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
private lateinit var mGameEntity: GameEntity
private lateinit var mViewModel: DownloadViewModel
private lateinit var mBinding: DialogDownloadBinding
private lateinit var mElapsedHelper: TimeElapsedHelper
private lateinit var mGestureDetector: GestureDetector
private var mAdapter: DownloadDialogAdapter? = null
// 合集页面保持和后台一样的顺序
private var mCollectionAdapter: DownloadDialogAdapter? = null
/**
* 例子:在首页跳转至专题详情点击下载
* mEntrance-> (首页)+(专题详情)
* mLocation-> 专题名称:游戏名称
*
* 注意location 只用于下载统计,具体的 entrance = entrance + path
*/
private var mEntrance: String = "" // 入口位置
private var mLocation: String = "" // 最终位置
private var mInitPositionY = 0f
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.gameId == mGameEntity?.id &&
DownloadStatus.delete != DownloadManager.getInstance(requireContext()).getStatus(downloadEntity.url)) {
mAdapter?.listData?.forEachIndexed { index, entity ->
if (entity.normal?.packageName == downloadEntity.packageName
|| entity.installed?.packageName == downloadEntity.packageName) {
mAdapter?.notifyItemChanged(index)
}
}
mCollectionAdapter?.listData?.forEachIndexed { index, entity ->
if (entity.normal?.packageName == downloadEntity.packageName
|| entity.installed?.packageName == downloadEntity.packageName) {
mCollectionAdapter?.notifyItemChanged(index)
}
}
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val createDialog = super.onCreateDialog(savedInstanceState)
createDialog.setCanceledOnTouchOutside(true)
val window = createDialog.window
window?.setGravity(Gravity.BOTTOM)
window?.setWindowAnimations(R.style.community_publication_animation)
return createDialog
}
override fun onCreate(savedInstanceState: Bundle?) {
EventBus.getDefault().register(this)
super.onCreate(savedInstanceState)
mGameEntity = requireArguments().getParcelable(GameEntity::class.java.simpleName)!!
mEntrance = requireArguments().getString(EntranceUtils.KEY_ENTRANCE) ?: ""
mLocation = requireArguments().getString(EntranceUtils.KEY_LOCATION) ?: ""
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)
mBinding.contentList.layoutManager = createLayoutManager(itemList)
mBinding.contentList.adapter = mAdapter
})
mViewModel.collectionLiveData.observe(this, Observer { collection ->
if (collection != null) {
postBrowseMta()
mBinding.title.text = collection.name
val saveApkList = collection.saveApkEntity
throwExceptionInDebug("collection content must not be empty", saveApkList.isNullOrEmpty())
val itemList: MutableList<DownloadDialogItemData> = ArrayList()
saveApkList?.forEach { apk ->
itemList.add(DownloadDialogItemData(normal = apk))
}
if (collection.downloadInstruction.isNotEmpty()) {
itemList.add(DownloadDialogItemData(instruction = collection.downloadInstruction))
}
mCollectionAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, true, mEntrance, mLocation)
mBinding.collectionList.layoutManager = createLayoutManager(itemList)
mBinding.collectionList.adapter = mCollectionAdapter
if (mAdapter != null) collectionEnterAnimation()
} else {
mBinding.title.text = ("选择下载" + mGameEntity?.pluginDesc + "版本")
mCollectionAdapter = null
collectionExitAnimation()
}
})
mViewModel.dismissLiveData.observe(this, Observer {
dismiss()
})
mElapsedHelper = TimeElapsedHelper()
}
@SuppressLint("ClickableViewAccessibility")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mBinding = DataBindingUtil.inflate(inflater, R.layout.dialog_download, container, false)
mBinding.title.text = ("选择下载" + mGameEntity.pluginDesc + "版本")
val downloadNotice = mGameEntity.downloadAd
if (downloadNotice != null) {
mBinding.downloadNotice.visibility = View.VISIBLE
mBinding.downloadNotice.text = downloadNotice.title
mBinding.downloadNotice.setOnClickListener {
if ("imprint" == downloadNotice.type) {
DialogUtils.showImprintDialog(requireContext(), mGameEntity, downloadNotice.title)
} else {
DirectUtils.directToLinkPage(
requireContext(),
downloadNotice,
mEntrance, "下载多平台弹窗")
}
MtaHelper.onEvent(MTA_KEY, "点击", mViewModel.gameEntity.name + "_" + downloadNotice.title)
}
}
mBinding.back.setOnClickListener {
if (mCollectionAdapter != null && mAdapter != null) {
postBrowseMta()
mViewModel.collectionLiveData.postValue(null)
} else {
dismiss()
}
}
mGestureDetector = GestureDetector(requireContext(), SingleTapConfirm())
mBinding.dragClose.setOnTouchListener(this)
mBinding.back.setOnTouchListener(this)
mBinding.downloadNotice.setOnTouchListener(this)
(mBinding.contentList.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
(mBinding.collectionList.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
mBinding.contentList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val layoutManager = mBinding.contentList.layoutManager
if (layoutManager is LinearLayoutManager) {
val position = layoutManager.findLastVisibleItemPosition()
mBinding.otherVersionButtonContainer.goneIf(position > mViewModel.otherSectionPosition - 1)
}
}
})
val smoothScroller: SmoothScroller = object : LinearSmoothScroller(requireContext()) {
override fun getVerticalSnapPreference(): Int {
return SNAP_TO_START
}
}
mBinding.otherVersionButtonContainer.setOnClickListener {
smoothScroller.targetPosition = mViewModel.otherSectionPosition
mBinding.contentList.layoutManager?.startSmoothScroll(smoothScroller)
}
return mBinding.root
}
private fun collectionEnterAnimation() {
val backAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.download_dialog_collection_back_enter)
backAnimation.fillAfter = true
mBinding.back.startAnimation(backAnimation)
val contentAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.download_dialog_content_enter)
contentAnimation.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
mBinding.contentListContainer.visibility = View.GONE
}
override fun onAnimationStart(animation: Animation?) {
}
})
mBinding.contentListContainer.startAnimation(contentAnimation)
val collectionAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.download_dialog_collection_content_enter)
mBinding.collectionList.startAnimation(collectionAnimation)
mBinding.collectionList.visibility = View.VISIBLE
}
private fun collectionExitAnimation() {
val backAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.download_dialog_collection_back_exit)
backAnimation.fillAfter = true
mBinding.back.startAnimation(backAnimation)
val contentAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.download_dialog_content_exit)
mBinding.contentListContainer.startAnimation(contentAnimation)
mBinding.contentListContainer.visibility = View.VISIBLE
val collectionAnimation = AnimationUtils.loadAnimation(requireContext(), R.anim.download_dialog_collection_content_exit)
collectionAnimation.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
mBinding.collectionList.visibility = View.GONE
}
override fun onAnimationStart(animation: Animation?) {
}
})
mBinding.collectionList.startAnimation(collectionAnimation)
}
private fun createLayoutManager(listData: List<DownloadDialogItemData>): RecyclerView.LayoutManager {
val layoutManager = GridLayoutManager(requireContext(), 2)
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (listData[position].normal == null) 2 else 1
}
}
return layoutManager
}
override fun onResume() {
mAdapter?.notifyDataSetChanged()
mCollectionAdapter?.notifyDataSetChanged()
super.onResume()
DownloadManager.getInstance(requireContext()).addObserver(mDataWatcher)
mElapsedHelper.resetCounting()
mElapsedHelper.resumeCounting()
}
override fun onPause() {
super.onPause()
DownloadManager.getInstance(requireContext()).removeObserver(mDataWatcher)
mElapsedHelper.pauseCounting()
postBrowseMta()
}
private fun postBrowseMta() {
if (mCollectionAdapter == null) {
MtaHelper.onEventWithTime(MTA_KEY, mElapsedHelper.elapsedTime, "浏览", mGameEntity?.name)
} else {
val collectionData = mViewModel.collectionLiveData.value
MtaHelper.onEventWithTime(MTA_KEY, mElapsedHelper.elapsedTime, "浏览", mGameEntity?.name + "_" + collectionData?.name)
throwExceptionInDebug("collectionData must be not null", collectionData == null)
}
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width, height)
}
override fun onBack(): Boolean {
if (mCollectionAdapter != null && mAdapter != null) {
postBrowseMta()
mViewModel.collectionLiveData.postValue(null)
return true
}
return super.onBack()
}
// dialog drag animation
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (mGestureDetector.onTouchEvent(event) && mBinding.root.y == 0F) {
v.performClick()
return true
}
when (event.action) {
MotionEvent.ACTION_DOWN -> {
mInitPositionY = mBinding.root.y - event.rawY
}
MotionEvent.ACTION_MOVE -> {
val offsetY = event.rawY + mInitPositionY
val dialogY = mBinding.root.y
if (dialogY + offsetY > 0) {
mBinding.root.animate()
.y(offsetY)
.setDuration(0)
.start()
} else {
resetDialogPosition()
}
}
MotionEvent.ACTION_CANCEL,
MotionEvent.ACTION_UP,
MotionEvent.ACTION_OUTSIDE -> {
if (mBinding.root.y >= mBinding.root.height / 2) {
dismiss()
} else {
resetDialogPosition(300)
}
}
else -> return false
}
return true
}
private fun resetDialogPosition(duration: Long = 0) {
mBinding.root.animate()
.y(0F)
.setDuration(duration)
.start()
}
private class SingleTapConfirm : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(event: MotionEvent): Boolean {
return true
}
}
//安装、卸载事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (::mViewModel.isInitialized && mViewModel.gameEntity.pluggableCollection == null) {
val listData = mViewModel.listLiveData.value ?: return
listData.forEach { itemData ->
if (itemData.installed != null) {
if (itemData.installed?.packageName == busFour.packageName) {
mViewModel.initListData()
return
}
}
if (itemData.normal != null) {
if (itemData.normal?.packageName == busFour.packageName) {
mViewModel.initListData()
return
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
EventBus.getDefault().unregister(this)
}
companion object {
@JvmStatic
fun showDownloadDialog(context: Context?, gameEntity: GameEntity, entrance: String?, location: String?) {
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
context
} else if (BuildConfig.DEBUG) {
throw IllegalStateException("DownloadDialog context must be FragmentActivity")
} else {
val currentActivity = AppManager.getInstance().currentActivity()
if (currentActivity is FragmentActivity) {
currentActivity
} else {
throw IllegalStateException("current activity context must be FragmentActivity")
}
}
// 防止重复弹出
if (hasDownloadDialogInCurrentActivity(fragmentActivity)) return
val downloadDialog = DownloadDialog().apply {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance)
bundle.putString(EntranceUtils.KEY_LOCATION, location)
bundle.putParcelable(GameEntity::class.java.simpleName, gameEntity)
arguments = bundle
}
downloadDialog.show(fragmentActivity.supportFragmentManager, DownloadDialog::class.java.name)
}
private fun hasDownloadDialogInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
fragments.forEach { fragment ->
if (fragment is DownloadDialog) return true
}
return false
}
const val MTA_KEY = "多版本下载"
}
}

View File

@ -0,0 +1,130 @@
package com.gh.download.dialog
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.OnViewClickListener
import com.gh.common.util.MtaHelper
import com.gh.common.util.throwExceptionInDebug
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.QaActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.GameEntity
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.utils.Utils
class DownloadDialogAdapter(context: Context,
val viewModel: DownloadViewModel,
val listData: List<DownloadDialogItemData>,
val isCollectionPage: Boolean,
private val mEntrance: String,
private val mLocation: String) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private val mPath = if (isCollectionPage) {
"下载弹窗-二级页"
} else {
"下载弹窗"
}
override fun getItemViewType(position: Int): Int {
val itemData = listData[position]
if (itemData.links != null) return ITEM_LINK
if (itemData.section != null) return ITEM_SECTION
if (itemData.installed != null) return ITEM_INSTALLED
if (itemData.instruction != null) return ITEM_INSTRUCTION
if (itemData.platformRequest != null) return ITEM_PLATFORM_REQUEST
return ITEM_NORMAL
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View
return when (viewType) {
ITEM_LINK -> {
view = mLayoutInflater.inflate(R.layout.download_dialog_link_item, parent, false)
DownloadDialogLinkItemViewHolder(DownloadDialogLinkItemBinding.bind(view))
}
ITEM_SECTION -> {
view = mLayoutInflater.inflate(R.layout.download_dialog_section_item, parent, false)
DownloadDialogSectionItemViewHolder(DownloadDialogSectionItemBinding.bind(view))
}
ITEM_INSTALLED -> {
view = mLayoutInflater.inflate(R.layout.download_dialog_installed_item, parent, false)
DownloadDialogInstalledItemViewHolder(DownloadDialogInstalledItemBinding.bind(view))
}
ITEM_INSTRUCTION -> {
view = mLayoutInflater.inflate(R.layout.download_dialog_instruction_item, parent, false)
DownloadDialogInstructionItemViewHolder(DownloadDialogInstructionItemBinding.bind(view))
}
ITEM_PLATFORM_REQUEST -> {
view = mLayoutInflater.inflate(R.layout.download_dialog_platform_request_item, parent, false)
DownloadDialogPlatformRequestItemViewHolder(DownloadDialogPlatformRequestItemBinding.bind(view))
}
else -> {
view = mLayoutInflater.inflate(R.layout.download_dialog_item, parent, false)
DownloadDialogItemViewHolder(DownloadDialogItemBinding.bind(view))
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DownloadDialogSectionItemViewHolder -> {
holder.binding.type = listData[position].section
}
is DownloadDialogLinkItemViewHolder -> {
holder.binding.links = listData[position].links
holder.binding.clickListener = OnViewClickListener<GameEntity.PluginLink> { _, data ->
when (data.linkType) {
"dialog" -> {
DownloadLinkDialog.showDownloadDialog(mContext, data)
}
"article" -> {
mContext.startActivity(NewsDetailActivity.getIntentById(mContext, data.linkId, mEntrance))
}
"qa" -> {
mContext.startActivity(QaActivity.getIntent(mContext, data.linkText, qaId = data.linkId))
}
"qa_collection" -> {
mContext.startActivity(QaActivity.getIntent(mContext, data.linkText, qaCollectionId = data.linkId))
}
else -> {
Utils.toast(mContext, "暂不支持类型:" + data.linkType)
}
}
MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", viewModel.gameEntity.name + "_" + data.title)
}
}
is DownloadDialogInstructionItemViewHolder -> {
holder.bindItem(listData[position].instruction!!)
}
is DownloadDialogPlatformRequestItemViewHolder -> {
holder.bindItem(viewModel.gameEntity)
}
is DownloadDialogInstalledItemViewHolder -> {
holder.bindInstalledItem(listData[position].installed!!, viewModel, mEntrance, mPath, mLocation)
throwExceptionInDebug("合集页面不应该存在该条数据", isCollectionPage)
}
is DownloadDialogItemViewHolder -> {
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mEntrance, mPath, mLocation)
}
}
}
override fun getItemCount(): Int {
return listData.size
}
companion object {
private const val ITEM_LINK = 200
private const val ITEM_SECTION = 201
private const val ITEM_INSTALLED = 202
private const val ITEM_NORMAL = 203
private const val ITEM_INSTRUCTION = 204
private const val ITEM_PLATFORM_REQUEST = 205
const val ITEM_TAG_KEY = R.id.download_item_type
}
}

View File

@ -0,0 +1,128 @@
package com.gh.download.dialog
import android.view.View
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.util.PackageUtils
import com.gh.common.util.goneIf
import com.gh.common.util.throwExceptionInDebug
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DownloadDialogInstalledItemBinding
import com.gh.gamecenter.entity.ApkEntity
import com.halo.assistant.HaloApp
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) {
val gameEntity = viewModel.gameEntity
val apkCollection = apkEntity.apkCollection
binding.pluginDesc = gameEntity.pluginDesc
binding.apk = if (apkCollection != null) {
ApkEntity(platformIcon = apkCollection.newIcon, platformName = apkCollection.name, remark = apkCollection.remark)
} else apkEntity
binding.root.setBackgroundResource(R.drawable.download_dialog_item_background)
if (apkEntity.apkLink != null) {
throwExceptionInDebug("apkLink 不应该出现在这里")
} else if (apkCollection != null || apkEntity.downloadInstruction.isNotEmpty()) {
binding.collection.visibility = View.VISIBLE
binding.downloadStatusIcon.visibility = View.GONE
binding.progressbar.visibility = View.GONE
binding.pluggable.visibility = View.GONE
binding.install.visibility = View.GONE
binding.update.visibility = View.GONE
binding.status.visibility = View.GONE
binding.launch.visibility = View.GONE
if (apkCollection != null) {
binding.remark.goneIf(apkCollection.remark.isEmpty())
binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
} else {
binding.remark.goneIf(apkEntity.remark.isEmpty())
}
binding.collection.text = if (apkCollection != null) {
"查看合集"
} else "查看详情"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.COLLECTION)
} else {
binding.collection.visibility = View.GONE
val downloadEntity = DownloadManager.getInstance(HaloApp.getInstance().application).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity != null) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.progressbar.visibility = View.VISIBLE
binding.status.visibility = View.VISIBLE
binding.remark.visibility = View.GONE
binding.launch.visibility = View.GONE
binding.pluggable.visibility = View.GONE
binding.update.visibility = View.GONE
binding.install.goneIf(DownloadStatus.done != downloadEntity.status)
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_pause)
binding.progressbar.progress = downloadEntity.percent.toInt()
binding.status.text = DownloadDialogItemViewHolder.getDownloadingStatusText(downloadEntity)
if (DownloadStatus.done == downloadEntity.status) {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.INSTALL)
} else {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.DOWNLOADING)
}
} else {
binding.downloadStatusIcon.visibility = View.GONE
binding.progressbar.visibility = View.GONE
binding.status.visibility = View.GONE
binding.install.visibility = View.GONE
binding.remark.goneIf(apkEntity.remark.isEmpty())
if (PackageUtils.isCanPluggable(apkEntity)) {
binding.pluggable.visibility = View.VISIBLE
binding.update.visibility = View.GONE
binding.launch.visibility = View.GONE
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.PLUGGABLE)
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
binding.update.visibility = View.VISIBLE
binding.pluggable.visibility = View.GONE
binding.launch.visibility = View.GONE
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.UPDATE)
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id) {
binding.status.visibility = View.VISIBLE
binding.pluggable.visibility = View.GONE
binding.update.visibility = View.GONE
var isFilter = false
Config.getSettings()?.gameDownloadBlackList?.forEach { pkgName ->
if (pkgName == apkEntity.packageName) {
isFilter = true
}
}
if (isFilter) {
// 已安装
binding.status.visibility = View.VISIBLE
binding.launch.visibility = View.GONE
binding.status.text = "已安装"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.INSTALLED)
} else {
// 点击启动
binding.launch.visibility = View.VISIBLE
binding.status.visibility = View.GONE
binding.status.text = "点击启动"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LAUNCH)
}
} else {
throwExceptionInDebug("下载弹窗-我的版本出现未知类型")
}
}
}
DownloadDialogItemViewHolder.setDownloadClickListener(itemView, apkEntity, viewModel, entrance, path, location)
binding.executePendingBindings()
}
}

View File

@ -0,0 +1,18 @@
package com.gh.download.dialog
import android.graphics.Color
import com.gh.base.BaseRecyclerViewHolder
import com.gh.gamecenter.databinding.DownloadDialogInstructionItemBinding
class DownloadDialogInstructionItemViewHolder(val binding: DownloadDialogInstructionItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(instruction: String) {
binding.webView.loadDataWithBaseURL(
null,
"<body style='margin:0;padding:0;'>$instruction</body>",
"text/html",
"utf-8", null)
binding.webView.settings
binding.webView.setBackgroundColor(Color.TRANSPARENT)
}
}

View File

@ -0,0 +1,16 @@
package com.gh.download.dialog
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameEntity
data class DownloadDialogItemData(var links: List<GameEntity.PluginLink>? = null,
var section: DownloadDialogSectionType? = null,
var installed: ApkEntity? = null,
var normal: ApkEntity? = null,
var instruction: String? = null,
var platformRequest: Any? = null)
enum class DownloadDialogSectionType {
INSTALLED,
OTHER
}

View File

@ -0,0 +1,14 @@
package com.gh.download.dialog
enum class DownloadDialogItemStatus {
DOWNLOAD,
LAUNCH,
DOWNLOADING,
INSTALL,
PLUGGABLE,
UPDATE,
COLLECTION,
LINK,
INSTALLED,
IGNORE
}

View File

@ -0,0 +1,288 @@
package com.gh.download.dialog
import android.content.Context
import android.view.View
import com.gh.base.BaseActivity
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.util.*
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
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.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(apkEntity: ApkEntity,
viewModel: DownloadViewModel,
isCollectionPage: Boolean,
entrance: String,
path: String,
location: String) {
val gameEntity = viewModel.gameEntity
val apkLink = apkEntity.apkLink
val apkCollection = apkEntity.apkCollection
binding.apk = when {
apkLink != null -> ApkEntity(
platformIcon = apkLink.icon,
platformName = apkLink.name,
remark = apkLink.remark)
apkCollection != null -> ApkEntity(
platformIcon = apkCollection.newIcon,
platformName = apkCollection.name,
remark = apkCollection.remark)
else -> apkEntity
}
binding.root.setBackgroundResource(R.drawable.download_dialog_item_background)
if (apkLink != null) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.status.visibility = View.VISIBLE
binding.progressbar.visibility = View.GONE
binding.install.visibility = View.GONE
binding.remark.goneIf(apkLink.remark.isEmpty())
binding.status.text = "点击查看"
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_link)
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LINK)
} else if (apkCollection != null || (!isCollectionPage && apkEntity.downloadInstruction.isNotEmpty())) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.progressbar.visibility = View.GONE
binding.install.visibility = View.GONE
binding.status.visibility = View.GONE
if (apkCollection != null) {
binding.remark.goneIf(apkCollection.remark.isEmpty())
binding.root.setBackgroundResource(R.drawable.download_dialog_item_collection_background)
} else {
binding.remark.goneIf(apkEntity.remark.isEmpty())
}
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_collection)
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.COLLECTION)
} else {
val downloadEntity = DownloadManager.getInstance(HaloApp.getInstance().application).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity != null) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.progressbar.visibility = View.VISIBLE
binding.status.visibility = View.VISIBLE
binding.remark.visibility = View.GONE
binding.install.goneIf(DownloadStatus.done != downloadEntity.status)
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_pause)
binding.progressbar.progress = downloadEntity.percent.toInt()
binding.status.text = getDownloadingStatusText(downloadEntity)
if (DownloadStatus.done == downloadEntity.status) {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.INSTALL)
} else {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.DOWNLOADING)
}
} else {
binding.progressbar.visibility = View.GONE
binding.install.visibility = View.GONE
binding.remark.goneIf(apkEntity.remark.isEmpty())
if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.status.visibility = View.VISIBLE
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) {
binding.downloadStatusIcon.visibility = View.GONE
binding.status.visibility = View.VISIBLE
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
var isFilter = false
Config.getSettings()?.gameDownloadBlackList?.forEach { pkgName ->
if (pkgName == apkEntity.packageName) {
isFilter = true
}
}
if (isFilter) {
// 已安装
binding.status.text = "已安装"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.INSTALLED)
} else {
// 点击启动
binding.status.text = "点击启动"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.LAUNCH)
}
} else {
binding.downloadStatusIcon.visibility = View.VISIBLE
binding.status.visibility = View.GONE
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_status_download)
if (PackageUtils.isCanPluggable(apkEntity)) {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.PLUGGABLE)
} else {
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.DOWNLOAD)
}
}
}
}
setDownloadClickListener(itemView, apkEntity, viewModel, entrance, path, location)
binding.executePendingBindings()
}
companion object {
fun getDownloadingStatusText(downloadEntity: DownloadEntity): String {
return when (downloadEntity.status) {
DownloadStatus.waiting -> "等待中"
DownloadStatus.done -> "等待安装"
DownloadStatus.downloading -> SpeedUtils.getSpeed(downloadEntity.speed)
else -> "已暂停"
}
}
fun setDownloadClickListener(itemView: View,
apkEntity: ApkEntity,
viewModel: DownloadViewModel,
entrance: String,
path: String,
location: String) {
val gameEntity = viewModel.gameEntity
itemView.setOnClickListener {
var mtaValue = "未知"
when (itemView.getTag(DownloadDialogAdapter.ITEM_TAG_KEY)) {
DownloadDialogItemStatus.DOWNLOAD -> {
createDownloadTask(it.context, apkEntity, gameEntity, "下载", entrance, location)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_下载"
}
DownloadDialogItemStatus.LAUNCH -> {
PackageUtils.launchApplicationByPackageName(it.context, apkEntity.packageName)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_启动"
}
DownloadDialogItemStatus.DOWNLOADING -> {
// 打开下载管理界面
it.context.startActivity(DownloadManagerActivity.getDownloadMangerIntent(
it.context,
apkEntity.url,
BaseActivity.mergeEntranceAndPath(entrance, path)))
if (AppManager.getInstance().currentActivity() is DownloadManagerActivity) {
viewModel.dismissLiveData.postValue(Any())
}
val downloadEntity = DownloadManager.getInstance(it.context).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity.status == DownloadStatus.pause) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_暂停中"
} else if (downloadEntity.status == DownloadStatus.waiting) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_等待中"
} else if (downloadEntity.status == DownloadStatus.subscribe) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_排队中"
} else {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_下载中"
}
}
DownloadDialogItemStatus.INSTALL -> {
val downloadEntity = DownloadManager.getInstance(it.context).getDownloadEntityByUrl(apkEntity.url)
if (FileUtils.isEmptyFile(downloadEntity.path)) {
Utils.toast(it.context, R.string.install_failure_hint)
DownloadManager.getInstance(it.context).cancel(apkEntity.url)
} else {
if (PackageUtils.isCanPluggable(apkEntity)) {
DialogUtils.showPluginDialog(it.context) {
it.context.startActivity(PackageUtils.getUninstallIntent(it.context, downloadEntity.path))
}
} else {
PackageUtils.launchSetup(it.context, downloadEntity)
}
}
if (downloadEntity.isPluggable) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_插件化安装"
} else {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_安装"
}
}
DownloadDialogItemStatus.PLUGGABLE -> {
createDownloadTask(it.context, apkEntity, gameEntity, "插件化", entrance, location)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_插件化"
}
DownloadDialogItemStatus.UPDATE -> {
createDownloadTask(it.context, apkEntity, gameEntity, "更新", entrance, location)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_更新"
}
DownloadDialogItemStatus.COLLECTION -> {
val apkCollection = apkEntity.apkCollection
if (apkCollection != null) {
viewModel.collectionLiveData.postValue(apkCollection)
mtaValue = gameEntity.name + "_" + apkCollection.name + "_查看合集"
} else if (apkEntity.downloadInstruction.isNotEmpty()) {
val fakeCollection = GameCollectionEntity()
fakeCollection.saveApkEntity = arrayListOf(apkEntity)
fakeCollection.name = apkEntity.getPlatformName()
fakeCollection.downloadInstruction = apkEntity.downloadInstruction
viewModel.collectionLiveData.postValue(fakeCollection)
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_查看详情"
} else {
throwExceptionInDebug("合集和下载说明至少一个不为空")
}
}
DownloadDialogItemStatus.LINK -> {
directToLinkPage(it.context, apkEntity.apkLink?.getLinkEntity()!!, entrance, path)
mtaValue = gameEntity.name + "_" + apkEntity.apkLink?.name
}
DownloadDialogItemStatus.INSTALLED -> {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_已安装"
}
}
throwExceptionInDebug("无法识别当前状态", mtaValue == "未知")
MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", mtaValue)
}
}
private fun createDownloadTask(context: Context,
apkEntity: ApkEntity,
gameEntity: GameEntity,
downloadMethod: String,
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)
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
}
})
}
})
}
}
}

View File

@ -0,0 +1,8 @@
package com.gh.download.dialog
import com.gh.base.BaseRecyclerViewHolder
import com.gh.gamecenter.databinding.DownloadDialogLinkItemBinding
class DownloadDialogLinkItemViewHolder(val binding: DownloadDialogLinkItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
}

View File

@ -0,0 +1,19 @@
package com.gh.download.dialog
import com.gh.base.BaseRecyclerViewHolder
import com.gh.common.util.MtaHelper
import com.gh.gamecenter.VoteActivity
import com.gh.gamecenter.databinding.DownloadDialogPlatformRequestItemBinding
import com.gh.gamecenter.entity.GameEntity
class DownloadDialogPlatformRequestItemViewHolder(val binding: DownloadDialogPlatformRequestItemBinding)
: BaseRecyclerViewHolder<Any>(binding.root) {
fun bindItem(gameEntity: GameEntity) {
binding.content.setOnClickListener {
val intent = VoteActivity.getIntent(it.context, gameEntity.name, gameEntity.id)
it.context.startActivity(intent)
MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", gameEntity.name + "_求版本")
}
}
}

View File

@ -0,0 +1,9 @@
package com.gh.download.dialog
import com.gh.base.BaseRecyclerViewHolder
import com.gh.gamecenter.databinding.DownloadDialogLinkItemBinding
import com.gh.gamecenter.databinding.DownloadDialogSectionItemBinding
class DownloadDialogSectionItemViewHolder(val binding: DownloadDialogSectionItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
}

View File

@ -0,0 +1,64 @@
package com.gh.download.dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.FragmentActivity
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.dip2px
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogDownloadLinkBinding
import com.gh.gamecenter.entity.GameEntity
import com.halo.assistant.HaloApp
import com.lightgame.utils.AppManager
class DownloadLinkDialog : BaseDialogFragment() {
private lateinit var mLinkEntity: GameEntity.PluginLink
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding: DialogDownloadLinkBinding = DataBindingUtil.inflate(inflater, R.layout.dialog_download_link, container, false)
binding.title.text = mLinkEntity.title
binding.webView.loadDataWithBaseURL(null,
mLinkEntity.content, "text/html", "utf-8", null)
binding.confirm.setOnClickListener {
dismiss()
}
return binding.root
}
override fun onStart() {
super.onStart()
val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT
dialog?.window?.setLayout(width - 60F.dip2px(), height)
}
companion object {
@JvmStatic
fun showDownloadDialog(context: Context?, linkEntity: GameEntity.PluginLink) {
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
context
} else if (BuildConfig.DEBUG) {
throw IllegalStateException("DownloadLinkDialog context must be FragmentActivity")
} else {
val currentActivity = AppManager.getInstance().currentActivity()
if (currentActivity is FragmentActivity) {
currentActivity
} else {
throw IllegalStateException("current activity context must be FragmentActivity")
}
}
val dialog = DownloadLinkDialog().apply { mLinkEntity = linkEntity }
dialog.show(fragmentActivity.supportFragmentManager, DownloadLinkDialog::class.java.name)
}
}
}

View File

@ -0,0 +1,246 @@
package com.gh.download.dialog
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
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.lightgame.download.DownloadStatus
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.ArrayList
/**
* 已安装部分排序:安装插件化->安装更新->插件化下载中->更新下载中->插件化->更新->启动
*
* 其它部分排序:安装→下载中
*
* 注意:
* 1.上述一级页面排序包含合集
* 2.二级页面(合集详情),切勿打乱原有排序,按后台顺序显示
*/
class DownloadViewModel(application: Application, val gameEntity: GameEntity) : AndroidViewModel(application) {
val listLiveData: MutableLiveData<List<DownloadDialogItemData>> = MutableLiveData()
val collectionLiveData: MutableLiveData<GameCollectionEntity> = MutableLiveData()
val dismissLiveData: MutableLiveData<Any> = MutableLiveData()
private var mAllApkList: MutableList<ApkEntity> = ArrayList()
private var mInstalledApkList: MutableList<ApkEntity> = ArrayList()
private var mOtherApkList: MutableList<ApkEntity> = ArrayList()
var otherSectionPosition = -1
init {
if (gameEntity.pluggableCollection != null) {
collectionLiveData.postValue(gameEntity.pluggableCollection)
} else {
initListData()
}
}
fun initListData() {
mAllApkList = ArrayList()
mInstalledApkList = ArrayList()
mOtherApkList = ArrayList()
mergeApkCollection()
mergeApkLink()
mAllApkList.forEach { apk ->
setSortValueToApkEntity(apk)
val installed = if (apk.apkCollection != null) {
var isInstalled = false
apk.apkCollection?.saveApkEntity?.let {
for (entity in it) {
isInstalled = PackagesManager.isInstalled(entity.packageName)
if (isInstalled) break
}
}
isInstalled
} else {
PackagesManager.isInstalled(apk.packageName)
}
if (installed) {
mInstalledApkList.add(apk)
} else {
mOtherApkList.add(apk)
}
}
mInstalledApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
mOtherApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
val itemList: MutableList<DownloadDialogItemData> = ArrayList()
val pluginLink = gameEntity.pluginLink
if (pluginLink.isNotEmpty()) {
itemList.add(DownloadDialogItemData(links = pluginLink))
}
if (mInstalledApkList.isNotEmpty()) {
itemList.add(DownloadDialogItemData(section = DownloadDialogSectionType.INSTALLED))
}
mInstalledApkList.forEach { apk ->
itemList.add(DownloadDialogItemData(installed = apk))
}
if (mOtherApkList.isNotEmpty()) {
otherSectionPosition = itemList.size
itemList.add(DownloadDialogItemData(section = DownloadDialogSectionType.OTHER))
}
mOtherApkList.forEach { apk ->
itemList.add(DownloadDialogItemData(normal = apk))
}
itemList.add(DownloadDialogItemData(platformRequest = Any()))
listLiveData.postValue(itemList)
}
private fun setSortValueToApkEntity(apkEntity: ApkEntity) {
apkEntity.apkCollection?.saveApkEntity?.forEach { saveApk ->
val sortValue = getSortValue(saveApk)
if (apkEntity.order < sortValue) {
apkEntity.order = sortValue
}
}
if (apkEntity.order == 0) {
apkEntity.order = getSortValue(apkEntity)
}
}
private fun getSortValue(apkEntity: ApkEntity): Int {
val packageName = apkEntity.packageName
val downloadEntity = DownloadManager.getInstance(getApplication()).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity == null) {
if (PackagesManager.isInstalled(packageName)) {
if (PackageUtils.isCanPluggable(apkEntity)) {
return SORT_PLUGGABLE
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
return SORT_UPDATE
} else if (PackageUtils.getMetaData(getApplication(), packageName, "gh_id") == gameEntity.id) {
return SORT_NORMAL_LAUNCH
}
}
return SORT_NORMAL
} else {
return if (downloadEntity.status == DownloadStatus.done) {
if (downloadEntity.isPluggable) {
SORT_PLUGGABLE_INSTALL
} else if (downloadEntity.isUpdate) {
SORT_UPDATE_INSTALL
} else {
SORT_NORMAL_INSTALL
}
} else {
if (downloadEntity.isPluggable) {
SORT_PLUGGABLE_DOWNLOADING
} else if (downloadEntity.isUpdate) {
SORT_UPDATE_DOWNLOADING
} else {
SORT_NORMAL_DOWNLOADING
}
}
}
}
private fun mergeApkCollection() {
val gameCollectionApk = ArrayList<ApkEntity>()
val hashMap = ConcurrentHashMap<String, Int>()
var isCollection: Boolean
for (apkEntity in gameEntity.getApk()) {
isCollection = false
for (gameCollectionEntity in gameEntity.collection) {
for (packageName in gameCollectionEntity.packages) {
if (packageName == apkEntity.packageName) {
isCollection = true
val index = hashMap[gameCollectionEntity.name]
if (index != null) {
gameCollectionApk[index].apkCollection?.saveApkEntity?.add(apkEntity)
} else {
val newApkEntity = ApkEntity()
val saveApkList = ArrayList<ApkEntity>()
saveApkList.add(apkEntity)
gameCollectionEntity.saveApkEntity = saveApkList
newApkEntity.apkCollection = gameCollectionEntity
gameCollectionApk.add(newApkEntity)
hashMap[gameCollectionEntity.name] = gameCollectionApk.size - 1
}
}
}
}
if (!isCollection) {
gameCollectionApk.add(apkEntity)
}
}
mAllApkList = gameCollectionApk
}
private fun mergeApkLink() {
gameEntity.apkLink?.forEach { link ->
val collection = link.collection
if (collection.isNotEmpty()) {
mAllApkList.forEach { apk ->
apk.apkCollection?.let { apkCollection ->
val saveApkEntity = apkCollection.saveApkEntity
if (saveApkEntity != null && collection == apkCollection.id) {
val element = ApkEntity()
element.apkLink = link
if (saveApkEntity.size > link.sort) {
saveApkEntity.add(link.sort, element)
} else {
saveApkEntity.add(element)
}
}
}
}
} else {
val linkApkEntity = ApkEntity()
linkApkEntity.apkLink = link
if (mAllApkList.size > link.sort) {
mAllApkList.add(link.sort, linkApkEntity)
} else {
mAllApkList.add(linkApkEntity)
}
}
}
}
class Factory(val mApplication: Application, val gameEntity: GameEntity) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return DownloadViewModel(mApplication, gameEntity) as T
}
}
companion object {
// 需要修改排序的话,只需要修改以下数值即可(由大到小排序)
const val SORT_PLUGGABLE_INSTALL = 10
const val SORT_PLUGGABLE_DOWNLOADING = 9
const val SORT_PLUGGABLE = 8
const val SORT_UPDATE_INSTALL = 7
const val SORT_UPDATE_DOWNLOADING = 6
const val SORT_UPDATE = 5
const val SORT_NORMAL_INSTALL = 4
const val SORT_NORMAL_DOWNLOADING = 3
const val SORT_NORMAL_LAUNCH = 2
const val SORT_NORMAL = 1
}
}

View File

@ -36,7 +36,6 @@ class HelpAndFeedbackActivity : BaseActivity_TabLayout() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle("帮助与反馈")
mTabIndicatorView.setIndicatorWidth(88)
}
override fun onPageSelected(position: Int) {
@ -56,8 +55,10 @@ class HelpAndFeedbackActivity : BaseActivity_TabLayout() {
const val SUGGESTION_ITEM = 1
@JvmStatic
fun getIntent(context: Context): Intent {
return Intent(context, HelpAndFeedbackActivity::class.java)
fun getIntent(context: Context, position: Int = HELP_ITEM): Intent {
val intent = Intent(context, HelpAndFeedbackActivity::class.java)
intent.putExtra(PAGE_INDEX, position)
return intent
}
}
}

View File

@ -96,8 +96,6 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
private String mListStatus; // 记录列表领取状态(防止状态在详情改变导致列表状态改变)
private String mName;
private String mTitle;
protected String mDownloadAddWord;
protected String mDownloadOffText;
@Override
protected void handleMessage(Message msg) {
@ -148,7 +146,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
private DetailViewHolder getDetailViewHolder() {
// 每次获取需要重新创建, 防止数据刷新
return new DetailViewHolder(mContentView, mGameEntity, mDownloadEntity, mDownloadOffText, mDownloadAddWord,
return new DetailViewHolder(mContentView, mGameEntity, mDownloadEntity,
false, mEntrance, mName, mTitle, null); // 下载按钮ViewHolder
}
@ -362,8 +360,6 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
mGameEntity = response;
mAdapter.setGameEntity(mGameEntity);
mDownloadAddWord = mGameEntity.getDownloadAddWord();
mDownloadOffText = mGameEntity.getDownloadOffText();
DetailDownloadUtils.detailInitDownload(getDetailViewHolder(), true);
mAdapter.addLibaoDetail(LibaoDetailActivity.this, true);

View File

@ -23,6 +23,9 @@ 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;
@ -32,6 +35,7 @@ import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.common.im.ImManager;
import com.gh.common.loghub.LoghubUtils;
import com.gh.common.repository.ReservationRepository;
import com.gh.common.util.ActivationHelper;
import com.gh.common.util.ClassUtils;
@ -87,8 +91,10 @@ import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import com.tencent.bugly.beta.tinker.TinkerManager;
import com.tencent.bugly.crashreport.CrashReport;
import com.umeng.message.PushAgent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
@ -113,8 +119,6 @@ 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;
@ -140,7 +144,6 @@ public class MainActivity extends BaseActivity {
public final static String SWITCH_TO_COMMUNITY = "switch_to_community";
public final static String SWITCH_TO_VIDEO = "switch_to_video";
private final static String IS_SKIPPED = "is_skipped";
private final static String CURRENT_PAGE = "current_page";
private PackageViewModel mPackageViewModel;
@ -160,17 +163,16 @@ public class MainActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setStatusBarColor(Color.TRANSPARENT);
mSp = PreferenceManager.getDefaultSharedPreferences(this);
mMainWrapperFragment = new MainWrapperFragment();
if (savedInstanceState != null) {
mMainWrapperFragment.setArguments(savedInstanceState);
} else if (getIntent() != null) {
Bundle extras = getIntent().getExtras();
mMainWrapperFragment.setArguments(extras);
mMainWrapperFragment.setArguments(getIntent().getExtras());
}
replaceFragment(mMainWrapperFragment);
mSp = PreferenceManager.getDefaultSharedPreferences(this);
isNewFirstLaunch = mSp.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
if (isNewFirstLaunch) {
final LunchType lunchType = DeviceTokenUtils.getLaunchType();
@ -211,9 +213,10 @@ public class MainActivity extends BaseActivity {
"玩家操作", "点击关闭"));
}
// checkTinkerPath(); // todo 看情况是否需要显示弹窗
// checkTinkerPath(); // 看情况是否需要显示补丁弹窗
checkRetryDownload();
// 必须放在这里否在会导致获取baseActivity不是本应用包名
DownloadManager.getInstance(this).initDownloadService();
checkNotificationPermission();
@ -243,6 +246,7 @@ public class MainActivity extends BaseActivity {
PushHelper.postPushClickAction(this.getApplicationContext(), null);
}, 2000);
// 耗时操作
AppExecutor.getIoExecutor().execute(() -> {
// 上传数据
@ -253,6 +257,8 @@ public class MainActivity extends BaseActivity {
UpdateManager.getInstance(this).checkUpdate(true, null);
// 初始化PlatformUtils
PlatformUtils.getInstance(getApplicationContext());
// 友盟记录启动
PushAgent.getInstance(this).onAppStart();
});
@ -299,7 +305,6 @@ public class MainActivity extends BaseActivity {
DisplayUtils.setLightStatusBar(this, false);
}
}
}
}
@ -694,15 +699,23 @@ public class MainActivity extends BaseActivity {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBPackage busFour) {
final String packageName = busFour.getPackageName();
final String versionName = busFour.getVersionName();
String gameId = "";
DownloadEntity mDownloadEntity = null;
for (DownloadEntity downloadEntity : DownloadManager.getInstance(getApplicationContext()).getAll()) {
//todo 根据包名获取DownloadEntity? 假如存在相同包名的下载任务,有可能会删除错误
if (packageName.equals(downloadEntity.getPackageName())) {
mDownloadEntity = downloadEntity;
gameId = mDownloadEntity.getGameId();
break;
gameId = mDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER);
if (TextUtils.isEmpty(busFour.getVersionName())) {
// 没有版本号的事件直接选用第一个找到的 downloadEntity
break;
} else {
// 有版本号的事件直接尽量找到版本一致的 downloadEntity
if (versionName.equals(downloadEntity.getVersionName())) {
break;
}
}
}
}
@ -748,7 +761,7 @@ public class MainActivity extends BaseActivity {
public void onResponse(List<GameDigestEntity> response) {
for (GameDigestEntity gameDigestEntity : response) {
if (!TextUtils.isEmpty(gameDigestEntity.getId())) { // 关注游戏
if (finalDownloadEntity != null && gameDigestEntity.getId().equals(finalDownloadEntity.getGameId())) {
if (finalDownloadEntity != null && gameDigestEntity.getId().equals(finalDownloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER))) {
ConcernUtils.INSTANCE.postConcernGameId(MainActivity.this, gameDigestEntity.getId(), null, false);
}
}
@ -791,11 +804,23 @@ public class MainActivity extends BaseActivity {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList();
// 更新已安装游戏
JSONObject packageObject = PackageUtils.getAppBasicInfoByPackageName(packageName);
JSONObject dataObject = new JSONObject();
JSONObject wrapperObject = new JSONObject();
try {
dataObject.put("type", "POST");
dataObject.put("device_id", HaloApp.getInstance().getGid());
dataObject.put("app", packageObject);
dataObject.put("time", Utils.getTime(getApplicationContext()));
wrapperObject.put("content", dataObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"),
packageObject.toString());
// 更新已安装游戏
RetrofitManager.getInstance(MainActivity.this).getApi()
.postNewlyInstalledApp(HaloApp.getInstance().getGid(), requestBody)
@ -827,6 +852,20 @@ public class MainActivity extends BaseActivity {
// 发送应用变更前都检查一下是否需要把所有应用都上传
PackageRepository.checkAndUploadAppList();
// 删除已安装游戏
JSONObject dataObject = new JSONObject();
JSONObject wrapperObject = new JSONObject();
try {
dataObject.put("type", "DELETE");
dataObject.put("device_id", HaloApp.getInstance().getGid());
dataObject.put("package", packageName);
dataObject.put("time", Utils.getTime(getApplicationContext()));
wrapperObject.put("content", dataObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true);
// 删除已安装游戏
RetrofitManager.getInstance(MainActivity.this).getApi()
.deleteInstalledApp(HaloApp.getInstance().getGid(), packageName)
@ -843,6 +882,11 @@ public class MainActivity extends BaseActivity {
}
}
@Override
protected boolean useButterKnife() {
return false;
}
@Override
public String getActivityNameInChinese() {
return "游戏首页";

View File

@ -118,7 +118,6 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
private long start = 0L;
private String newsId;
private String downloadOffText;
private SharedPreferences sp;
@ -168,7 +167,7 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
private DetailViewHolder getDetailViewHolder() {
// 每次获取需要重新创建, 防止数据刷新
return new DetailViewHolder(mContentView, gameEntity, mDownloadEntity, downloadOffText, null,
return new DetailViewHolder(mContentView, gameEntity, mDownloadEntity,
true, mEntrance, "新闻详情", adapter.getTitle(), null); // 下载按钮ViewHolder
}
@ -343,7 +342,7 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
newsDetailEntity.getMe().setArticleFavorite(false);
mNewsCollection.setEnabled(true);
mNewsCollection.setIcon(R.drawable.menu_ic_collect_unselect);
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_unselect);
toast(R.string.collection_cancel);
}
@ -367,7 +366,7 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
}
userData.setArticleFavorite(true);
mNewsCollection.setEnabled(true);
mNewsCollection.setIcon(R.drawable.menu_ic_collect_select);
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_select);
toast(R.string.collection_success);
}
@ -446,9 +445,9 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
mNewsCollection.setVisible(true);
NewsDetailEntity newsDetailEntity = adapter.getNewsDetailEntity();
if (newsDetailEntity.getMe() != null && newsDetailEntity.getMe().isArticleFavorite()) {
mNewsCollection.setIcon(R.drawable.menu_ic_collect_select);
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_select);
} else {
mNewsCollection.setIcon(R.drawable.menu_ic_collect_unselect);
mNewsCollection.setIcon(R.drawable.community_content_detail_collect_unselect);
}
}
@ -629,7 +628,6 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
gameEntity = response;
adapter.setGameEntity(gameEntity);
adapter.notifyItemInserted(1);
downloadOffText = gameEntity.getDownloadOffText();
mDetailBottomLl.setVisibility(View.VISIBLE);
DetailDownloadUtils.detailInitDownload(getDetailViewHolder(), true);

View File

@ -0,0 +1,25 @@
package com.gh.gamecenter
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.help.HelpContainerFragment
class QaActivity : NormalActivity() {
companion object {
/**
* qaId 存在则是QA页面
* qaCollectionId 存在则是QA合集页面
* 两个都存在则默认时QA合集页面
*/
fun getIntent(context: Context, navigationTitle: String, qaId: String? = null, qaCollectionId: String? = null): Intent {
val args = Bundle()
args.putString(EntranceUtils.KEY_QA_ID, qaId)
args.putString(EntranceUtils.KEY_QA_COLLECTION_ID, qaCollectionId)
args.putString(EntranceUtils.KEY_NAVIGATION_TITLE, navigationTitle)
return getTargetIntent(context, QaActivity::class.java, HelpContainerFragment::class.java, args)
}
}
}

View File

@ -24,6 +24,7 @@ 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_COLUMN;
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_DOWNLOAD;
import static com.gh.common.util.EntranceUtils.HOST_GAME;
import static com.gh.common.util.EntranceUtils.HOST_LIBAO;
@ -51,7 +52,6 @@ import static com.gh.common.util.EntranceUtils.KEY_TYPE;
import static com.gh.common.util.EntranceUtils.KEY_VERSION;
/**
* TODO 将此页面与 DefaultWebViewUrlHandler 的跳转格式写成文档
* Created by LGT on 2016/11/16.
* 链接跳转用
*/
@ -232,6 +232,13 @@ public class SkipActivity extends BaseActivity {
String position = uri.getQueryParameter("position");
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
break;
case HOST_COMMUNITY_COLUMN:
CommunityEntity community = new CommunityEntity();
community.setId(uri.getQueryParameter("community_id"));
community.setName(uri.getQueryParameter("community_name"));
String columnId = uri.getQueryParameter("column_id");
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;

View File

@ -19,6 +19,7 @@ import com.g00fy2.versioncompare.Version;
import com.gh.base.BaseActivity;
import com.gh.common.AppExecutor;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DeviceTokenUtils;
import com.gh.common.util.DeviceUtils;
@ -26,19 +27,21 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.EmptyCallback;
import com.gh.common.util.GameRepositoryHelper;
import com.gh.common.util.GdtHelper;
import com.gh.common.util.GsonUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.TagUtils;
import com.gh.common.util.TimestampUtils;
import com.gh.common.util.UsageStatsHelper;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.entity.AuthDialogEntity;
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
import com.gh.gamecenter.manager.FilterManager;
import com.gh.gamecenter.retrofit.BiResponse;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.user.UserRepository;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.qq.gdt.action.ActionType;
@ -47,11 +50,13 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
@ -87,22 +92,17 @@ public class SplashScreenActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
isNewFirstLaunch = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
super.onCreate(savedInstanceState);
UserRepository.getInstance(getApplication()); // 初始化登录
// 处理助手已经在后台运行导致的再次启动助手
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
finish();
return;
}
TimestampUtils.initMap();
// 判断是不是这个版本的新用户
if (isNewFirstLaunch) {
// 删除更新后的光环助手包
@ -120,6 +120,7 @@ public class SplashScreenActivity extends BaseActivity {
// 判断是不是光环的新用户
if (SPUtils.getBoolean(SP_BRAND_NEW_USER, true)) {
HaloApp.getInstance().isBrandNewInstall = true;
showPrivacyPolicy(() -> {
// Dialog dismiss 后的回调
guideLayout.setVisibility(View.VISIBLE);
@ -136,7 +137,9 @@ public class SplashScreenActivity extends BaseActivity {
AppExecutor.getIoExecutor().execute(() -> {
Config.getGhzsSettings();
deviceDialogSetting();
getFilterDetailTags();
getAuthDialog();
UsageStatsHelper.checkAndPostUsageStats();
GameRepositoryHelper.getGameRepository(this);
@ -160,8 +163,6 @@ public class SplashScreenActivity extends BaseActivity {
// 更新本地时间
DeviceTokenUtils.syncServerTime(this);
DownloadManager.getInstance(this).initDownloadService();
});
}
@ -173,6 +174,42 @@ public class SplashScreenActivity extends BaseActivity {
}
}
@SuppressLint("CheckResult")
private void deviceDialogSetting() {
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
.getApi().deviceDialogs()
.subscribe((entities, throwable) -> {
if (entities.size() > 0) {
SPUtils.setString(Constants.SP_DEVICE_REMIND, GsonUtils.toJson(entities));
}
});
}
private void getFilterDetailTags() {
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
.getApi().getFilterDetailTags()
.subscribe(new Response<ArrayList<String>>() {
@Override
public void onResponse(@Nullable ArrayList<String> response) {
super.onResponse(response);
SPUtils.setString(Constants.SP_FILTER_TAGS, GsonUtils.toJson(response));
}
});
}
private void getAuthDialog() {
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
.getApi()
.authDialog()
.subscribe(new Response<List<AuthDialogEntity>>() {
@Override
public void onResponse(@Nullable List<AuthDialogEntity> response) {
super.onResponse(response);
SPUtils.setString(Constants.SP_AUTH_DIALOG, GsonUtils.toJson(response));
}
});
}
@SuppressLint("CheckResult")
private void showPrivacyPolicy(EmptyCallback callback) {
RetrofitManager.getInstance(this).getApi()
@ -199,15 +236,11 @@ public class SplashScreenActivity extends BaseActivity {
@Override
protected int getLayoutId() {
final int layoutId;
if (isNewFirstLaunch) {
layoutId = R.layout.activity_splash_intro;
return R.layout.activity_splash_intro;
} else {
layoutId = R.layout.activity_splash_normal;
return 0;
}
return layoutId;
}
@Override
@ -222,6 +255,16 @@ public class SplashScreenActivity extends BaseActivity {
return super.onKeyDown(keyCode, event);
}
@Override
protected boolean useEventBus() {
return false;
}
@Override
protected boolean useButterKnife() {
return false;
}
// 跳转到主界面
private void launchMainActivity() {
getUniqueId();

View File

@ -86,6 +86,7 @@ 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;
@ -483,8 +484,11 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
int widthPixels = getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(SuggestionActivity.this, 20), DisplayUtils.dip2px(SuggestionActivity.this, 12),
0, DisplayUtils.dip2px(SuggestionActivity.this, 12));
reportTv.setPadding(
DisplayUtils.dip2px(SuggestionActivity.this, 20),
DisplayUtils.dip2px(SuggestionActivity.this, 12),
DisplayUtils.dip2px(SuggestionActivity.this, 20),
DisplayUtils.dip2px(SuggestionActivity.this, 12));
container.addView(reportTv);
reportTv.setOnClickListener(v -> {
@ -707,6 +711,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
R.style.GhAlertDialog,
"意见反馈",
"意见反馈-游戏收录弹窗",
null,
"点击空白",
"点击手机返回键", false);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

View File

@ -43,13 +43,13 @@ import io.reactivex.schedulers.Schedulers;
*/
public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayout.OnRefreshListener, OnRequestCallBackListener {
@BindView(R.id.et_search)
public EditText searchEt;
@BindView(R.id.tv_search)
public TextView searchTv;
@BindView(R.id.tv_back)
public TextView backTv;
public View backTv;
@BindView(R.id.toolbox_appbar)
AppBarLayout mAppBar;
@BindView(R.id.toolbox_rv)
@ -64,51 +64,51 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
SwipeRefreshLayout mRefresh;
@BindView(R.id.reuse_ll_loading)
View mLoading;
private LinearLayoutManager mLayoutManager;
private ToolBoxRvAdapter mRvAdapter;
private ToolBoxRvAdapter mNormalRvAdapter;
private boolean mIsSearch; // 记录页面状态 搜索页面/普通页面
private String mSearchKey; // 记录搜索关键字
Runnable runnable = () -> changeAdapter(true);
@NonNull
public static Intent getIntent(Context context, String entrance) {
Intent intent = new Intent(context, ToolBoxActivity.class);
intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance);
return intent;
}
@Override
protected int getLayoutId() {
return R.layout.activity_toolbox;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setNavigationTitle("光环工具箱");
mRefresh.setColorSchemeResources(R.color.theme);
mRefresh.setOnRefreshListener(this);
// 跳转到工具箱 https://gitlab.ghzs.com/pm/halo-app-issues/issues/636
String gameId = getIntent().getStringExtra(EntranceUtils.KEY_GAMEID);
String targetUrl = getIntent().getStringExtra(EntranceUtils.KEY_URL);
if (!TextUtils.isEmpty(targetUrl) && !TextUtils.isEmpty(gameId)) {
findGameAndOpenItsToolboxWebview(gameId, targetUrl);
}
mLayoutManager = new LinearLayoutManager(this);
mToolboxRv.setLayoutManager(mLayoutManager);
mRvAdapter = new ToolBoxRvAdapter(this, this, mIsSearch, mSearchKey);
mToolboxRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
mToolboxRv.setAdapter(mRvAdapter);
mNormalRvAdapter = mRvAdapter;
mToolboxRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
@ -121,7 +121,7 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
}
}
});
mAppBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
if (verticalOffset == 0) {
mRefresh.setEnabled(true);
@ -133,10 +133,10 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
Util_System_Keyboard.hideSoftKeyboard(this);
}
});
initSearch();
}
private void findGameAndOpenItsToolboxWebview(String gameId, String url) {
RetrofitManager.getInstance(this)
.getApi()
@ -147,7 +147,7 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
@Override
public void onResponse(@Nullable List<ToolBoxEntity> response) {
if (response == null) return;
for (ToolBoxEntity toolbox : response) {
if (url.equals(toolbox.getUrl())) {
Intent intent = WebActivity.getWebByCollectionTools(ToolBoxActivity.this, toolbox, false);
@ -157,14 +157,14 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
}
});
}
private void initSearch() {
backTv.setOnClickListener(v -> search(false, searchEt.getText().toString()));
TextHelper.limitTheLengthOfEditText(searchEt, 20, () -> {
Utils.toast(this, "最多输入20字");
});
searchTv.setOnClickListener(v -> {
MtaHelper.onEvent("我的光环_新", "工具箱", "点击搜索");
if (TextUtils.isEmpty(searchEt.getText().toString())) {
@ -173,13 +173,13 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
}
search(true, searchEt.getText().toString());
});
searchEt.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
Util_System_Keyboard.hideSoftKeyboard(this, searchEt);
}
});
searchEt.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
searchTv.performClick();
@ -187,8 +187,8 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
return false;
});
}
@OnClick({R.id.reuse_no_connection, R.id.reuse_none_data})
public void onClick(View view) {
if (view.getId() == R.id.reuse_no_connection) {
@ -203,7 +203,7 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
}
}
}
@Override
public void loadDone() {
mRefresh.setRefreshing(false);
@ -211,12 +211,12 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
mNoConnection.setVisibility(View.GONE);
mLoading.setVisibility(View.GONE);
}
@Override
public void loadDone(Object obj) {
}
@Override
public void loadEmpty() {
mRefresh.setRefreshing(false);
@ -229,7 +229,7 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
mNoneDataTv.setText(getResources().getString(R.string.game_empty));
}
}
@Override
public void loadError() {
mRefresh.setRefreshing(false);
@ -237,12 +237,12 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
mNoConnection.setVisibility(View.VISIBLE);
mLoading.setVisibility(View.GONE);
}
@Override
public void onRefresh() {
mRefresh.postDelayed(runnable, 1000);
}
public void search(boolean isSearch, String searchKey) {
if (mNoneData.getVisibility() == View.VISIBLE) {
mNoneData.setVisibility(View.GONE);
@ -254,7 +254,7 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
mSearchKey = searchKey;
changeAdapter(false);
}
private void changeAdapter(boolean isRefresh) {
if (mIsSearch) {
mRvAdapter = new ToolBoxRvAdapter(this, this, mIsSearch, mSearchKey);
@ -267,12 +267,12 @@ public class ToolBoxActivity extends ToolBarActivity implements SwipeRefreshLayo
}
}
mToolboxRv.setAdapter(mRvAdapter);
if (mSearchKey != null) {
searchEt.setText(mSearchKey);
searchEt.setSelection(searchEt.getText().length());
}
if (mIsSearch) {
backTv.setVisibility(View.VISIBLE);
} else {

View File

@ -21,6 +21,12 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipeline;
@ -37,7 +43,6 @@ import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PermissionHelper;
import com.gh.common.util.SimpleImageLoader;
import com.gh.common.view.Gh_RelativeLayout;
import com.gh.common.view.Gh_RelativeLayout.OnSingleTapListener;
import com.gh.common.view.Gh_ViewPager;
import com.gh.gamecenter.entity.ImageInfoEntity;
import com.gh.gamecenter.retrofit.Response;
@ -58,11 +63,6 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import butterknife.BindView;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -71,6 +71,8 @@ import io.reactivex.schedulers.Schedulers;
* 查看游戏截图页面
*
* @author 黄壮华
*
* todo BigImageView静态webp/动态webp(ImageInfoExtractor.getImageType(image))判断有问题,导致部分静态webp无法使用缩放功能
*/
public class ViewImageActivity extends BaseActivity implements OnPageChangeListener {
@ -291,23 +293,23 @@ public class ViewImageActivity extends BaseActivity implements OnPageChangeListe
}
});
}
private void loadImage(String url, final BigImageView imageView) {
if (TextUtils.isEmpty(url)) return;
if (url.startsWith("data:image/png;base64")) {
AppExecutor.getIoExecutor().execute(() -> {
String base64String = url.replace("data:image/png;base64", "");
try {
File imageFile = new File(getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".png");
byte[] decodedString = Base64.decode(base64String, Base64.DEFAULT);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(imageFile));
bos.write(decodedString);
bos.flush();
bos.close();
AppExecutor.getUiExecutor().execute(() -> {
imageView.setImageViewFactory(new FrescoImageViewFactory());
imageView.showImage(Uri.fromFile(imageFile));
@ -323,7 +325,7 @@ public class ViewImageActivity extends BaseActivity implements OnPageChangeListe
}
}
private class ViewImageAdapter extends PagerAdapter implements OnSingleTapListener {
private class ViewImageAdapter extends PagerAdapter {
@Override
public int getCount() {
@ -476,11 +478,5 @@ public class ViewImageActivity extends BaseActivity implements OnPageChangeListe
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@Override
public void onSingleTap() {
finish();
}
}
}

View File

@ -86,6 +86,14 @@ public class WebActivity extends NormalActivity {
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
}
@NonNull
public static Intent getCopyrighyRulesIntent(Context context) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_GAMENAME, context.getString(R.string.copyright_title));
bundle.putString(EntranceUtils.KEY_URL, context.getString(R.string.copyright_rules_url));
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
}
@NonNull
public static Intent getSecurityCertificationIntent(Context context) {
Bundle bundle = new Bundle();
@ -168,6 +176,17 @@ public class WebActivity extends NormalActivity {
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
}
@NonNull
public static Intent getIntent(Context context, String url, String title, boolean autoCompletionTitle, boolean isOpenNativePage) {
Bundle bundle = new Bundle();
bundle.putString(EntranceUtils.KEY_URL, url);
bundle.putString(EntranceUtils.KEY_GAMENAME, title);
bundle.putBoolean(WebFragment.KEY_COMPLETION_TITLE, autoCompletionTitle);
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, false);
bundle.putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, isOpenNativePage);
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
}
@NonNull
public static Intent getIntentByUrl(Context context, String url) {
return getIntentByUrl(context, url, false);
@ -196,8 +215,13 @@ public class WebActivity extends NormalActivity {
@Override
protected View.OnClickListener provideNavigationItemClickListener() {
Bundle bundle = getIntent().getBundleExtra(NORMAL_FRAGMENT_BUNDLE);
if (bundle != null && bundle.getBoolean(WebFragment.KEY_ISTOOLS, false)) {
return view -> finish();
if (bundle != null) {
boolean isTools = bundle.getBoolean(WebFragment.KEY_ISTOOLS, false);
boolean isOpenNativePage = bundle.getBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, false);
if (isTools || isOpenNativePage) {
return view -> finish();
}
return super.provideNavigationItemClickListener();
} else {
return super.provideNavigationItemClickListener();
}

View File

@ -2,9 +2,6 @@ package com.gh.gamecenter.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
@ -41,6 +38,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.recyclerview.widget.LinearLayoutManager;
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;
@ -190,13 +190,21 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
linearLayoutManager.setStackFromEnd(true);
holder.libaoCodeRv.setLayoutManager(linearLayoutManager);
int count = (int) (((float) mLibaoEntity.getAvailable() / (float) mLibaoEntity.getTotal()) * 100);
float availablePercent = ((float) mLibaoEntity.getAvailable() / (float) mLibaoEntity.getTotal()) * 100;
int count;
if (availablePercent >= 1) {
count = (int) availablePercent;
} else if (availablePercent == 0) {
count = 0;
} else {
count = 1;
}
Spanned content = null;
String status = mLibaoEntity.getBeforeStatus();
if ("coming".equals(status) || "finish".equals(status) || TextUtils.isEmpty(status)) {
content = Html.fromHtml("剩余:--");
} else if ("ling".equals(status) || "linged".equals(status)) {
content = Html.fromHtml(StringUtils.buildString("剩余:", "<font color=\"#06D0A8\">", count + "%", "</font>"));
content = Html.fromHtml(StringUtils.buildString("剩余:", "<font color=\"#1383EB\">", count + "%", "</font>"));
} else if ("tao".equals(status) || "taoed".equals(status)) {
content = Html.fromHtml(StringUtils.buildString("剩余:", String.valueOf(count), "%"));
} else if ("used_up".equals(status)) {

View File

@ -496,7 +496,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
}
private void statNewsViews(final String news_id) {
RetrofitManager.getInstance(mContext).getData().postNewsViews(news_id)
RetrofitManager.getInstance(mContext).getApi().postArticleVisit(news_id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new JSONObjectResponse() {

View File

@ -1,557 +0,0 @@
package com.gh.gamecenter.adapter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
import com.gh.common.util.DataLogUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DeviceUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.DownloadDialogHelper;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.PackageHelper;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.VoteActivity;
import com.gh.gamecenter.adapter.viewholder.PlatformViewHolder;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.ApkLink;
import com.gh.gamecenter.entity.CollectionCloseEntity;
import com.gh.gamecenter.entity.GameCollectionEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.manager.PackagesManager;
import com.halo.assistant.HaloApp;
import com.lightgame.adapter.BaseRecyclerAdapter;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Util_System_Phone_State;
import com.lightgame.utils.Utils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.collection.ArrayMap;
/**
* Created by LGT on 2016/9/27.
*/
public class PlatformAdapter extends BaseRecyclerAdapter<PlatformViewHolder> {
private OnCollectionCallBackListener mOnCollectionCallBackListener; // 为空则是合集ViewPager
private List<ApkEntity> mPlatformList;
private ArrayMap<String, DownloadEntity> mEntryMap;
private SparseArray<PlatformAdapter> mAdapterMap;
private GameEntity mGameEntity;
private CollectionCloseEntity mCloseEntity;
private String mAutoDownloadPlatform;
private String mEntrance;
private String mLocation;
private ExposureEvent mTraceEvent;
private int mAdapterPosition;
private int mCount;
private final int mRow = 3;
private final int mColumn = 3;
public PlatformAdapter(Context context, OnCollectionCallBackListener listener, GameEntity gameEntity,
CollectionCloseEntity closeEntity, ArrayMap<String, DownloadEntity> eMap,
SparseArray<PlatformAdapter> aMap, List<ApkEntity> list, String entrance, String location,
int position, ExposureEvent traceEvent, String autoDownloadPlatform) {
super(context);
mOnCollectionCallBackListener = listener;
mGameEntity = gameEntity;
mCloseEntity = closeEntity;
mEntryMap = eMap;
mAdapterMap = aMap;
mPlatformList = list;
mEntrance = entrance;
mLocation = location;
mAdapterPosition = position;
mTraceEvent = traceEvent;
mAutoDownloadPlatform = autoDownloadPlatform;
if (mPlatformList.size() <= (mRow * mColumn)) {
mCount = mPlatformList.size();
} else if (mPlatformList.size() - (mRow * mColumn) * mAdapterPosition >= (mRow * mColumn)) {
mCount = (mRow * mColumn);
} else {
mCount = mPlatformList.size() - (mRow * mColumn) * mAdapterPosition;
}
}
@Override
public PlatformViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mLayoutInflater.inflate(R.layout.game_download_item, parent, false);
return new PlatformViewHolder(view);
}
@Override
public void onBindViewHolder(final PlatformViewHolder viewHolder, int position) {
final ApkEntity apkEntity = mPlatformList.get((mRow * mColumn) * mAdapterPosition + position);
if ("求版本".equals(apkEntity.getPackageName())) {
viewHolder.mDownloadItemIvPic.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvHint.setVisibility(View.GONE);
viewHolder.mDownloadItemProgressbar.setVisibility(View.GONE);
viewHolder.mDownloadItemTvName.setVisibility(View.GONE);
viewHolder.mDownloadItemTvStatus.setVisibility(View.GONE);
ImageUtils.display(viewHolder.mDownloadItemIvPic, R.drawable.platform_vote);
viewHolder.itemView.setBackgroundDrawable(new ColorDrawable(0));
viewHolder.itemView.setOnClickListener(v -> {
Intent intent = VoteActivity.getIntent(mContext, mGameEntity.getName(), mGameEntity.getId());
mContext.startActivity(intent);
});
return;
}
if (apkEntity.getApkCollection() == null) {
// 非合集
viewHolder.itemView.setOnClickListener(v -> {
ApkLink apkLink = apkEntity.getApkLink();
if (apkLink != null) {
String entrance = mEntrance + "(" + apkLink.getName() + ")";
DirectUtils.directToLinkPage(mContext, apkLink.getLinkEntity(), entrance, "下载多平台弹窗");
} else if (viewHolder.mDownloadItemTvStatus.getVisibility() == View.GONE) {
//下载游戏
DownloadDialogHelper.findAvailableDialogAndShow(mContext, mGameEntity, apkEntity, () -> {
DialogUtils.checkDownload(mContext, apkEntity.getSize(),
isSubscribe -> download(apkEntity, viewHolder.mDownloadItemTvStatus, "下载", isSubscribe));
});
DataLogUtils.uploadGameLog(mContext, mGameEntity.getId(), mGameEntity.getName(), mEntrance);
} else {
String status = viewHolder.mDownloadItemTvStatus.getText().toString();
switch (status) {
case "下载中":
case "等待中":
case "插件化下载中":
case "更新下载中":
case "插件化等待中":
case "更新等待中":
// 打开下载管理界面
mContext.startActivity(DownloadManagerActivity.getDownloadMangerIntent(mContext, apkEntity.getUrl()
, mEntrance + "(" + mLocation.split(":")[0] + ")"));
break;
case "已安装":
case "启动":
Map<String, Object> kv = new HashMap<>();
kv.put("版本", apkEntity.getPlatform());
DataUtils.onEvent(mContext, "游戏启动", mGameEntity.getName(), kv);
PackageUtils.launchApplicationByPackageName(mContext, apkEntity.getPackageName());
break;
case "安装":
case "安装更新":
install(apkEntity, viewHolder.getAdapterPosition());
break;
case "插件化":
DialogUtils.checkDownload(mContext, apkEntity.getSize(),
isSubscribe -> download(apkEntity, viewHolder.mDownloadItemTvStatus, "插件化", isSubscribe));
break;
case "安装插件":
showPluginDialog(apkEntity, PlatformAdapter.this, viewHolder.getAdapterPosition());
break;
case "更新":
DialogUtils.checkDownload(mContext, apkEntity.getSize(), isSubscribe -> update(apkEntity, isSubscribe));
break;
}
}
});
ApkLink apkLink = apkEntity.getApkLink();
if (apkLink != null) {
viewHolder.mDownloadItemIvPic.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvHint.setVisibility(View.GONE);
viewHolder.mDownloadItemTvName.setVisibility(View.GONE);
viewHolder.mDownloadItemTvStatus.setVisibility(View.GONE);
viewHolder.mDownloadItemProgressbar.setVisibility(View.GONE);
viewHolder.mDownloadItemTvHint.setText(apkLink.getName());
ImageUtils.display(viewHolder.mDownloadItemIvPic, apkLink.getIcon());
viewHolder.itemView.setBackgroundDrawable(new ColorDrawable(0));
} else {
Object gh_id = PackageUtils.getMetaData(mContext, apkEntity.getPackageName(), "gh_id");
if (PackageHelper.INSTANCE.getLocalPackageNameSet().contains(apkEntity.getPackageName())
&& (gh_id == null || gh_id.equals(mGameEntity.getId()))) {
// 已安装
viewHolder.mDownloadItemIvPic.setVisibility(View.GONE);
viewHolder.mDownloadItemTvHint.setVisibility(View.GONE);
viewHolder.mDownloadItemProgressbar.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvName.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvStatus.setVisibility(View.VISIBLE);
int color = Color.parseColor(PlatformUtils.getInstance(mContext)
.getPlatformColor(apkEntity.getPlatform()));
viewHolder.itemView.setBackgroundDrawable(getGradientDrawable(color));
viewHolder.mDownloadItemTvName.setTextColor(color);
viewHolder.mDownloadItemTvName.setText(PlatformUtils
.getInstance(mContext).getPlatformName(apkEntity.getPlatform()));
viewHolder.mDownloadItemProgressbar.setProgressDrawable(getLayerDrawable(color));
DownloadEntity downloadEntity = mEntryMap.get(apkEntity.getUrl());
if (downloadEntity == null) {
viewHolder.mDownloadItemProgressbar.setProgress(1000);
if (mGameEntity.getTag() != null && mGameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(mContext, apkEntity.getPackageName())
&& apkEntity.isShowPlugin(PluginLocation.only_game)) {
viewHolder.mDownloadItemTvStatus.setText(R.string.pluggable);
downloadEntity = DownloadManager.getInstance(mContext).getDownloadEntityByPackageName(apkEntity.getPackageName());
if (downloadEntity == null
|| downloadEntity.getUrl().equals(apkEntity.getUrl())) {
viewHolder.itemView.setClickable(true);
viewHolder.mDownloadItemProgressbar.setProgress(1000);
} else {
viewHolder.itemView.setClickable(false);
viewHolder.mDownloadItemProgressbar.setProgress(0);
}
} else if (PackagesManager.INSTANCE.isCanUpdate(mGameEntity.getId(), apkEntity.getPackageName())) {
viewHolder.mDownloadItemTvStatus.setText(R.string.update);
} else {
boolean isFilter = false;
SettingsEntity settings = Config.getSettings();
if (settings != null) {
for (String pkgName : settings.getGameDownloadBlackList()) {
if (pkgName.equals(apkEntity.getPackageName())) {
isFilter = true;
}
}
}
if (isFilter) {
viewHolder.mDownloadItemTvStatus.setText("已安装");
} else {
viewHolder.mDownloadItemTvStatus.setText(R.string.launch);
}
}
} else {
viewHolder.mDownloadItemProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (downloadEntity.isPluggable()) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
viewHolder.mDownloadItemTvStatus.setText("安装插件");
} else if (downloadEntity.getStatus().equals(DownloadStatus.subscribe)) {
viewHolder.mDownloadItemTvStatus.setText("插件化等待中");
} else {
viewHolder.mDownloadItemTvStatus.setText("插件化下载中");
}
} else if (downloadEntity.isUpdate()) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
viewHolder.mDownloadItemTvStatus.setText("安装更新");
} else if (downloadEntity.getStatus().equals(DownloadStatus.subscribe)) {
viewHolder.mDownloadItemTvStatus.setText("更新等待中");
} else {
viewHolder.mDownloadItemTvStatus.setText("更新下载中");
}
}
}
} else {
// 未安装
DownloadEntity downloadEntity = mEntryMap.get(apkEntity.getUrl());
if (downloadEntity == null
|| downloadEntity.getStatus().equals(DownloadStatus.cancel)
|| downloadEntity.getStatus().equals(DownloadStatus.hijack)
|| downloadEntity.getStatus().equals(DownloadStatus.notfound)) {
String path = PlatformUtils.getInstance(mContext)
.getPlatformPicUrl(apkEntity.getPlatform());
viewHolder.mDownloadItemIvPic.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvHint.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvName.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvStatus.setVisibility(View.GONE);
viewHolder.mDownloadItemProgressbar.setVisibility(View.GONE);
viewHolder.itemView.setBackgroundColor(0x00ffffff);
viewHolder.mDownloadItemTvHint.setText(
PlatformUtils.getInstance(mContext).getPlatformName(apkEntity.getPlatform()));
if (TextUtils.isEmpty(path)) {
int id = PlatformUtils.getInstance(mContext).getPlatformPic(
apkEntity.getPlatform());
ImageUtils.display(viewHolder.mDownloadItemIvPic, id);
} else {
ImageUtils.displayIcon(viewHolder.mDownloadItemIvPic, path);
}
} else {
viewHolder.mDownloadItemIvPic.setVisibility(View.GONE);
viewHolder.mDownloadItemTvHint.setVisibility(View.GONE);
viewHolder.mDownloadItemProgressbar.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvName.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvStatus.setVisibility(View.VISIBLE);
int color = Color.parseColor(PlatformUtils.getInstance(
mContext).getPlatformColor(apkEntity.getPlatform()));
viewHolder.itemView.setBackgroundDrawable(getGradientDrawable(color));
viewHolder.mDownloadItemTvName.setTextColor(color);
viewHolder.mDownloadItemTvName.setText(PlatformUtils
.getInstance(mContext).getPlatformName(apkEntity.getPlatform()));
viewHolder.mDownloadItemProgressbar.setProgressDrawable(getLayerDrawable(color));
viewHolder.mDownloadItemProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
DownloadStatus status = downloadEntity.getStatus();
if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.timeout)
|| status.equals(DownloadStatus.neterror)
|| status.equals(DownloadStatus.downloading)
|| status.equals(DownloadStatus.waiting)
|| status.equals(DownloadStatus.overflow)) {
viewHolder.mDownloadItemTvStatus.setText(R.string.downloading);
} else if (status.equals(DownloadStatus.done)) {
viewHolder.mDownloadItemTvStatus.setText(R.string.install);
} else if (status.equals(DownloadStatus.subscribe)) {
viewHolder.mDownloadItemTvStatus.setText(R.string.waiting);
}
}
}
}
if (!TextUtils.isEmpty(mAutoDownloadPlatform) && mAutoDownloadPlatform.equals(apkEntity.getPlatform())) {
mAutoDownloadPlatform = null;
DialogUtils.checkDownload(mContext, apkEntity.getSize(),
isSubscribe -> download(apkEntity, viewHolder.mDownloadItemTvStatus, "下载", isSubscribe));
}
} else {
// 合集
viewHolder.mDownloadItemIvPic.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvHint.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvName.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemTvStatus.setVisibility(View.GONE);
viewHolder.mDownloadItemProgressbar.setVisibility(View.GONE);
viewHolder.itemView.setBackgroundColor(0x00ffffff);
viewHolder.mDownloadItemTvHint.setText(apkEntity.getApkCollection().getName());
ImageUtils.displayIcon(viewHolder.mDownloadItemIvPic, apkEntity.getApkCollection().getIcon());
if (mCloseEntity.getPosition() == position && mAdapterPosition == mCloseEntity.getAdapterPosition()) {
viewHolder.mDownloadItemOpenCollection.setVisibility(View.GONE);
viewHolder.mDownloadItemColseCollection.setVisibility(View.VISIBLE);
} else {
viewHolder.mDownloadItemOpenCollection.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemColseCollection.setVisibility(View.GONE);
}
viewHolder.itemView.setOnClickListener(v -> {
if (viewHolder.mDownloadItemOpenCollection.getVisibility() == View.VISIBLE) {
if (mOnCollectionCallBackListener != null) {
mOnCollectionCallBackListener.showCollection(apkEntity.getApkCollection());
}
mCloseEntity.setPosition(viewHolder.getAdapterPosition());
mCloseEntity.setAdapterPosition(mAdapterPosition);
for (int[] ints : mCloseEntity.getList()) {
mAdapterMap.get(ints[0]).notifyItemChanged(ints[1]);
}
mCloseEntity.getList().clear();
int[] arrCollectionPosition = {mAdapterPosition, viewHolder.getAdapterPosition()};
mCloseEntity.getList().add(arrCollectionPosition);
viewHolder.mDownloadItemOpenCollection.setVisibility(View.GONE);
viewHolder.mDownloadItemColseCollection.setVisibility(View.VISIBLE);
} else {
if (mOnCollectionCallBackListener != null) {
mOnCollectionCallBackListener.hideCollection();
}
mCloseEntity.setPosition(-1);
mCloseEntity.setAdapterPosition(-1);
viewHolder.mDownloadItemOpenCollection.setVisibility(View.VISIBLE);
viewHolder.mDownloadItemColseCollection.setVisibility(View.GONE);
}
});
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (!TextUtils.isEmpty(mAutoDownloadPlatform) && apkCollection != null &&
apkCollection.getSaveApkEntity() != null) {
for (ApkEntity entity : apkCollection.getSaveApkEntity()) {
if (mAutoDownloadPlatform.equals(entity.getPlatform())) {
viewHolder.itemView.performClick();
mAutoDownloadPlatform = null;
break;
}
}
}
}
}
@Override
public int getItemCount() {
return mCount;
}
// 下载游戏
public void download(ApkEntity apkEntity, TextView mDownloadItemTvStatus, String method, boolean isSubscribe) {
String msg = FileUtils.isCanDownload(mContext, apkEntity.getSize());
if (TextUtils.isEmpty(msg)) {
String platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(apkEntity.getPlatform());
Map<String, Object> kv = new HashMap<>();
kv.put("游戏", mGameEntity.getName() + ":" + platform);
kv.put("用户机型", Build.MODEL);
kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
kv.put("位置", mEntrance);
kv.put("类型", method);
kv.put("厂商", Build.MANUFACTURER);
kv.put("Android版本", Build.VERSION.RELEASE);
DataUtils.onEvent(mContext, "游戏下载", mGameEntity.getName(), kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("版本", apkEntity.getPlatform() + "-开始");
kv2.put("状态", "下载开始");
kv2.put("位置", mEntrance + "-开始");
kv2.put("游戏分平台", mGameEntity.getName() + ":" + platform + "-开始");
kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
DataUtils.onEvent(mContext, "游戏下载位置", mGameEntity.getName(), kv2);
Map<String, Object> kv6 = new HashMap<>();
kv6.put("下载", "下载开始");
kv6.put("版本", apkEntity.getPlatform());
ExposureUtils.DownloadType downloadType;
if ("插件化".equals(method)) {
DataUtils.onEvent(mContext, "插件化", mGameEntity.getName(), kv6);
DataUtils.onMtaEvent(mContext, "插件化_新", "位置", mEntrance, "游戏", mGameEntity.getName() + "-" + platform, "操作", "下载开始", "网络状态", DeviceUtils
.getNetwork(HaloApp.getInstance().getApplication()));
downloadType = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD;
} else {
downloadType = ExposureUtils.DownloadType.DOWNLOAD;
}
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(mGameEntity, apkEntity
.getPlatform(), mTraceEvent, downloadType);
DownloadManager.createDownload(mContext, apkEntity, mGameEntity, method, mEntrance, mLocation, isSubscribe, downloadExposureEvent);
// DownloadManager.getInstance(mContext).putStatus(apkEntity.getUrl(), "downloading");
if (isSubscribe) {
mDownloadItemTvStatus.setText(R.string.waiting);
} else {
mDownloadItemTvStatus.setText(R.string.downloading);
}
} else {
Utils.toast(mContext, msg);
}
}
//安装游戏
private void install(ApkEntity apkEntity, int position) {
DownloadEntity downloadEntity = mEntryMap.get(apkEntity.getUrl());
if (downloadEntity != null) {
if (downloadEntity.isPluggable()) {
Map<String, Object> kv = new HashMap<>();
kv.put("操作", "点击安装完成");
DataUtils.onEvent(mContext, "插件化", downloadEntity.getName(), kv);
}
DataUtils.onMtaEvent(mContext,
"插件化_新",
"位置", mEntrance,
"游戏", mGameEntity.getName() + "-" + apkEntity.getPlatform(),
"操作", "点击安装",
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
String path = downloadEntity.getPath();
if (FileUtils.isEmptyFile(path)) {
Utils.toast(mContext, R.string.install_failure_hint);
mEntryMap.remove(apkEntity.getUrl());
DownloadManager.getInstance(mContext).cancel(apkEntity.getUrl());
notifyItemChanged(position);
} else {
PackageUtils.launchSetup(mContext, downloadEntity);
}
}
}
// 显示插件化
private void showPluginDialog(final ApkEntity apkEntity, final PlatformAdapter adapter, final int location) {
DialogUtils.showPluginDialog(mContext, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
Map<String, Object> kv6 = new HashMap<>();
kv6.put("操作", "点击插件化安装完成");
DataUtils.onEvent(mContext, "插件化", mGameEntity.getName(), kv6);
DataUtils.onMtaEvent(mContext,
"插件化_新",
"位置", mEntrance,
"游戏", mGameEntity.getName() + "-" + apkEntity.getPlatform(),
"操作", "点击插件化",
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
DownloadEntity downloadEntity = mEntryMap.get(apkEntity.getUrl());
if (downloadEntity == null) return;
String path = downloadEntity.getPath();
if (FileUtils.isEmptyFile(path)) {
Utils.toast(mContext, R.string.install_failure_hint);
mEntryMap.remove(apkEntity.getUrl());
DownloadManager.getInstance(mContext).cancel(apkEntity.getUrl());
adapter.notifyItemChanged(location);
} else {
mContext.startActivity(PackageUtils.getUninstallIntent(mContext, path));
}
}
});
}
// 下载可更新游戏
private void update(ApkEntity apkEntity, boolean isSubscribe) {
Map<String, Object> kv = new HashMap<>();
kv.put("版本", apkEntity.getPlatform());
kv.put("状态", "下载开始");
DataUtils.onEvent(mContext, "游戏更新", mGameEntity.getName(), kv);
ExposureUtils.DownloadType downloadType = ExposureUtils.getUpdateType(apkEntity);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(mGameEntity, apkEntity.getPlatform(), mTraceEvent, downloadType);
DownloadManager.createDownload(mContext, apkEntity, mGameEntity, "更新", mEntrance, mLocation, isSubscribe, downloadExposureEvent);
}
private GradientDrawable getGradientDrawable(int color) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.WHITE);
gradientDrawable.setStroke(DisplayUtils.dip2px(mContext, 1), color);
return gradientDrawable;
}
private LayerDrawable getLayerDrawable(int color) {
Drawable[] layers = new Drawable[2];
GradientDrawable drawable = new GradientDrawable();
drawable.setColor(0xFFC7C7C7);
layers[0] = drawable;
ClipDrawable clipDrawable = new ClipDrawable(new ColorDrawable(color), Gravity.LEFT, ClipDrawable.HORIZONTAL);
layers[1] = clipDrawable;
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.progress);
return layerDrawable;
}
}

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