Compare commits

...

257 Commits

Author SHA1 Message Date
ef6a2c58ff tinker_base-4.0.2 2020-07-09 10:28:15 +08:00
2aa41661a2 首页横向专题备注默认隐藏 2020-07-09 09:49:24 +08:00
e326f072d2 视频合集用户信息扩大点击区域 2020-07-08 14:29:59 +08:00
f53cc18ab6 修改启动页调用获取设备弹窗接口错误 2020-07-08 10:38:54 +08:00
723a504d7c 开发环境不主动捕获RxJava抛出的异常 2020-07-08 10:23:21 +08:00
dab48607e8 修改文案 2020-07-08 09:59:23 +08:00
3ee69146bb 光环助手V4.0.2-视频上传与编辑功能优化(20200707测试补充 1) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/887 2020-07-08 09:57:33 +08:00
ca86a66b14 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-07-07 18:26:51 +08:00
c92bdd3014 修复首页竖向专题下载进度无法刷新问题 2020-07-07 18:26:35 +08:00
0be23f26f2 修复自定义栏目正文高亮文字点击提示复制成功的问题 2020-07-07 18:12:23 +08:00
6ce4592e5e 修改分享事件上报 2020-07-07 17:49:20 +08:00
92caedb011 光环助手V4.0.2-视频上传与编辑功能优化(20200707测试补充 3,5)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/887 2020-07-07 16:48:45 +08:00
f796411fa8 光环助手V4.0.2-视频上传与编辑功能优化(20200707测试补充 1,2,4)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/887 2020-07-07 16:06:38 +08:00
d45f185f77 处理分享数据未上传问题 2020-07-07 15:03:54 +08:00
10028dfebc 视频浏览记录、视频收藏列表扩大用户信息点击区域 2020-07-07 14:41:00 +08:00
fa06795cef Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-07-06 16:55:45 +08:00
c1eb324d79 分享功能数据埋点 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/919 2020-07-06 16:55:39 +08:00
cdf9528583 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-07-06 15:10:26 +08:00
5f5a621bd1 光环助手V4.0.2-视频上传与编辑功能优化(20200703测试补充1,2,3,5,6) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/887 2020-07-06 15:10:10 +08:00
b8d54dfa59 更新依赖库 hash 2020-07-06 11:55:37 +08:00
b4f39d09e4 Merge branch 'intergrate-antibot-sdk' into 'dev'
集成反爬虫SDK

See merge request halo/assistant-android!18
2020-07-06 11:47:52 +08:00
a3aea6259c 光环助手V4.0.2 RELEASE(20200629-2330)测试汇总20200703测试问题(1) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/914 2020-07-03 15:31:32 +08:00
73e4c90956 恢复 chucker 2020-07-03 12:02:46 +08:00
c1432159f3 修复前台启动也会显示光环助手正在运行中的问题 2020-07-03 11:59:44 +08:00
45f47d98ba 补充部分遗漏的接口 2020-07-03 10:13:00 +08:00
2e9638b8c5 光环助手V4.0.2 RELEASE(20200629-2330)测试汇总(8,9) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/914 2020-07-03 09:42:25 +08:00
7ea30c1d0e 修改 keep 规则 2020-07-02 18:09:26 +08:00
034e04944a 调整API_HOST 2020-07-02 17:51:48 +08:00
99326596d5 接入阿里反爬虫 SDK https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/915 2020-07-02 17:39:51 +08:00
1cc2b85816 光环助手V4.0.2-开服日历表优化(20200702需求补充) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/893 2020-07-02 17:12:37 +08:00
f4cd9419a4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-07-02 15:56:35 +08:00
a24b9d92c7 WebFragment页面支持js打开分享弹窗 2020-07-02 15:56:29 +08:00
8e7e83ad72 处理link跳转使用jumpActivity方式 2020-07-02 15:37:14 +08:00
cd810f0048 光环助手V4.0.2-游戏专题功能强化(前端)20200701优化补充(2,3,4) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885 2020-07-02 14:52:25 +08:00
fa050039cd 暂时停用chucker 2020-07-02 11:09:07 +08:00
935fb1149f DsBridge 转为本地依赖,暂时停用chucker(jitpack连不上) 2020-07-02 11:03:34 +08:00
951817455a 修复游戏列表评分数值字体大小不一问题 2020-07-01 18:22:53 +08:00
e71e7f6163 处理系统消息link不显示 2020-07-01 10:07:21 +08:00
09be5e157d 修复去掉游戏详情富文本正文换行符时会切掉最后一个字符的问题 2020-06-30 17:33:59 +08:00
1f5e59fc1d 处理系统推送列表link显示 2020-06-30 17:14:10 +08:00
e58861afa4 处理系统推送title为空问题 2020-06-30 16:47:36 +08:00
44e51ecb0a 补充一些代码注释 2020-06-30 15:10:59 +08:00
794c17a1bb 恢复误删的带 chucker 测试环境编译代码 2020-06-30 15:08:49 +08:00
1b287962f0 完成将镜像游戏隐藏的自定义栏目放置于详细信息之后的功能 2020-06-30 15:07:53 +08:00
8bdf98b9d8 修改游戏专题大图link跳转问题 2020-06-30 14:27:55 +08:00
e1aeb61c9b Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-30 10:56:28 +08:00
a39a70ac2d 修复游戏列表和游戏详情评分数值不一致的问题 2020-06-30 10:56:22 +08:00
4fdcaaf591 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-30 00:07:04 +08:00
b4502638ff 修改光环助手V4.0.2-链接跳转做成通用模块bug 2020-06-30 00:07:00 +08:00
05502d56b1 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-29 22:54:31 +08:00
90e1e8a40f 修复游戏列表和游戏详情评分数值不一致的问题 2020-06-29 22:54:26 +08:00
b10293da50 镜像游戏去掉大家都在玩 2020-06-29 22:50:43 +08:00
83cf0687e6 修复一些闪退问题 2020-06-29 22:32:15 +08:00
f56b03716a 我的光环进入游戏投稿前请求权限 2020-06-29 21:45:41 +08:00
61a41e6039 修复游戏详情游戏简介的显示异常 2020-06-29 21:02:03 +08:00
20ae9fe0ec 补充镜像游戏的镜像下载选项 2020-06-29 20:51:36 +08:00
74fdec9d72 UI优化 2020-06-29 19:31:51 +08:00
3437265cc1 Merge branches 'dev' and 'dev' of gitlab.ghzs.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescAdapter.kt
2020-06-29 19:08:36 +08:00
271993a876 光环助手V4.0.2-链接跳转做成通用模块0629测试1(2),2(1),5(3),9(2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/879 2020-06-29 19:06:28 +08:00
3a8b7bb920 视频上传时把是否勾选"视频上传服务准则"的判断放到最后 2020-06-29 17:52:37 +08:00
fd85f3889d 修复镜像游戏的预约状态问题 2020-06-29 17:05:01 +08:00
556ecea749 修复游戏详情游戏简介的换行问题 2020-06-29 17:04:33 +08:00
8a97844676 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-29 16:58:06 +08:00
f152296e7a 游戏列表评分数值与游戏详情统一 2020-06-29 16:57:59 +08:00
4ccc789c7c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-29 16:09:55 +08:00
747b02eb7a 处理视频流内存泄漏问题 2020-06-29 16:09:50 +08:00
a73c033c03 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-29 15:57:59 +08:00
939db8c820 光环助手V4.0.2-游戏专题功能强化(前端)(20200629UI测试) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885 2020-06-29 15:57:54 +08:00
8601440d97 修复接口环境标识文字造成的显示问题 2020-06-29 15:12:48 +08:00
7a1fa90175 测试包右上角添加接口环境标识文字 2020-06-29 12:36:41 +08:00
46722ba69d 测试包右上角添加接口环境标识文字 2020-06-29 12:03:37 +08:00
70d9d461bf 更换web编辑器图标 2020-06-29 11:03:52 +08:00
91944df6a4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-29 10:59:40 +08:00
ef86c1158c 尝试修复Tab专题页面Fragment回收后无法重建的问题 2020-06-29 10:59:36 +08:00
0f3b6ed34b 镜像游戏去掉镜像标签中的特殊标签 2020-06-29 10:26:52 +08:00
8b50620ddc SpanBuilder的image方法使用application,避免出现内存泄漏 2020-06-29 10:12:39 +08:00
8b2a9eb6ca 我的收藏ui优化 2020-06-29 09:54:27 +08:00
7297f5480e 修改意见反馈文案 2020-06-28 19:58:41 +08:00
3bee8cc034 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-28 18:56:12 +08:00
584a16e111 上传视频流浏览记录 2020-06-28 18:55:25 +08:00
6460c7f8d6 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-28 18:24:15 +08:00
feb99c9f78 光环助手V4.0.2-开服日历表优化(20200628UI测试) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/893 2020-06-28 18:24:09 +08:00
68ac809bcb 恢复误删的华为离线推送配置 2020-06-28 17:58:35 +08:00
de207f66d9 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-28 17:53:09 +08:00
054fcd2049 修正横向专题第一行文案标红规则 2020-06-28 17:52:45 +08:00
497fc998fe 修复通知栏推送的跳转问题 2020-06-28 17:16:56 +08:00
03f76453ab 更正错误的游戏镜像判断规则 2020-06-28 15:57:55 +08:00
0a87bd354a 修复首次启动时根据 gid 获取已下载的游戏列表失败的问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/880 2020-06-28 15:13:36 +08:00
1baceaef15 光环助手V4.0.2-多版本下载面板:合集插件化提示 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/907 2020-06-28 10:50:28 +08:00
9719a7fa28 微调视频上传页面UI 2020-06-28 09:39:41 +08:00
1718a66126 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-24 18:21:38 +08:00
b317ef3a39 fix bug 2020-06-24 18:21:29 +08:00
8b0cd69ae6 DownloadService 的前台通知增加 channelId 避免在部分国产 ROM 上显示不出来 2020-06-24 16:50:33 +08:00
c7126e9836 处理一些内存泄漏问题 2020-06-24 15:33:53 +08:00
f3d01335a4 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-24 15:07:01 +08:00
88e029b129 修复多平台下载面板-我的版本出现的未知类型 2020-06-24 15:06:54 +08:00
2bc72328c1 修复一些闪退异常 2020-06-24 14:45:44 +08:00
81179b1f72 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-24 11:54:59 +08:00
9a7d4997c2 修改更新弹窗文案 2020-06-24 11:54:53 +08:00
3b6ac881c2 正式环境api地址更新至4.0.2 2020-06-24 11:33:14 +08:00
6b5fb7d8bc Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-24 10:47:42 +08:00
1551b0a358 测试环境App更新为了方便测试写死下载链接(测试环境的包链接是不可用的) 2020-06-24 10:47:35 +08:00
6540af8386 适配居中显示文字的渐隐文字颜色 2020-06-24 10:29:24 +08:00
9badcdc382 插件意见反馈跳转协议新增参数 2020-06-24 10:05:14 +08:00
0ba94fa56f 插件意见反馈跳转协议新增参数 2020-06-24 09:51:46 +08:00
52c1343ade 光环助手V4.0.2-视频上传与编辑功能优化(20200623测试1,4) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/887 2020-06-23 21:14:00 +08:00
7a0e633b79 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-23 20:53:46 +08:00
9b68b05d7d 光环助手V4.0.2-更新推送功能优化(20200619补充)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/882 2020-06-23 20:53:41 +08:00
9e7f6b0854 处理一些内存泄漏问题 2020-06-23 20:34:47 +08:00
cf20ad6fc2 修复曝光类型下载上报类型错误问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/884 2020-06-23 19:42:56 +08:00
cb7bdba338 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-23 18:13:58 +08:00
f1fc06ca84 游戏上传接口更改 2020-06-23 18:13:52 +08:00
18f9fe7fcf 游戏详情自定义栏目渐隐文字支持颜色继承 2020-06-23 17:51:28 +08:00
18816a8a4e Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-23 17:15:24 +08:00
8d379501cb 光环助手V4.0.2-游戏上传功能优化20200623测试1,2,4 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/903 2020-06-23 17:15:18 +08:00
8f4c6abfd3 游戏详情自定义栏目富文本正文兼容低版本安卓系统 2020-06-23 16:44:28 +08:00
a24d0a9618 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-23 14:44:24 +08:00
8cdd66cd89 光环前端优化汇总(2020年6月第2周)0622测试:7(2) 9/10(1) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/895 2020-06-23 14:44:17 +08:00
3fd34576e8 更改游戏详情的自定义栏目富文本正文的展开实现 2020-06-23 11:58:27 +08:00
78d5cbcc42 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-23 10:43:40 +08:00
803f2bef75 修改新增开服的默认时间选择规则->开服表的选择时间(yyyy-MM-dd)+当前时间(HH:mm) 2020-06-23 10:43:33 +08:00
40c7e8f9e6 处理一些内存泄漏问题 2020-06-23 10:31:35 +08:00
b3c5ca6112 光环助手V4.0.2-意见反馈增加 版权申诉20200622测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/904 2020-06-22 18:22:20 +08:00
31067ea66d 光环助手V4.0.2-意见反馈增加 版权申诉 20200622UI测试 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/904 2020-06-22 18:05:31 +08:00
4e7626ff41 游戏上传UI优化 2020-06-22 17:50:58 +08:00
e62822505e urlscheme增加游戏上传 2020-06-22 17:02:28 +08:00
cbc705d1eb Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-22 16:05:40 +08:00
aa2e147a51 光环助手V4.0.2-游戏上传功能优化(20200622测试 1-5,7-9,15) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/903 2020-06-22 16:05:34 +08:00
6249726839 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-22 16:05:04 +08:00
8f4bc5a164 修复游戏专题在部分情况游戏摘要无法控制的问题 2020-06-22 16:04:53 +08:00
eee459d08a 修复自定义栏目富文本正文的收起异常 2020-06-22 15:55:09 +08:00
81b4e40dbf Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-22 11:51:26 +08:00
261068e286 处理视频数据统计异常问题 2020-06-22 11:51:21 +08:00
84364a7c66 修复模拟器上游戏详情自定义栏目圆形头像导致闪退的问题 2020-06-22 10:52:58 +08:00
3beb47a8be 避免周期性任务在其它进程触发 2020-06-22 10:11:28 +08:00
ca76af4474 避免周期性任务在其它进程触发 2020-06-22 09:55:43 +08:00
bc33673533 完成MTA的AppKey替换和不需要事件的移除 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/910 2020-06-22 09:54:28 +08:00
c5d038a173 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-19 17:57:50 +08:00
b1e492df1b 修复APP更新弹窗点击弹窗边缘无法取消弹窗问题 2020-06-19 17:57:42 +08:00
9d9c213af7 修复插件化更新曝光事件没有附上版本号的问题 2020-06-19 17:25:46 +08:00
d3f97ea527 更新 leakCanary 2020-06-19 17:24:58 +08:00
0a5fb4cb1d Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-19 17:03:19 +08:00
6905f7191a 修复一些闪退问题 2020-06-19 17:03:11 +08:00
bad7fb4922 游戏详情自定义栏目正文里的用户头像裁成圆形 2020-06-19 16:41:38 +08:00
250fa7eb7b Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-19 16:22:03 +08:00
f0cd8567cb 1.增加视频流浏览记录表用于日志上传 2.视频流增加计时器 2020-06-19 16:21:58 +08:00
f6dd35e4b8 回答、文章web编辑器字数监听 2020-06-19 15:02:18 +08:00
2dc299e7f4 游戏投稿包名去掉后缀apk 2020-06-19 11:01:13 +08:00
366e8ded14 完成"下载数据统计需求"的0618测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/884 2020-06-19 09:35:32 +08:00
8175742143 完成"下载数据统计需求"的0618测试问题 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/884 2020-06-18 18:20:52 +08:00
fc858f1272 删除无用的多版本图片 2020-06-18 18:20:18 +08:00
84b668714b Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-18 17:53:58 +08:00
5ea5346ee8 修改我的光环小红点规则 2020-06-18 17:53:53 +08:00
c2eb0b267c 完成"首页插件化提示区域优化"的红点优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/898 2020-06-18 17:32:17 +08:00
7fb502e87e Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-18 17:27:24 +08:00
98726ddc3a 修改我的光环小红点规则 2020-06-18 17:27:20 +08:00
75ff76acf4 评论详情间距优化 2020-06-18 17:13:14 +08:00
ba552812a3 游戏详情自定义栏目正文内容支持用户头像 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/891 2020-06-18 14:53:29 +08:00
83bfeb0abc 修复一些闪退问题 2020-06-18 14:31:26 +08:00
70f1b7a678 游戏开服的新增取最后一条开服数据作为模板 2020-06-18 11:07:33 +08:00
455d53fee0 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-18 10:55:16 +08:00
39e4b5bf55 20200616测试问题:1 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/893 2020-06-18 10:55:00 +08:00
40a729b6f8 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-18 10:40:26 +08:00
9643176e06 光环助手V4.0.2-意见反馈增加 版权申诉 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/904 2020-06-18 10:40:21 +08:00
1a70c33bef Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-18 10:25:45 +08:00
888ebe5f54 光环助手V4.0.2-多版本下载面板:合集插件化提示 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/907 2020-06-18 10:25:39 +08:00
cb02dbae57 游戏分地区配置添加网络状态切换重试 2020-06-18 09:43:51 +08:00
2683d02dcd Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-17 18:32:38 +08:00
ceb924e8f1 微调UI 2020-06-17 18:32:19 +08:00
bd91609a80 补充数据库升级配置 2020-06-17 18:31:39 +08:00
2fd74a4698 Merge remote-tracking branch 'origin/dev' into dev 2020-06-17 18:21:07 +08:00
e9e0d3b43e 基本完成游戏分地区管理供嗯 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/900 2020-06-17 18:20:59 +08:00
17e09ddad3 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-17 18:18:00 +08:00
65427c55d6 修改游戏投稿 2020-06-17 18:17:55 +08:00
7f99f75c6f Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-17 17:39:10 +08:00
548aea8d13 光环助手V4.0.2-首页插件化提示区域优化(除4.4外,其它完成) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/898 2020-06-17 17:39:05 +08:00
a177137744 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-17 16:50:52 +08:00
3c6443d78f 版权申诉UI 2020-06-17 16:50:47 +08:00
ba81ed9cb0 完成游戏镜像功能 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/899 2020-06-17 15:19:48 +08:00
6a1cbd10c6 光环助手V4.0.2-游戏上传功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/903 2020-06-17 11:25:40 +08:00
7e9ac0c4f1 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-16 17:26:10 +08:00
fe889639b3 游戏投稿(未完) 2020-06-16 17:26:05 +08:00
848e43af28 首页相关接口增加channel参数 2020-06-16 14:18:49 +08:00
c7a3893fae 修复虚拟按键遮挡启动图的问题 2020-06-16 11:51:51 +08:00
f7d633188c 光环助手V4.0.2-更新推送功能优化(3)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/882 2020-06-16 10:59:11 +08:00
e1e7d2d3d6 修复版块轮播图的曝光统计缺失问题 2020-06-15 18:18:43 +08:00
2b8a280768 移除无用代码 2020-06-15 18:18:08 +08:00
6efe96eb0d 微调UI 2020-06-15 18:06:33 +08:00
3562fe9273 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-15 16:29:04 +08:00
739ef44a8b 光环助手V4.0.2-开服日历表优化(1)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/893 2020-06-15 16:27:51 +08:00
879b42dbf2 修复游戏详情自定义栏目正文描述的显示问题 2020-06-15 15:02:43 +08:00
fae626bb98 移除下载限速相关的无用代码 2020-06-15 15:01:47 +08:00
cebd639d78 处理视频流全屏播放时点击返回键关闭页面问题 2020-06-15 11:32:35 +08:00
17a99a1cda 微调专题过滤选项UI 2020-06-15 10:50:02 +08:00
2a03683e1e 修改游戏专题平铺样式UI 2020-06-15 10:34:00 +08:00
a579b3fe10 修复游戏详情闪退问题 2020-06-15 09:33:51 +08:00
9c75dd18df Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-12 18:30:12 +08:00
cdc9c86852 光环助手V4.0.2-游戏专题功能强化(前端)(7) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885
修改专题详情游戏列表UI
修改多行类型专题控制选项UI(包换标签详情和分类详情)
2020-06-12 18:30:04 +08:00
fab1851436 完成自定义栏目优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/891 2020-06-12 11:54:04 +08:00
a6704e46a9 微调游戏列表UI 2020-06-12 11:49:19 +08:00
e188f70eb6 Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-12 10:54:24 +08:00
02dd115886 移除游戏列表礼包图标相关代码
修复开服表闪退问题
2020-06-12 10:54:19 +08:00
5cbfc7b461 游戏评论、撰写问答、撰写文章toast居中显示 2020-06-12 10:43:48 +08:00
b4742b5645 更换富文本编辑器图标 2020-06-12 09:36:22 +08:00
5ec25475ea Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-11 18:34:20 +08:00
c58040ef83 光环助手V4.0.2-游戏专题功能强化(前端)(1,2,3,4,5,6) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885 2020-06-11 18:34:10 +08:00
75701b6875 游戏详情自定义栏目支持富文本 2020-06-11 18:29:44 +08:00
2155a33689 处理个人主页文章关闭评论显示问题 2020-06-11 15:21:05 +08:00
68a9d5d771 微调UI 2020-06-11 11:51:35 +08:00
ebf6107faf Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-10 18:19:43 +08:00
e4bc36a743 光环前端优化汇总(2020年6月第2周)2-6,8,13 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/895 2020-06-10 18:19:37 +08:00
7a64251811 Merge branch 'update_push_sdk' into 'dev'
Update push sdk

See merge request halo/assistant-android!17
2020-06-10 18:13:12 +08:00
65409d75a7 统一测试环境和正式环境的推送配置 2020-06-10 18:08:49 +08:00
d40081d58b Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-10 16:34:46 +08:00
f276e981ed 光环助手V4.0.2-游戏专题功能强化(前端)(11)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885 2020-06-10 16:34:42 +08:00
e50db66b47 光环助手V4.0.2-游戏评论功能优化4,5 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/892 2020-06-10 15:06:16 +08:00
fc84022852 微调UI 2020-06-10 11:43:21 +08:00
b593f2f3ea 微调UI 2020-06-09 18:21:29 +08:00
e782d0542c Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-09 17:59:28 +08:00
1a085cad98 光环助手V4.0.2-开服日历表优化2(3) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/893
修复开服备注字数过多产生的UI显示异常问题
2020-06-09 17:59:22 +08:00
1c33a0c4c5 去掉评论数为0时,点击评论内容卡片自动弹出键盘的功能 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/892 2020-06-09 17:36:36 +08:00
3c4a7961c2 处理EllipsizeTextView省略号不显示问题 2020-06-09 16:37:48 +08:00
712f9b84cf 简单升级推送SDK,离线推送还有很多问题 2020-06-09 16:08:19 +08:00
2efb7b76cc Merge branch 'dev' of gitlab.ghzs.com:halo/assistant-android into dev 2020-06-09 15:45:25 +08:00
5c4d93ce15 光环助手V4.0.2-视频上传与编辑功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/887 2020-06-09 15:45:16 +08:00
7addd92058 处理滑动视频流播放问题 2020-06-09 14:40:12 +08:00
82c5898b9a 光环助手V4.0.2-链接跳转做成通用模块 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/879 2020-06-09 11:40:12 +08:00
cced6b7035 光环助手V4.0.2-开服日历表优化(2(1),2(2))https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/893 2020-06-08 16:47:38 +08:00
ae0b5b3738 Merge branch 'dev_4.0.2' into 'dev'
Merge 4.0.2 feature changes

See merge request halo/assistant-android!16
2020-06-08 15:37:08 +08:00
6fdf9cbe5d Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-08 15:36:00 +08:00
009244c65d 游戏评论字数限制 2020-06-08 15:35:54 +08:00
73a720bb9c Merge branch 'dev_4.0.2' of gitlab.ghzhushou.com:halo/assistant-android into dev_4.0.2 2020-06-08 15:31:19 +08:00
fd9df9904f 完成首页游戏替换功能(第三期) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/880 2020-06-08 15:30:52 +08:00
e75fb3a40d 视频合集、浏览记录、我的收藏视频点击用户头像昵称跳转个人主页 2020-06-08 11:36:33 +08:00
0bef1a2aa8 视频合集、个人主页、浏览记录、我的收藏视频UI优化 2020-06-08 11:01:03 +08:00
395eb641e5 移除首页无用的下载监听 2020-06-05 16:21:32 +08:00
9019242ffb Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-05 15:10:49 +08:00
9433bb72ca 光环助手V4.0.2-游戏专题功能强化(后台)(8) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/886 2020-06-05 15:10:13 +08:00
500f751152 完成光环助手V4.0.2-下载数据统计需求 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/884 2020-06-05 15:03:01 +08:00
9ebe3f4a0e 处理关闭视频流页面上传播放数据progress为0的问题 2020-06-05 10:32:51 +08:00
8c92fc9a42 Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-04 17:40:11 +08:00
2a7cb34218 新增urlscheme跳转链接 2020-06-04 17:40:07 +08:00
e1a42b49c1 光环助手V4.0.2-更新推送功能优化(2) https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/882 2020-06-04 17:24:07 +08:00
5a825debf5 Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-04 15:49:33 +08:00
e46b0a42b0 修复专题下载进度串行问题(10)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885 2020-06-04 15:49:25 +08:00
eb0c442a5e Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-04 10:58:29 +08:00
eb6460236b 视频UI封面图比例改为16:9 2020-06-04 10:58:24 +08:00
ef051daffd 历史记录数据库表新增字段 2020-06-04 10:55:50 +08:00
b6acb302d2 Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-04 10:54:36 +08:00
5cfc5a3971 光环助手V4.0.2-游戏专题功能强化(前端)(8,9)https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/885 2020-06-04 10:54:28 +08:00
04de97af16 升级版本至4.0.2 2020-06-04 10:32:03 +08:00
6367f90589 Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-03 17:33:32 +08:00
bc8f9d07bb 页面回收重建,根据tag找回fragment避免每次都重新创建 2020-06-03 17:33:27 +08:00
e205abd120 Merge branch 'dev_4.0.2' of gitlab.ghzs.com:halo/assistant-android into dev_4.0.2 2020-06-03 17:22:56 +08:00
5da8fccef7 尝试修复首页-问答模块不能左右滑动的问题 2020-06-03 17:22:38 +08:00
c7e78142ee okhttp版本更新至3.12.12 2020-06-03 16:42:21 +08:00
354c7d1f85 光环助手V4.0.2-游戏关注功能优化 https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/851 2020-06-03 14:49:33 +08:00
484 changed files with 9855 additions and 3189 deletions

View File

@ -42,7 +42,7 @@ android {
}
ndk {
abiFilters "armeabi-v7a", "x86"
abiFilters "armeabi-v7a"
}
// 由于app只针对中文用户所以仅保留zh资源其他删掉
@ -68,6 +68,13 @@ android {
buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\""
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
resValue "string", "huawei_push_appid", "appid=${HUAWEI_PUSH_APPID}"
/**
* Build Time 供区分 jenkins 打包时间用
*/
@ -95,7 +102,7 @@ android {
signingConfig signingConfigs.debug
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E3\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E4\""
multiDexKeepProguard file("tinker_multidexkeep.pro")
}
@ -107,7 +114,7 @@ android {
signingConfig signingConfigs.release
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E3\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E4\""
multiDexKeepProguard file("tinker_multidexkeep.pro")
}
@ -124,13 +131,10 @@ android {
dimension "nonsense"
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
}
// internal test dev host
@ -140,14 +144,11 @@ android {
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
buildConfigField "String", "MEIZUPUSH_APPID", "\"${DEBUG_MEIZUPUSH_APPID}\""
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${DEBUG_MEIZUPUSH_APPKEY}\""
buildConfigField "String", "SENSITIVE_API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "BUGLY_APPID", "\"${DEBUG_BUGLY_APPID}\""
buildConfigField "String", "UMENG_APPKEY", "\"${DEV_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEV_UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "BUGLY_APPID", "\"${DEV_BUGLY_APPID}\""
}
}
}
@ -171,7 +172,7 @@ rebuildChannel {
repositories {
flatDir {
dirs 'libs','libs/aars'
dirs 'libs', 'libs/aars'
}
}
@ -263,13 +264,11 @@ dependencies {
implementation "com.squareup.picasso:picasso:${picasso}"
// for video streaming
implementation ("com.shuyu:gsyVideoPlayer-java:$gsyVideo",{
implementation("com.shuyu:gsyVideoPlayer-java:$gsyVideo", {
exclude module: "gsyvideoplayer-androidvideocache"
})
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
implementation "com.github.wendux:DSBridge-Android:$dsBridge"
implementation "android.arch.work:work-runtime:${workManager}"
implementation "com.llew.huawei:verifier:${verifier}"

Binary file not shown.

View File

@ -248,4 +248,10 @@
-keep class com.pgl.sys.ces.* {*;}
-keep class com.gyf.immersionbar.* {*;}
-dontwarn com.gyf.immersionbar.**
-dontwarn com.gyf.immersionbar.**
-keep class com.taobao.securityjni.**{*;}
-keep class com.taobao.wireless.security.**{*;}
-keep class com.ut.secbody.**{*;}
-keep class com.taobao.dp.**{*;}
-keep class com.alibaba.wireless.security.**{*;}

View File

@ -4,7 +4,6 @@ import android.app.Application;
import com.facebook.stetho.Stetho;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.squareup.leakcanary.LeakCanary;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
@ -18,15 +17,6 @@ import okhttp3.logging.HttpLoggingInterceptor;
public class Injection {
public static boolean appInit(Application application) {
// init leakcanary
if (LeakCanary.isInAnalyzerProcess(application)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return false;
}
LeakCanary.install(application);
// init stetho
Stetho.initializeWithDefaults(application);

View File

@ -82,6 +82,7 @@
android:largeHeap="true"
android:resizeableActivity="true"
android:theme="@style/AppCompatTheme.APP"
tools:replace="android:allowBackup"
tools:targetApi="n">
<!--android:launchMode = "singleTask"-->
@ -518,6 +519,7 @@
<activity
android:name="com.gh.gamecenter.PushProxyActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent" />
<activity
@ -580,7 +582,7 @@
</receiver>
<!--魅族push应用定义消息receiver声明 -->
<receiver android:name="com.gh.gamecenter.receiver.MeizuPushReceiver">
<receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">
<intent-filter>
<!-- 接收push消息 -->
<action android:name="com.meizu.flyme.push.intent.MESSAGE" />
@ -605,7 +607,11 @@
</intent-filter>
</receiver>
<service android:name="com.gh.base.GHUmengNotificationService" />
<meta-data android:name="com.huawei.hms.client.appid" android:value="@string/huawei_push_appid"/>
<service
android:name="com.gh.base.GHUmengNotificationService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->

View File

@ -3,17 +3,25 @@ package com.gh.base;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.base.fragment.BaseFragment;
import com.gh.common.constant.Constants;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.RunningUtils;
@ -37,6 +45,7 @@ import java.lang.ref.WeakReference;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import butterknife.ButterKnife;
@ -109,6 +118,15 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
}
}
@SuppressWarnings("ConstantConditions")
@Override
public void setContentView(View view) {
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0) {
view = getRootViewWithEnvIndicator(view);
}
super.setContentView(view);
}
@Override
protected void onDestroy() {
if (useEventBus()) EventBus.getDefault().unregister(this);
@ -128,21 +146,55 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
String icon,
String shareTitle,
String shareSummary,
ShareUtils.ShareType shareType) {
ShareUtils.ShareEntrance shareEntrance, String id) {
ShareUtils.getInstance(this).showShareWindows(this,
getWindow().getDecorView(),
url,
icon,
shareTitle,
shareSummary,
shareType);
if (shareType == ShareUtils.ShareType.game || shareType == ShareUtils.ShareType.plugin) {
shareEntrance, id);
if (shareEntrance == ShareUtils.ShareEntrance.game || shareEntrance == ShareUtils.ShareEntrance.plugin) {
MtaHelper.onEvent("内容分享", "内容分享", shareTitle + shareSummary);
} else {
MtaHelper.onEvent("内容分享", "内容分享", shareTitle);
}
}
private View getRootViewWithEnvIndicator(View view) {
RelativeLayout screenRootView = new RelativeLayout(this);
screenRootView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
LinearLayout ll = new LinearLayout(this);
TextView tv = new TextView(this);
String envText = "正式环境";
if (BuildConfig.FLAVOR.equals("internal")) {
envText = "测试环境";
}
tv.setText(envText);
tv.setGravity(Gravity.CENTER);
tv.setTextColor(Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
tv.setBackground(ContextCompat.getDrawable(this, R.color.red));
tv.measure(0, 0);
tv.setAlpha(0.15F);
int height = tv.getMeasuredHeight();
int width = tv.getMeasuredWidth();
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
ll.setTranslationX(DisplayUtils.dip2px(20));
ll.setRotation(45);
ll.addView(tv);
ll.setPadding(0, (width - height) / 2, 0, (width - height) / 2);
screenRootView.addView(view);
screenRootView.addView(ll);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) ll.getLayoutParams();
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
return screenRootView;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(final EBShowDialog showDialog) {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)

View File

@ -35,6 +35,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
val mDraftBtn by bindView<TextView>(R.id.draft_btn)
private val mEditorTextNumTv by bindView<TextView>(R.id.editorTextNumTv)
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
private val mEditorParagraph by bindView<CheckableImageView>(R.id.editor_paragraph)
@ -89,6 +90,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
// 防止个别手机在Js里无法获取粘贴内容
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
mRichEditor.addJavascriptInterface(OnEditorTextChangeListener(), "OnEditorTextChangeListener")
mRichEditor.setInputEnabled(true)
mDraftBtn.text = if (this is AnswerEditActivity) {
@ -258,6 +260,14 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
}
}
private inner class OnEditorTextChangeListener {
@JavascriptInterface
fun onTextChange(count: Int) {
val num = if (count > MAX_INPUT_TEXT_NUM) MAX_INPUT_TEXT_NUM - count else count
mEditorTextNumTv.text = num.toString()
}
}
abstract fun mtaEventName(): String
companion object {
@ -273,5 +283,6 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
const val INSERT_ANSWER_CODE = 411
const val INSERT_ARTICLE_CODE = 412
const val INSERT_GAME_CODE = 413
const val MAX_INPUT_TEXT_NUM = 10000
}
}

View File

@ -95,7 +95,7 @@ class GHUmengNotificationService : UmengMessageService() {
// 用户未登录的情况下不生成消息中心通知,避免用户掉登录了还收到跳转至消息中心的通知
if (data != null
&& data.link?.target == "system"
&& data.link?.link == "system"
&& !UserManager.getInstance().isLoggedIn) {
return
}

View File

@ -15,7 +15,6 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.MtaHelper;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
@ -239,7 +238,7 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.menu_download) {
MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
// MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(this, mEntrance);
startActivity(intent);
}

View File

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

View File

@ -3,11 +3,10 @@ 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.PagerAdapter
import androidx.viewpager.widget.ViewPager
import butterknife.BindView
import com.gh.base.adapter.FragmentAdapter
@ -15,7 +14,6 @@ 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
@ -23,8 +21,10 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
@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
@ -66,6 +66,10 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
if (arguments != null) mCheckedIndex = requireArguments().getInt(PAGE_INDEX, 0)
}
open fun providePagerAdapter(): PagerAdapter? {
return null
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
@ -74,7 +78,8 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
mViewPager.offscreenPageLimit = mFragmentsList.size
mViewPager.addOnPageChangeListener(this)
mViewPager.adapter = FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
mViewPager.adapter = providePagerAdapter()
?: FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
mViewPager.currentItem = mCheckedIndex
mTabLayout.setupWithViewPager(mViewPager)
mTabIndicatorView.setupWithTabLayout(mTabLayout)
@ -84,60 +89,10 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
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)
if (tabView == null) tabView = BaseFragment_TabLayout.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
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex)
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

View File

@ -6,6 +6,7 @@ import android.webkit.JavascriptInterface
import androidx.annotation.Keep
import com.gh.base.CurrentActivityHolder
import com.gh.common.util.*
import com.gh.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.LoginActivity
import com.gh.gamecenter.ViewImageActivity
@ -23,7 +24,6 @@ import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
import wendu.dsbridge.CompletionHandler
class DefaultJsApi(var context: Context) {

View File

@ -13,12 +13,13 @@ import com.gh.common.util.DirectUtils.directToVideoDetail
import com.gh.common.util.EntranceUtils
import com.gh.gamecenter.*
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.entity.VideoLinkEntity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.lightgame.utils.Utils
object DefaultWebViewUrlHandler {
object DefaultUrlHandler {
@JvmStatic
fun interceptUrl(context: Context, url: String, entrance: String): Boolean {
@ -178,7 +179,7 @@ object DefaultWebViewUrlHandler {
val tag = uri.getQueryParameter("tag") ?: ""
DirectUtils.directAskColumnLabelDetail(context, tag, community, entrance, "")
}
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL->{
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL -> {
val community = CommunityEntity()
community.id = uri.getQueryParameter("community_id") ?: ""
community.name = uri.getQueryParameter("community_name") ?: ""
@ -186,6 +187,37 @@ object DefaultWebViewUrlHandler {
DirectUtils.directAskColumnDetail(context, columnId, community, entrance, "")
}
EntranceUtils.HOST_BLOCK -> {
val name = uri.getQueryParameter("name")
?: ""
val entity = SubjectRecommendEntity(link = id, name = name, text = name)
DirectUtils.directToBlock(context, entity)
}
EntranceUtils.HOST_SERVER_BLOCK -> {
DirectUtils.directToGameServers(context, entrance = entrance, path = "")
}
EntranceUtils.HOST_AMWAY_BLOCK -> {
DirectUtils.directToAmway(context, entrance = entrance, path = "")
}
EntranceUtils.HOST_HELP -> {
val name = uri.getQueryParameter("name")
?: ""
DirectUtils.directToQa(context, name, id)
}
EntranceUtils.HOST_HELP_COLLECTION -> {
val name = uri.getQueryParameter("name")
?: ""
DirectUtils.directToQaCollection(context, name, id)
}
EntranceUtils.HOST_GAME_UPLOAD -> {
DirectUtils.directGameUpload(context,entrance = entrance, path = "")
}
else -> DialogUtils.showLowVersionDialog(context)
}
return true

View File

@ -0,0 +1,68 @@
package com.gh.common
import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.doOnMainProcessOnly
import com.gh.common.videolog.VideoRecordUtils
import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
import kotlin.concurrent.fixedRateTimer
object FixedRateJobHelper {
private const val CHECKER_PERIOD: Long = 60 * 1000L
private const val TIME_PERIOD: Long = 600 * 1000L
private const val LOGHUB_PERIOD: Long = 120 * 1000L
private const val EXPOSURE_PERIOD: Long = 300 * 1000L
private const val REGION_SETTING_PERIOD: Long = 300 * 1000L
private const val VIDEO_RECORD_PERIOD: Long = 60 * 1000L
private var mExecuteCount: Int = 0
var timeDeltaBetweenServerAndClient: Long = 0
@JvmStatic
fun begin() {
doOnMainProcessOnly {
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
// 时间校对10分钟一次
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let { timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis() }
}
})
}
// 提交曝光数据
if ((mExecuteCount * CHECKER_PERIOD) % EXPOSURE_PERIOD == 0L) {
ExposureManager.commitSavedExposureEvents(true)
}
// 提交普通 loghub 数据
if ((mExecuteCount * CHECKER_PERIOD) % LOGHUB_PERIOD == 0L) {
LoghubUtils.commitSavedLoghubEvents()
}
// 更新游戏屏蔽信息
if ((mExecuteCount * CHECKER_PERIOD) % REGION_SETTING_PERIOD == 0L) {
RegionSettingHelper.getRegionSetting()
}
// 提交视频浏览记录数据
if ((mExecuteCount * CHECKER_PERIOD) % VIDEO_RECORD_PERIOD == 0L) {
VideoRecordUtils.commitVideoRecord()
}
// ExposureUtils.logADownloadCompleteExposureEvent(GameEntity(id = mExecuteCount.toString(), name = "测试曝光上传"), platform = "", trace = null, downloadType = ExposureUtils.DownloadType.DOWNLOAD)
mExecuteCount++
}
}
}
}

View File

@ -38,22 +38,17 @@ object PushManager {
fun init(channel: String) {
tryWithDefaultCatch {
//初始化友盟推送
UMConfigure.init(mApplication,
Config.UMENG_APPKEY, channel,
UMConfigure.DEVICE_TYPE_PHONE,
Config.UMENG_MESSAGE_SECRET)
UMConfigure.init(mApplication, Config.UMENG_APPKEY, channel, UMConfigure.DEVICE_TYPE_PHONE, Config.UMENG_MESSAGE_SECRET)
val pushAgent = PushAgent.getInstance(mApplication)
runOnIoThread { registerDevice() }
// 注册小米、华为和魅族通道
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)
//注册推送服务每次调用register方法都会回调该接口
runOnIoThread { registerDevice() }
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
mPreviousAlias = aliasInSp?.toObject()

View File

@ -31,6 +31,7 @@ import io.reactivex.schedulers.Schedulers;
public class Config {
public static final String API_HOST = BuildConfig.API_HOST;
public static final String SENSITIVE_API_HOST = BuildConfig.SENSITIVE_API_HOST;
/**
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
@ -253,7 +254,7 @@ public class Config {
public static void getGhzsSettings() {
String channel = HaloApp.getInstance().getChannel();
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
.getApi().getSettings(PackageUtils.getVersionName(), channel)
.getSensitiveApi().getSettings(PackageUtils.getVersionName(), channel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<SettingsEntity>() {

View File

@ -42,6 +42,9 @@ public class Constants {
// 最近显示的弹窗信息
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
public static final String SP_LAST_OPENING_TIME = "last_opening_dialog_time";
// 新用户首次启动光环的时间
public static final String SP_INITIAL_USAGE_TIME = "initial_usage_time";
//引导设置 “通知管理” 引导弹窗
public static final String SP_SHOWED_NOTIFICATION_LOGIN = "show_notification_login_hint";
@ -86,6 +89,8 @@ public class Constants {
public static final String SP_AUTH_DIALOG = "auth_dialog";
//顶部视频进度保存,重启恢复
public static final String SP_TOP_VIDEO_SCHEDULE = "top_video_schedule";
//我的光环小红点提示
public static final String SP_GH_RED_POINT_REMIND = "gh_red_point_remind";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";

View File

@ -2,6 +2,7 @@ package com.gh.common.databind;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@ -13,6 +14,12 @@ 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;
@ -68,12 +75,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Created by khy on 12/02/18.
*/
@ -95,6 +96,26 @@ public class BindingAdapters {
view.setTextSize(number);
}
@BindingAdapter("setTypeface")
public static void setTypeface(TextView view, String type) {
if (type == null) return;
switch (type) {
case "bold":
view.setTypeface(null, Typeface.BOLD);
break;
case "italic":
view.setTypeface(null, Typeface.ITALIC);
break;
case "bold_italic":
view.setTypeface(null, Typeface.BOLD_ITALIC);
break;
default:
view.setTypeface(null, Typeface.NORMAL);
break;
}
}
@BindingAdapter({"addDetailKaiFuView", "addDetailKaiFuViewListener", "isReadyPatch"})
public static void addDetailKaiFuView(LinearLayout view, List<ServerCalendarEntity> list
, OnViewClickListener listener, Boolean isReadyPatch) {
@ -687,14 +708,15 @@ public class BindingAdapters {
}
}
@BindingAdapter({"setGameName", "isShowPlatform"})
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform) {
@BindingAdapter({"setGameName", "isShowPlatform", "isShowSuffix"})
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform, @Nullable Boolean isShowSuffix) {
if (isShowSuffix == null) isShowSuffix = true; // 默认显示
if (isShowPlatform && game.getApk().size() > 0) {
view.setText(String.format("%s - %s", game.getName(),
view.setText(String.format("%s - %s", !isShowSuffix ? game.getNameWithoutSuffix() : game.getName(),
PlatformUtils.getInstance(view.getContext()).getPlatformName(
game.getApk().get(0).getPlatform())));
} else {
view.setText(game.getName());
view.setText(!isShowSuffix ? game.getNameWithoutSuffix() : game.getName());
}
}

View File

@ -10,6 +10,7 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.util.DirectUtils
import com.gh.common.util.DisplayUtils
import com.gh.common.util.MtaHelper
@ -18,7 +19,10 @@ import com.gh.gamecenter.entity.GameEntity
import kotlinx.android.synthetic.main.dialog_game_off_service.*
// 游戏关闭下载弹窗
class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
class GameOffServiceDialogFragment
// : BaseTrackableDialogFragment()
:BaseDialogFragment() {
private var mDialog: GameEntity.Dialog? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -42,7 +46,7 @@ class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
siteTv.text = site.text
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
siteTv.setOnClickListener {
MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
dismiss()
}
@ -52,13 +56,13 @@ class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
}
}
override fun getEvent(): String {
return "游戏下载状态按钮"
}
override fun getKey(): String {
return "查看详情弹窗"
}
// override fun getEvent(): String {
// return "游戏下载状态按钮"
// }
//
// override fun getKey(): String {
// return "查看详情弹窗"
// }
companion object {
@JvmStatic

View File

@ -14,6 +14,7 @@ import androidx.lifecycle.MutableLiveData
import butterknife.BindView
import butterknife.ButterKnife
import butterknife.OnClick
import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.constant.Config
import com.gh.common.history.HistoryHelper
import com.gh.common.repository.ReservationRepository
@ -29,7 +30,9 @@ import okhttp3.ResponseBody
import org.json.JSONObject
// 预约弹窗
class ReserveDialogFragment : BaseTrackableDialogFragment() {
class ReserveDialogFragment
: BaseDialogFragment() {
// : BaseTrackableDialogFragment() {
@BindView(R.id.reserve_hint_tv)
lateinit var reserveHintTv: TextView
@ -64,13 +67,13 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
return inflater.inflate(R.layout.dialog_reserve_game, null)
}
override fun getEvent(): String {
return "预约游戏"
}
override fun getKey(): String {
return "预约功能操作"
}
// override fun getEvent(): String {
// return "预约游戏"
// }
//
// override fun getKey(): String {
// return "预约功能操作"
// }
@Suppress("DEPRECATION")
@SuppressLint("SetTextI18n")
@ -109,7 +112,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
} else {
customizableBtn.text = dialogConfig?.text
customizableBtn.setOnClickListener {
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击跳转按钮")
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击跳转按钮")
DirectUtils.directToLinkPage(
requireContext(),
dialogConfig!!.toLinkEntity(),
@ -127,7 +130,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
fun onClick(view: View) {
when (view.id) {
R.id.reserve_without_mobile_btn -> {
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击无手机号预约")
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击无手机号预约")
mViewModel.reserve(gameId = mGameId, gameName = mGameName)
}
@ -138,12 +141,12 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
return
}
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击立即预约")
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击立即预约")
mViewModel.reserve(gameId = mGameId, gameName = mGameName, mobile = mobile)
}
R.id.close_btn -> {
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击关闭")
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击关闭")
dismissAllowingStateLoss()
}
}
@ -189,7 +192,7 @@ class ReserveViewModel(application: Application) : AndroidViewModel(application)
reservation.postValue(Reservation(success = true, withMobile = mobile.isNotEmpty(), boundWechat = boundWechat))
ReservationRepository.addReservationToMemoryAndRefresh(gameId)
MtaHelper.onEvent("预约游戏", "预约", gameName)
// MtaHelper.onEvent("预约游戏", "预约", gameName)
}
override fun onFailure(exception: Exception) {

View File

@ -11,6 +11,7 @@ data class ExposureEntity(
@SerializedName("game_id")
val gameId: String? = "",
val gameName: String? = "",
val gameVersion: String? = "",
val sequence: Int? = 0,
val platform: String? = "",
val downloadType: String? = "",

View File

@ -8,6 +8,7 @@ import com.gh.common.constant.Constants
import com.gh.common.exposure.meta.Meta
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.time.TimeUtil
import com.gh.common.util.getFirstElementDividedByDivider
import com.gh.gamecenter.entity.GameEntity
import kotlinx.android.parcel.Parcelize
import java.util.*
@ -27,9 +28,14 @@ data class ExposureEvent(
companion object {
@JvmStatic
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
if (gameEntity?.getApk()?.size == 1) {
gameEntity.gameVersion = gameEntity.getApk().elementAtOrNull(0)?.version ?: ""
}
return ExposureEvent(
payload = ExposureEntity(gameId = gameEntity?.id,
payload = ExposureEntity(
gameId = gameEntity?.id?.getFirstElementDividedByDivider(Constants.GAME_ID_DIVIDER),
gameName = gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = gameEntity?.gameVersion,
sequence = gameEntity?.sequence,
platform = gameEntity?.platform,
downloadType = gameEntity?.downloadType,

View File

@ -26,6 +26,10 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
visibleState?.let { commitExposure(it) }
throttleBus?.clear()
}
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
}
}, false)
}

View File

@ -9,7 +9,6 @@ import com.gh.loghub.LoghubHelper
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.util.concurrent.Executors
import kotlin.concurrent.fixedRateTimer
/**
* A handful tool for committing logs to aliyun loghub.
@ -17,7 +16,7 @@ import kotlin.concurrent.fixedRateTimer
* 如何简单地统计列表中每个 item 的曝光事件?
*
* 1. Adapter 实现 IExposable 接口,在 BindView 阶段更新 ExposureEventExposureEvent 供 getEventByPosition(pos) 方法获取用
* 2. 构建一个 ExposureListener 并作为入参添加至 recyclerview 的 Scroll 回调中
* 2. 构建一个 ExposureListener 并作为入参添加至 recyclerview 的 onScroll 回调中
* 3. 没了
*/
object ExposureManager {
@ -25,7 +24,6 @@ object ExposureManager {
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
private const val PROJECT = "ghzs"
private const val STORE_SIZE = 100
private const val STORE_FORCE_UPLOAD_PERIOD = 300 * 1000L
private const val LOG_STORE = BuildConfig.EXPOSURE_REPO
private val loghubHelper = LoghubHelper.getInstance()
@ -38,18 +36,12 @@ object ExposureManager {
@JvmStatic
fun init() {
TimeUtil.init()
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
exposureExecutor.execute {
val eventList = exposureDao.getAll()
exposureSet.addAll(eventList)
}
fixedRateTimer(name = "ExposureManager-Store-Checker", initialDelay = 500, period = STORE_FORCE_UPLOAD_PERIOD) {
commitSavedExposureEvents(true)
}
}
/**

View File

@ -1,5 +1,6 @@
package com.gh.common.exposure
import android.text.TextUtils
import com.g00fy2.versioncompare.Version
import com.gh.common.constant.Constants
import com.gh.common.util.PackageUtils
@ -22,6 +23,7 @@ object ExposureUtils {
} else {
entity.id
}
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version ?: gameEntity.gameVersion
gameEntity.platform = platform
gameEntity.downloadType = downloadType.toString()
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
@ -63,7 +65,11 @@ object ExposureUtils {
}
}
} else {
DownloadType.PLUGIN_DOWNLOAD
if (!TextUtils.isEmpty(apkEntity.ghVersion)) {
DownloadType.PLUGIN_DOWNLOAD
} else {
DownloadType.UPDATE
}
}
} else {
DownloadType.DOWNLOAD

View File

@ -1,30 +0,0 @@
package com.gh.common.exposure.time
import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
import kotlin.concurrent.fixedRateTimer
class Corrector {
companion object {
const val TIME_CORRECTOR_ADJUST_PERIOD: Long = 600000
}
var delta: Long = 0
init {
fixedRateTimer("TimeUtil-Corrector-Checker", initialDelay = 0, period = TIME_CORRECTOR_ADJUST_PERIOD) {
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let { delta = it * 1000 - System.currentTimeMillis() }
}
})
}
}
}

View File

@ -1,23 +1,15 @@
package com.gh.common.exposure.time
import com.gh.common.FixedRateJobHelper
object TimeUtil {
private lateinit var corrector: Corrector
fun init() {
corrector = Corrector()
}
fun currentTimeMillis(): Long {
return corrector.delta + System.currentTimeMillis()
return FixedRateJobHelper.timeDeltaBetweenServerAndClient + System.currentTimeMillis()
}
fun currentTime(): Int {
return if (::corrector.isInitialized) {
((corrector.delta + System.currentTimeMillis()) / 1000).toInt()
} else {
(System.currentTimeMillis() / 1000).toInt()
}
return ((FixedRateJobHelper.timeDeltaBetweenServerAndClient + System.currentTimeMillis()) / 1000).toInt()
}
}

View File

@ -0,0 +1,21 @@
package com.gh.common.filter
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
@Keep
data class RegionSetting(
@SerializedName("game_mirror")
var mirrorGameIdSet: HashSet<String>,
@SerializedName("game_block")
var filterGameIdSet: HashSet<String>,
@SerializedName("channel_control")
var channelControl: ChannelControl) {
@Keep
data class ChannelControl(
@SerializedName("game_category")
var gameCategory: String,
@SerializedName("effect")
var effect: Boolean)
}

View File

@ -0,0 +1,96 @@
package com.gh.common.filter
import android.annotation.SuppressLint
import com.gh.common.constant.Constants
import com.gh.common.util.SPUtils
import com.gh.common.util.toJson
import com.gh.common.util.toObject
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
object RegionSettingHelper {
private var mChannelControl: RegionSetting.ChannelControl? = null
private var mFilterGameIdSet: HashSet<String>? = hashSetOf()
private var mDisplayMirrorIfoGameIdSet: HashSet<String>? = hashSetOf()
private const val SP_SETTING = "region_setting"
fun shouldThisGameDisplayMirrorInfo(gameId: String): Boolean {
return mDisplayMirrorIfoGameIdSet?.contains(gameId) ?: false
}
@JvmStatic
fun shouldThisGameBeFiltered(gameId: String?): Boolean {
return mFilterGameIdSet?.contains(gameId) ?: false
}
@JvmStatic
fun filterGame(list: List<GameEntity>?): ArrayList<GameEntity> {
if (list == null) return arrayListOf()
if (mFilterGameIdSet?.isEmpty() == true) {
if (list is ArrayList) return list
}
val listCopy: ArrayList<GameEntity> = if (list is ArrayList) list else ArrayList(list)
listCopy.removeAll { mFilterGameIdSet?.contains(it.id) ?: false }
return listCopy
}
@JvmField
var filterGame = Function { list: List<GameEntity> ->
filterGame(list)
list
}
fun shouldGameOfThisCategoryUseMirrorInfo(category: String) : Boolean {
return if (mChannelControl == null || mChannelControl?.effect == false || !isUserUsedLessThan24Hours()) {
false
} else {
mChannelControl?.gameCategory == category
}
}
@SuppressLint("CheckResult")
@JvmStatic
fun getRegionSetting() {
RetrofitManager.getInstance(HaloApp.getInstance().application)
.sensitiveApi
.getRegionSetting(HaloApp.getInstance().channel)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<RegionSetting>() {
override fun onSuccess(data: RegionSetting) {
updateSettingsInMemory(data)
SPUtils.setString(SP_SETTING, data.toJson())
}
override fun onFailure(exception: Exception) {
SPUtils.getString(SP_SETTING).toObject<RegionSetting>()?.let {
updateSettingsInMemory(it)
}
}
})
}
private fun updateSettingsInMemory(data: RegionSetting) {
mFilterGameIdSet = data.filterGameIdSet
mDisplayMirrorIfoGameIdSet = data.mirrorGameIdSet
mChannelControl = data.channelControl
}
/**
* 该用户是否是使用了不到 24 小时的新用户
*/
private fun isUserUsedLessThan24Hours(): Boolean {
val initialUsageTime = SPUtils.getLong(Constants.SP_INITIAL_USAGE_TIME, 0)
return !(initialUsageTime == 0L || System.currentTimeMillis() - initialUsageTime > 86400000)
}
}

View File

@ -15,7 +15,7 @@ import com.gh.gamecenter.room.converter.*
import com.gh.gamecenter.room.dao.*
import com.halo.assistant.HaloApp
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 5, exportSchema = false)
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 6, exportSchema = false)
@TypeConverters(CountConverter::class,
CommunityConverter::class,
TimeConverter::class,
@ -23,7 +23,8 @@ import com.halo.assistant.HaloApp
ThumbnailConverter::class,
TagStyleListConverter::class,
StringArrayListConverter::class,
CommunityVideoConverter::class)
CommunityVideoConverter::class,
UserConverter::class)
abstract class HistoryDatabase : RoomDatabase() {
@ -54,11 +55,20 @@ abstract class HistoryDatabase : RoomDatabase() {
}
}
val MIGRATION_5_6: Migration = object : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("Alter TABLE MyVideoEntity add title TEXT NOT NULL DEFAULT ''")
database.execSQL("Alter TABLE MyVideoEntity add commentCount INTEGER NOT NULL DEFAULT 0")
database.execSQL("Alter TABLE MyVideoEntity add user TEXT NOT NULL DEFAULT ''")
}
}
val instance by lazy {
Room.databaseBuilder(HaloApp.getInstance().application, HistoryDatabase::class.java, "USER_TRACK_HISTORY_DATABASE")
.addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4)
.addMigrations(MIGRATION_4_5)
.addMigrations(MIGRATION_5_6)
.build()
}
}

View File

@ -6,13 +6,10 @@ import com.aliyun.sls.android.sdk.model.LogGroup
import com.gh.loghub.LoghubHelper
import org.json.JSONObject
import java.util.concurrent.Executors
import kotlin.concurrent.fixedRateTimer
object LoghubUtils {
private const val STORE_SIZE = 100
private const val STORE_FORCE_UPLOAD_INTERVAL = 120 * 1000L
private lateinit var mApplication: Application
private val loghubEventSet by lazy { hashSetOf<LoghubEvent>() }
@ -27,10 +24,6 @@ object LoghubUtils {
val eventList = loghubEventDao.getAll()
loghubEventSet.addAll(eventList)
}
fixedRateTimer(name = "Loghub-Event-Checker", initialDelay = 1000, period = STORE_FORCE_UPLOAD_INTERVAL) {
commitSavedLoghubEvents()
}
}
@JvmStatic
@ -54,7 +47,7 @@ object LoghubUtils {
LoghubHelper.getInstance().uploadLogGroup(logGroup, logStore)
}
private fun commitSavedLoghubEvents() {
fun commitSavedLoghubEvents() {
loghubEventExecutor.execute {
if (loghubEventSet.isEmpty()) return@execute

View File

@ -1,5 +1,6 @@
package com.gh.common.repository
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.RandomUtils
import com.gh.gamecenter.entity.GameEntity
@ -15,7 +16,8 @@ object RemenkapaiRepository {
@JvmStatic
fun getRemenkapai(size: Int): Observable<List<GameEntity>> {
return if (remenkapaiList.isEmpty()) {
RetrofitManager.getInstance(getApplication()).api.remenkapai
RetrofitManager.getInstance(getApplication()).sensitiveApi.remenkapai
.map(RegionSettingHelper.filterGame)
.map { gameList -> filterEntityWithoutApk(gameList) }
.map { pickRandomSizeEntity(size) }
.map(ApkActiveUtils.filterMapperList)

View File

@ -0,0 +1,14 @@
package com.gh.common.util
import com.alibaba.wireless.security.jaq.avmp.IJAQAVMPSignComponent
import com.alibaba.wireless.security.open.SecurityGuardManager
import com.halo.assistant.HaloApp
object AntiBotHelper {
@JvmStatic
val manager by lazy {
SecurityGuardManager.getInstance(HaloApp.getInstance().application).getInterface(IJAQAVMPSignComponent::class.java).apply {
this.initialize()
}
}
}

View File

@ -3,19 +3,16 @@ package com.gh.common.util;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.common.constant.Config;
import com.gh.common.constant.Constants;
import com.gh.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.BuildConfig;
import com.gh.gid.GidCallback;
import com.gh.gid.GidHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.config.CommonDebug;
import com.lightgame.utils.Util_System_Phone_State;
import com.lightgame.utils.Utils;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.stat.MtaSDkException;
@ -126,11 +123,18 @@ public class DataUtils {
public static void getGid() {
GidHelper.getInstance().registerDevice(new GidCallback() {
@Override
public void onSuccess(String s) {
Utils.log("Gid", s);
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, s).apply();
public void onSuccess(String gid) {
Utils.log("Gid", gid);
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
String originalGid = HaloApp.getInstance().getGid();
HaloApp.getInstance().setGid(gid);
// 避免重复调用
if (!TextUtils.isEmpty(gid) && !gid.equals(originalGid)) {
GameSubstituteRepositoryHelper.updateSubstitutableGames();
}
HaloApp.getInstance().setGid(s);
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
MetaUtil.INSTANCE.refreshMeta();
}
@ -197,36 +201,36 @@ public class DataUtils {
// 游戏下载
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
Map<String, Object> kv = new HashMap<>();
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
kv.put("版本", 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("位置", entrance);
kv.put("类型", method);
kv.put("厂商", Build.MANUFACTURER);
kv.put("Android版本", Build.VERSION.RELEASE);
onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("状态", status);
kv2.put("位置", entrance);
if (status.equals("开始")) {
kv2.put("版本", entrance + "-开始");
kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
} else {
kv2.put("版本", platform);
kv2.put("游戏分平台", gameName + "-" + platform);
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
}
onEvent(context, "游戏下载位置", gameName, kv2);
// Map<String, Object> kv = new HashMap<>();
//
// platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
//
// kv.put("版本", 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("位置", entrance);
// kv.put("类型", method);
// kv.put("厂商", Build.MANUFACTURER);
// kv.put("Android版本", Build.VERSION.RELEASE);
// onEvent(context, "游戏下载", gameName, kv);
//
// Map<String, Object> kv2 = new HashMap<>();
// kv2.put("状态", status);
// kv2.put("位置", entrance);
//
// if (status.equals("开始")) {
// kv2.put("版本", entrance + "-开始");
// kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
// } else {
// kv2.put("版本", platform);
// kv2.put("游戏分平台", gameName + "-" + platform);
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
// }
//
// onEvent(context, "游戏下载位置", gameName, kv2);
}
// 游戏更新

View File

@ -269,18 +269,21 @@ public class DeviceUtils {
// 只能获取WiFi的IpAddress
public static String getCurrentIpAddress() {
String ipAddress;
WifiManager wifiManager = (WifiManager) HaloApp.getInstance().
getApplication().
getApplicationContext().
getSystemService(Context.WIFI_SERVICE);
int address = wifiManager.getDhcpInfo().ipAddress;
ipAddress = ((address & 0xFF)
+ "." + ((address >> 8) & 0xFF)
+ "." + ((address >> 16) & 0xFF)
+ "." + ((address >> 24) & 0xFF));
return ipAddress;
String ipAddress = "0.0.0.0";
try {
WifiManager wifiManager = (WifiManager) HaloApp.getInstance().
getApplication().
getApplicationContext().
getSystemService(Context.WIFI_SERVICE);
int address = wifiManager.getDhcpInfo().ipAddress;
ipAddress = ((address & 0xFF)
+ "." + ((address >> 8) & 0xFF)
+ "." + ((address >> 16) & 0xFF)
+ "." + ((address >> 24) & 0xFF));
return ipAddress;
} catch (Exception e) {
return ipAddress;
}
}
}

View File

@ -8,7 +8,6 @@ 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;
@ -60,7 +59,6 @@ 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;
@ -196,7 +194,7 @@ public class DialogUtils {
AppExecutor.getUiExecutor().executeWithDelay(() -> Utils.toast(context, "当前使用移动网络下载,请注意流量消耗"), 500);
callBack.onResponse(false);
} else {
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(context), "出现弹窗提示");
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(context), "出现弹窗提示");
showDownloadDialog(context,
() -> callBack.onResponse(false),
() -> callBack.onResponse(true));
@ -256,12 +254,12 @@ public class DialogUtils {
}, 500);
listener.onConfirm();
dialog.dismiss();
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "本次允许");
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "本次允许");
});
wifiAuto.setOnClickListener(v -> {
cancelListener.onCancel();
dialog.dismiss();
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "连上WiFi后自动下载");
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "连上WiFi后自动下载");
});
allowAlways.setOnClickListener(v -> {
PreferenceManager
@ -276,7 +274,7 @@ public class DialogUtils {
}, 500);
listener.onConfirm();
dialog.dismiss();
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "总是允许");
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "总是允许");
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
@ -1343,6 +1341,33 @@ public class DialogUtils {
dialog.show();
}
public static void showPluggableNeverRemindDialog(Context context, String nameAndPlatform, @NonNull ConfirmListener listener) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_pluggable_never_remind, null);
View cancelBtn = contentView.findViewById(R.id.cancel);
View confirmBtn = contentView.findViewById(R.id.confirm);
TextView contentTv = contentView.findViewById(R.id.content);
contentTv.setText(("助手首页将不再提示《" + nameAndPlatform + "》的所有插件化消息,确定吗?"));
cancelBtn.setOnClickListener(v -> {
dialog.dismiss();
});
confirmBtn.setOnClickListener(v -> {
listener.onConfirm();
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
/**
* @param context may be is application context
* @return activity context

View File

@ -6,11 +6,17 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import com.gh.base.BaseActivity
import com.gh.base.ToolBarActivity
import com.gh.base.fragment.BaseFragment_TabLayout
import com.gh.common.AppExecutor
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureEvent.Companion.createEvent
import com.gh.common.exposure.ExposureManager.log
import com.gh.common.exposure.ExposureTraceUtils.appendTrace
import com.gh.common.exposure.ExposureType
import com.gh.common.util.EntranceUtils.*
import com.gh.gamecenter.*
import com.gh.gamecenter.amway.AmwayActivity
@ -21,6 +27,7 @@ import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.eventbus.EBSkip
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
import com.gh.gamecenter.game.upload.GameSubmissionActivity
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mygame.PlayedGameActivity
@ -124,30 +131,36 @@ object DirectUtils {
when (linkEntity.type) {
"article", "news", "文章" -> {
NewsUtils.statNewsViews(context, linkEntity.link) // 统计阅读量
context.startActivity(NewsDetailActivity.getIntentById(context, linkEntity.link, BaseActivity.mergeEntranceAndPath(entrance, path)))
directToArticle(context, linkEntity.link
?: "", BaseActivity.mergeEntranceAndPath(entrance, path))
}
"game", "游戏" -> {
if (exposureEvent != null) {
GameDetailActivity.startGameDetailActivity(context, linkEntity.link, BaseActivity.mergeEntranceAndPath(entrance, path), exposureEvent)
directToGameDetail(context, linkEntity.link
?: "", BaseActivity.mergeEntranceAndPath(entrance, path), traceEvent = exposureEvent)
} else {
GameDetailActivity.startGameDetailActivity(context, linkEntity.link, BaseActivity.mergeEntranceAndPath(entrance, path))
directToGameDetail(context, linkEntity.link
?: "", BaseActivity.mergeEntranceAndPath(entrance, path))
}
}
"column", "游戏专题" -> SubjectActivity.startSubjectActivity(context, linkEntity.link, linkEntity.text, false, BaseActivity.mergeEntranceAndPath(entrance, path))
"column", "游戏专题" -> directToSubject(context, linkEntity.link
?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path))
"question", "社区问题" -> context.startActivity(QuestionsDetailActivity.getIntent(context, linkEntity.link, entrance, path))
"question", "社区问题" -> directToQuestionDetail(context, linkEntity.link
?: "", entrance, path)
"answer", "社区回答" -> context.startActivity(AnswerDetailActivity.getIntent(context, linkEntity.link, entrance, path))
"answer", "社区回答" -> directToAnswerDetail(context, linkEntity.link ?: "", entrance, path)
"community", "问答社区" -> directToCommunity(context, CommunityEntity(linkEntity.link!!, linkEntity.text!!))
"community_article", "社区文章" -> context.startActivity(ArticleDetailActivity.getIntent(context, linkEntity.community!!, linkEntity.link!!, entrance, path))
"community_article", "社区文章" -> directToCommunityArticle(context, linkEntity.community!!, linkEntity.link!!, entrance, path)
"community_column", "社区专题" -> directToCommunityColumn(context, linkEntity.community, linkEntity.link!!, entrance, path)
"community_special_column" -> context.startActivity(AskColumnDetailActivity.getIntentByColumnId(context, linkEntity.link, linkEntity.community!!, entrance, path))
"community_special_column" -> directAskColumnDetail(context, linkEntity.link
?: "", linkEntity.community!!, entrance, path)
"web", "inurl", "web链接" -> {
when {
@ -166,37 +179,28 @@ object DirectUtils {
"tag" -> context.startActivity(TagsActivity.getIntent(context, linkEntity.text!!, linkEntity.title, entrance, path))
"all_community_article" -> {
context.startActivity(SimpleArticleListActivity.getIntent(
context,
linkEntity.link ?: "",
entrance,
path))
}
"all_community_article" -> directSimpleArticleList(context, linkEntity.link
?: "", entrance, path)
"category", "分类" -> {
context.startActivity(CategoryDirectoryActivity.getIntent(context, linkEntity.link!!, linkEntity.text!!))
}
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
"block", "版块" -> {
context.startActivity(BlockActivity.getIntent(context, SubjectRecommendEntity(
directToBlock(context, SubjectRecommendEntity(
link = linkEntity.link,
text = linkEntity.text,
name = linkEntity.name,
display = linkEntity.display ?: Display())))
display = linkEntity.display ?: Display()))
}
"column_collection", "专题合集" -> directToColumnCollection(context, linkEntity.link!!, -1, entrance)
"server", "game_server" -> {
context.startActivity(GameServersActivity.getIntent(context, entrance, path))
}
"server", "game_server", "开服表" -> directToGameServers(context, entrance, path)
"top_game_comment" -> directToAmway(context, null, entrance, path)
"wechat_bind" -> context.startActivity(WebActivity.getBindWechatIntent(context))
"video", "video_stream" -> directToVideoDetail(context,
"video", "video_stream", "视频" -> directToVideoDetail(context,
videoId = linkEntity.link!!,
fromLocation = VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value,
entrance = entrance,
@ -204,16 +208,21 @@ object DirectUtils {
"game_video" -> directToGameVideo(context, linkEntity.link ?: "", entrance, path)
"libao" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
"libao", "礼包" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, entrance)
"qa" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa_collection" -> directToQaCollection(context, linkEntity.text ?: "", linkEntity.link
"qa_collection", "Q&A合集" -> directToQaCollection(context, linkEntity.text
?: "", linkEntity.link
?: "")
"anliwall" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
"anliwall", "安利墙" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
"game_detail_comment" -> directToGameDetail(context, linkEntity.link ?: "", entrance)
"game_upload", "游戏投稿" -> directGameUpload(context, entrance, path)
//"h5_game_center" -> directLetoGameCenter(context)
@ -233,15 +242,27 @@ object DirectUtils {
/**
* 跳转至QA
*/
@JvmStatic
fun directToQa(context: Context, text: String, id: String) {
context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaId = id))
// context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaId = id))
val bundle = Bundle()
bundle.putString(KEY_TO, QaActivity::class.java.simpleName)
bundle.putString(KEY_NAVIGATION_TITLE, text)
bundle.putString(KEY_QA_ID, id)
jumpActivity(context, bundle)
}
/**
* 跳转至QA合集
*/
@JvmStatic
fun directToQaCollection(context: Context, text: String, id: String) {
context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaCollectionId = id))
// context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaCollectionId = id))
val bundle = Bundle()
bundle.putString(KEY_TO, QaActivity::class.java.simpleName)
bundle.putString(KEY_NAVIGATION_TITLE, text)
bundle.putString(KEY_QA_COLLECTION_ID, id)
jumpActivity(context, bundle)
}
/**
@ -249,7 +270,14 @@ object DirectUtils {
*/
@JvmStatic
fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String, columnName: String = "") {
context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance, columnName))
// context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance, columnName))
val bundle = Bundle()
bundle.putString(KEY_TO, ColumnCollectionDetailActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putString(KEY_COLLECTION_ID,id)
bundle.putString(KEY_COLUMNNAME,columnName)
bundle.putInt(KEY_POSITION,position)
jumpActivity(context, bundle)
}
/**
@ -299,7 +327,7 @@ object DirectUtils {
* 跳转到游戏详情
*/
@JvmStatic
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, scrollToLibao: Boolean = false) {
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, scrollToLibao: Boolean = false, traceEvent: ExposureEvent? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, GameDetailActivity::class.java.simpleName)
@ -308,6 +336,11 @@ object DirectUtils {
bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_TRENDES)
bundle.putBoolean(KEY_SCROLL_TO_LIBAO, scrollToLibao)
}
if (traceEvent != null) {
val clickEvent = createEvent(GameEntity(id), traceEvent.source, appendTrace(traceEvent), ExposureType.CLICK)
log(clickEvent)
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
}
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
jumpActivity(context, bundle)
}
@ -450,6 +483,9 @@ object DirectUtils {
@JvmStatic
fun directToExternalBrowser(context: Context, url: String) {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
if (context !is AppCompatActivity){
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(browserIntent)
}
@ -470,7 +506,11 @@ object DirectUtils {
chatType = "wpa"
}
val str = "mqqwpa://im/chat?chat_type=$chatType&uin=$qq&version=1&src_type=web"
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(str)))
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(str))
if (context !is AppCompatActivity){
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
} else {
// 没有安装QQ 复制账号
Util_System_ClipboardManager.setText(context, qq)
@ -481,17 +521,24 @@ object DirectUtils {
// 跳转 QQ 群
@JvmStatic
fun directToQqGroup(context: Context, groupNumber: String? = null): Boolean {
val intent = Intent()
intent.data = Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$groupNumber")
// 此Flag可根据具体产品需要自定义如设置则在加群界面按返回返回手Q主界面不设置按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent)
return true
} catch (e: Exception) {
// 未安装手Q或安装的版本不支持
if (ShareUtils.isQQClientAvailable(context)) {
val intent = Intent()
intent.data = Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$groupNumber")
// 此Flag可根据具体产品需要自定义如设置则在加群界面按返回返回手Q主界面不设置按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
return try {
if (context !is AppCompatActivity){
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
true
} catch (e: Exception) {
false
}
}else{
Utils.toast(context, "请安装QQ客户端")
return false
}
}
/**
@ -551,6 +598,17 @@ object DirectUtils {
jumpActivity(context, bundle)
}
@JvmStatic
fun directToCommunityArticle(context: Context, community: CommunityEntity?, articleId: String?, entrance: String?, path: String?) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
bundle.putString(KEY_TO, ArticleDetailActivity::class.java.name)
bundle.putString(KEY_COMMUNITY_ARTICLE_ID, articleId)
bundle.putParcelable(KEY_COMMUNITY_DATA, community)
jumpActivity(context, bundle)
}
/**
* 跳转到社区专题
*/
@ -716,4 +774,51 @@ object DirectUtils {
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
/**
* 跳转到板块
*/
@JvmStatic
fun directToBlock(context: Context, blockData: SubjectRecommendEntity) {
val bundle = Bundle()
bundle.putString(KEY_TO, BlockActivity::class.java.name)
bundle.putParcelable(KEY_BLOCK_DATA, blockData)
jumpActivity(context, bundle)
}
/**
* 跳转到开服表
*/
@JvmStatic
fun directToGameServers(context: Context, entrance: String, path: String) {
val bundle = Bundle()
bundle.putString(KEY_TO, GameServersActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, ToolBarActivity.mergeEntranceAndPath(entrance, path))
jumpActivity(context, bundle)
}
/**
* 跳转到游戏上传
*/
@JvmStatic
fun directGameUpload(context: Context, entrance: String? = null, path: String? = "") {
val bundle = Bundle()
bundle.putString(KEY_TO, GameSubmissionActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
/**
* 社区文章
*/
@JvmStatic
fun directSimpleArticleList(context: Context, sortType: String, entrance: String? = null, path: String? = "") {
val bundle = Bundle()
bundle.putString(KEY_TO, SimpleArticleListActivity::class.java.name)
bundle.putString(KEY_TYPE, sortType)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
jumpActivity(context, bundle)
}
}

View File

@ -271,6 +271,16 @@ public class DisplayUtils {
return metrics.heightPixels;
}
public static int getToastOffset() {
int i = Resources.getSystem().getIdentifier("toast_y_offset", "dimen", "android");
return HaloApp.getInstance().getApplication().getResources().getDimensionPixelSize(i);
}
public static int getToastDefaultGravity() {
int i = Resources.getSystem().getIdentifier("config_toastDefaultGravity", "integer", "android");
return HaloApp.getInstance().getApplication().getResources().getInteger(i);
}
public static boolean hasSoftKeys(Context context) {
if (!(context instanceof Activity)) return false;

View File

@ -1,5 +1,6 @@
package com.gh.common.util
import com.gh.common.filter.RegionSettingHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.retrofit.Response
@ -18,8 +19,12 @@ object DownloadHelper {
* @param block 成功添加下载任务后执行的代码块
*/
fun createABrandNewDownloadTaskQuietly(gameId: String? = "", packageName: String? = "", block: () -> Unit) {
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
return
}
RetrofitManager.getInstance(HaloApp.getInstance().application)
.api
.sensitiveApi
.getGameDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())

View File

@ -8,6 +8,12 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.common.dialog.CertificationDialog;
import com.gh.common.dialog.DeviceRemindDialog;
@ -34,12 +40,6 @@ 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 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
*/
@ -134,16 +134,23 @@ public class DownloadItemUtils {
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform) {
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false);
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false, null);
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform, boolean hideDownloadBtnIfNoAvailableContent) {
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, hideDownloadBtnIfNoAvailableContent);
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, hideDownloadBtnIfNoAvailableContent, null);
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform, PluginLocation pluginLocation, boolean hideDownloadBtnIfNoAvailableContent) {
boolean isShowPlatform, String briefStyle) {
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false, briefStyle);
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform, PluginLocation pluginLocation,
boolean hideDownloadBtnIfNoAvailableContent,
@Nullable String briefStyle) {
// 控制是否显示下载按钮
if (!Config.isShowDownload(gameEntity.getId()) || context.getString(R.string.app_name).equals(gameEntity.getName())) {
@ -154,9 +161,7 @@ public class DownloadItemUtils {
// 显示预约
if (gameEntity.isReservable()) {
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
updateItemViewStatus(holder, false, briefStyle);
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
holder.gameDownloadBtn.setText("预约");
holder.gameDownloadBtn.setTextColor(Color.WHITE);
@ -174,9 +179,7 @@ public class DownloadItemUtils {
LinkEntity h5LinkEntity = gameEntity.getH5Link();
String offStatus = gameEntity.getDownloadOffStatus();
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
updateItemViewStatus(holder, false, briefStyle);
if (h5LinkEntity != null) {
if ("play".equals(h5LinkEntity.getType())) {
@ -201,16 +204,16 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setClickable(false);
}
} else if (gameEntity.getApk().size() == 1) {
updateNormalItem(context, holder, gameEntity, isShowPlatform, pluginLocation);
updateNormalItem(context, holder, gameEntity, isShowPlatform, pluginLocation, briefStyle);
} else {
updatePluginItem(context, holder, gameEntity, isShowPlatform, pluginLocation);
updatePluginItem(context, holder, gameEntity, isShowPlatform, pluginLocation, briefStyle);
}
}
// 更新正常的条目只有一个apk包
static void updateNormalItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform, PluginLocation pluginLocation) {
boolean isShowPlatform, PluginLocation pluginLocation, String briefStyle) {
final ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
final ApkEntity apkEntity = gameEntity.getApk().get(0);
@ -226,14 +229,12 @@ public class DownloadItemUtils {
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
updateItemViewStatus(holder, false, briefStyle);
}
// 更新插件的条目有多个apk包
private static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform, PluginLocation pluginLocation) {
boolean isShowPlatform, PluginLocation pluginLocation, String briefStyle) {
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
@ -252,18 +253,14 @@ public class DownloadItemUtils {
return;
}
}
holder.gameDes.setVisibility(View.VISIBLE);
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
updateItemViewStatus(holder, false, briefStyle);
}
// 更改进度条和提示文本的状态
public static void changeStatus(Context context, GameViewHolder holder, DownloadEntity downloadEntity,
boolean isShowPlatform, boolean isNormal) {
holder.gameDes.setVisibility(View.GONE);
holder.gameProgressbar.setVisibility(View.VISIBLE);
holder.gameInfo.setVisibility(View.VISIBLE);
updateItemViewStatus(holder, true, null);
String platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
@ -345,6 +342,29 @@ public class DownloadItemUtils {
}
}
private static void updateItemViewStatus(GameViewHolder holder, boolean hasDownload, @Nullable String briefStyle) {
if (hasDownload) {
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
holder.gameDes.setVisibility(View.GONE);
holder.gameProgressbar.setVisibility(View.VISIBLE);
holder.gameInfo.setVisibility(View.VISIBLE);
} else {
holder.gameProgressbar.setVisibility(View.GONE);
holder.gameInfo.setVisibility(View.GONE);
if (briefStyle != null && briefStyle.contains("star")) {
if (holder.gameRating != null) holder.gameRating.setVisibility(View.VISIBLE);
} else {
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
}
if (TextUtils.isEmpty(briefStyle) || briefStyle.contains("brief")) {
holder.gameDes.setVisibility(View.VISIBLE);
} else {
holder.gameDes.setVisibility(View.GONE);
}
}
}
public static void setOnClickListener(final Context context,
final TextView downloadBtn,
final GameEntity gameEntity,
@ -429,7 +449,7 @@ public class DownloadItemUtils {
LinkEntity linkEntity = gameEntity.getH5Link();
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
if (isPlay) {
HistoryHelper.insertGameEntity(gameEntity);
}

View File

@ -88,30 +88,33 @@ object DownloadNotificationHelper {
else -> builder.setSortKey("C")
}
val notification = builder.build()
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
tryCatchInRelease {
val notification = builder.build() // 可能会抛出异常
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
if (entity.status == DownloadStatus.delete
|| entity.status == DownloadStatus.cancel
|| entity.status == DownloadStatus.hijack
|| entity.status == DownloadStatus.notfound
|| entity.status == DownloadStatus.overflow
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty())) {
requireUpdateNotificationGroupDelay = true
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
} else {
if (entity.status != DownloadStatus.downloading) {
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
if (entity.status == DownloadStatus.delete
|| entity.status == DownloadStatus.cancel
|| entity.status == DownloadStatus.hijack
|| entity.status == DownloadStatus.notfound
|| entity.status == DownloadStatus.overflow
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty())) {
requireUpdateNotificationGroupDelay = true
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
} else {
val time = mNotifyMap[entity.path]
val curTime = System.currentTimeMillis()
if (time == null || curTime - time > 2000) {
mNotifyMap[entity.path] = curTime
if (entity.status != DownloadStatus.downloading) {
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
} else {
val time = mNotifyMap[entity.path]
val curTime = System.currentTimeMillis()
if (time == null || curTime - time > 2000) {
mNotifyMap[entity.path] = curTime
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
}
}
}
}
if (requireUpdateNotificationGroupDelay) {
// 虽然运行到这里时 notification 已经被 cancel 了,但在下面的 notificationManager.getActiveNotifications 里它有可能还是 active 状态,
// 这里延时 100 ms 避免出现所有的任务都取消了以后依旧有一条 notification group 常驻

View File

@ -55,9 +55,9 @@ object DownloadObserver {
processHijack(downloadEntity)
val nameAndPlatform = (downloadEntity.name + ":"
+ PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
MtaHelper.onEvent("下载劫持",
"游戏名字", nameAndPlatform,
"网络状态", DeviceUtils.getNetwork(mApplication))
// MtaHelper.onEvent("下载劫持",
// "游戏名字", nameAndPlatform,
// "网络状态", DeviceUtils.getNetwork(mApplication))
return
} else if (DownloadStatus.notfound == downloadEntity.status) {
// 404 Not Found
@ -66,9 +66,9 @@ object DownloadObserver {
downloadManager.cancel(downloadEntity.url)
Utils.toast(mApplication, "该链接已失效!请联系管理员。")
MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
"游戏", downloadEntity.name,
"平台", downloadEntity.platform)
// MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
// "游戏", downloadEntity.name,
// "平台", downloadEntity.platform)
DialogUtils.showAlertDialog(AppManager.getInstance().currentActivity(), "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
@ -90,9 +90,9 @@ object DownloadObserver {
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
"游戏", downloadEntity.name,
"平台", downloadEntity.platform)
// MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
// "游戏", downloadEntity.name,
// "平台", downloadEntity.platform)
debugOnly {
Utils.log("DownloadObserver", "下载自动暂停->" + downloadEntity.toJson())
}
@ -149,11 +149,11 @@ object DownloadObserver {
val pm = mApplication.packageManager
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
if (packageInfo == null) {
MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
"游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
"游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
// "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
//
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
// "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
}
}
@ -199,13 +199,13 @@ object DownloadObserver {
type = ExposureUtils.DownloadType.DOWNLOAD
}
val kv2 = HashMap<String, Any>()
kv2["版本"] = downloadEntity.platform
kv2["状态"] = "下载完成"
kv2["位置"] = downloadEntity.entrance ?: "null"
kv2["游戏分平台"] = downloadEntity.name + "-" + platform
kv2["光环助手版本"] = BuildConfig.VERSION_NAME
DataUtils.onEvent(mApplication, "游戏下载位置", downloadEntity.name, kv2)
// val kv2 = HashMap<String, Any>()
// kv2["版本"] = downloadEntity.platform
// kv2["状态"] = "下载完成"
// kv2["位置"] = downloadEntity.entrance ?: "null"
// kv2["游戏分平台"] = downloadEntity.name + "-" + platform
// kv2["光环助手版本"] = BuildConfig.VERSION_NAME
// DataUtils.onEvent(mApplication, "游戏下载位置", downloadEntity.name, kv2)
if (downloadEntity.isPluggable) {
val kv3 = HashMap<String, Any>()
@ -215,16 +215,18 @@ object DownloadObserver {
type = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD
DataUtils.onEvent(mApplication, "插件化", downloadEntity.name, kv3)
MtaHelper.onEvent(
"插件化_新",
"位置", downloadEntity.entrance,
"游戏", downloadEntity.name + "-" + downloadEntity.platform,
"操作", "下载完成",
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
// MtaHelper.onEvent(
// "插件化_新",
// "位置", downloadEntity.entrance,
// "游戏", downloadEntity.name + "-" + downloadEntity.platform,
// "操作", "下载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
}
ExposureUtils.logADownloadCompleteExposureEvent(
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR)),
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER),
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
gameVersion = downloadEntity.versionName ?: ""),
downloadEntity.platform,
downloadEntity.exposureTrace,
type)

View File

@ -4,8 +4,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.gh.common.avoidcallback.AvoidOnResultManager;
import com.gh.common.avoidcallback.Callback;
import com.gh.gamecenter.MainActivity;
@ -13,6 +11,8 @@ import com.gh.gamecenter.NormalActivity;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.normal.NormalFragment;
import androidx.appcompat.app.AppCompatActivity;
/**
* @author CsHeng
* @Date 2017/4/25
@ -28,6 +28,7 @@ public class EntranceUtils {
public static final String KEY_ID = "id";
public static final String KEY_URL = "url";
public static final String KEY_GAMENAME = "gameName";
public static final String KEY_PACKAGE_MD5 = "package_md5";
public static final String HOST_ARTICLE = "article";
public static final String HOST_UPLOAD_VIDEO = "upload_video";//上传视频
public static final String HOST_VIDEO_SINGLE = "video_single";//指定视频-不能划动
@ -41,6 +42,12 @@ public class EntranceUtils {
public static final String HOST_COLUMN_COLLECTION = "column_collection";//专题合集
public static final String HOST_COMMUNITY_QUESTION_LABEL_DETAIL = "community_question_label_detail";//问题标签详情
public static final String HOST_COMMUNITY_COLUMN_DETAIL = "community_column_detail";//专栏详情
public static final String HOST_BLOCK = "block";//板块
public static final String HOST_SERVER_BLOCK = "server";//开服表板块
public static final String HOST_AMWAY_BLOCK = "amway";//安利墙板块
public static final String HOST_HELP = "help";//Q&A
public static final String HOST_HELP_COLLECTION = "help_collection";//Q&A合集
public static final String HOST_GAME_UPLOAD = "game_upload";//游戏上传
public static final String HOST_COMMUNITY_ARTICLE = "community_article";
public static final String HOST_COMMUNITY_COLUMN = "community_column";
public static final String HOST_GAME = "game";
@ -161,6 +168,7 @@ public class EntranceUtils {
public static final String KEY_SHOW_EDIT_DRAFT = "showEditDraft";
public static final String KEY_ARTICLE_OPEN_IN_NEW_PAGE = "openArticleInNewPage";
public static final String KEY_ONLY_CREATE_DRAFT = "onlyCreateDraft";
public static final String KEY_KAIFU_SELECT_TIME = "kaifuSelectTime";
public static void jumpActivity(Context context, Bundle bundle) {
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);

View File

@ -3,10 +3,11 @@ package com.gh.common.util
import android.animation.Animator
import android.content.ClipboardManager
import android.content.Context
import android.text.Editable
import android.text.Html
import android.text.Spanned
import android.text.TextWatcher
import android.os.Build
import android.text.*
import android.text.style.ClickableSpan
import android.text.style.ImageSpan
import android.text.style.URLSpan
import android.util.TypedValue
import android.view.Gravity
import android.view.View
@ -22,10 +23,15 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.airbnb.lottie.LottieAnimationView
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.DefaultUrlHandler
import com.gh.common.constant.Config
import com.gh.common.constant.Constants
import com.gh.common.view.CenterImageSpan
import com.gh.common.view.CustomLinkMovementMethod
import com.gh.common.view.ExpandTextView
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.google.gson.reflect.TypeToken
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
@ -36,6 +42,7 @@ import okhttp3.MediaType
import okhttp3.RequestBody
import java.net.URI
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.math.abs
/**
@ -191,6 +198,28 @@ inline fun <reified T : Any> T.toJson(): String {
return GsonUtils.toJson(this)
}
fun String.insert(index: Int, string: String): String {
return this.substring(0, index) + string + this.substring(index, this.length)
}
/**
* TextView 内部处理 ul li ol 得跟 Android 版本走,这里换成专属的标签手动处理
*/
fun String.replaceUnsupportedHtmlTag(): String {
return this.replace("<ul", "<hul")
.replace("</ul>", "</hul>")
.replace("<li", "<hli")
.replace("</li>", "</hli>")
.replace("<ol", "<hol")
.replace("</ol>", "</hol>")
}
fun String.containHtmlTag(): Boolean {
val pattern = Pattern.compile("<(\"[^\"]*\"|'[^']*'|[^'\">])*>")
val matcher = pattern.matcher(this)
return matcher.find()
}
/**
* 在限定 interval 里只触发一次 action
*/
@ -285,6 +314,13 @@ fun String.subStringIfPossible(length: Int): String {
}
}
fun String.getFirstElementDividedByDivider(divider: String): String {
if (this.contains(divider)) {
return this.split(divider.toRegex()).toTypedArray()[0]
}
return this
}
fun String.copyTextAndToast(toastText: String = "复制成功") {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@ -442,6 +478,75 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
})
}
/**
* 拦截 TextView 中的 Url Span用应用内页面的形式打开链接
* @param shrankText 未展开时的文字
* @param expandedText 展开后的文字
*/
fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence, expandedText: CharSequence) {
var shrankSsb = shrankText.interceptUrlSpanAndRoundImageSpan()
var expandedSsb = expandedText.interceptUrlSpanAndRoundImageSpan()
// 去掉旧版本 Android 系统 [Html.FROM_HTML_MODE_LEGACY] 产生的两个换行符 (丑陋的代码)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
while (shrankSsb.contains("\n\n")) {
val index = shrankSsb.indexOf("\n\n", 0, true)
shrankSsb = SpannableStringBuilder(shrankSsb.subSequence(0, index)).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length))
}
while (expandedSsb.contains("\n\n")) {
val index = expandedSsb.indexOf("\n\n", 0, true)
expandedSsb = SpannableStringBuilder(expandedSsb.subSequence(0, index)).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length))
}
}
// 去掉多余的 P 标签换行
if (expandedSsb.endsWith("\n", true)) {
expandedSsb = SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length)))
}
movementMethod = CustomLinkMovementMethod.getInstance()
shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, shrankSsb, highlightedTextClickListener = null)
expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, expandedSsb, highlightedTextClickListener = null)
setShrankTextAndExpandedText(shrankSsb, expandedSsb)
}
fun CharSequence.interceptUrlSpanAndRoundImageSpan(): SpannableStringBuilder {
return SpannableStringBuilder.valueOf(this).apply {
getSpans(0, length, URLSpan::class.java).forEach {
setSpan(
object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, R.color.theme_font)
ds.isUnderlineText = false
}
override fun onClick(widget: View) {
if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) {
widget.context.startActivity(WebActivity.getIntent(widget.context, it.url, true))
}
}
},
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
removeSpan(it)
}
getSpans(0, length, ImageSpan::class.java).forEach {
setSpan(
CenterImageSpan(it.drawable),
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
removeSpan(it)
}
}
}
fun Int.toColor(): Int {
return ContextCompat.getColor(HaloApp.getInstance().application, this)
}
@ -473,7 +578,20 @@ inline fun Context.doOnMainProcessOnly(f: () -> Unit) {
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
f.invoke()
} else {
Utils.log("Block one useless sub process method call.")
tryWithDefaultCatch {
Utils.log("Block one useless sub process method call from ${Thread.currentThread().stackTrace[3].methodName} -> ${Thread.currentThread().stackTrace[2].methodName}.")
}
}
}
inline fun doOnMainProcessOnly(f: () -> Unit) {
val processName = PackageUtils.obtainProcessName(HaloApp.getInstance().application)
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
f.invoke()
} else {
tryWithDefaultCatch {
Utils.log("Block one useless sub process method call from ${Thread.currentThread().stackTrace[3].methodName} -> ${Thread.currentThread().stackTrace[2].methodName}.")
}
}
}
@ -562,4 +680,30 @@ fun LottieAnimationView.doOnAnimationEnd(action: () -> Unit) {
}
})
}
/**
* 检查内容是否一致
* @return true:相同 false:不同
*/
fun List<String>?.checkSameFromStringArray(check2: List<String>?): Boolean {
if (this == check2) {
return true
}
if (this == null && check2 == null) {
return true
}
if (this == null || check2 == null) {
return false
}
if (this.size != check2.size) {
return false
}
for (tag in this) {
if (!check2.contains(tag)) return false
}
for (tag in check2) {
if (!this.contains(tag)) return false
}
return true
}

View File

@ -0,0 +1,183 @@
package com.gh.common.util
import android.text.Editable
import android.text.Html.TagHandler
import android.text.Spanned
import android.text.style.BulletSpan
import android.text.style.LeadingMarginSpan
import android.util.Log
import org.xml.sax.XMLReader
import java.util.*
/**
* Implements support for ordered (`<ol>`) and unordered (`<ul>`) lists in to Android TextView.
*
*
* This can be used as follows:<br></br>
* `textView.setText(Html.fromHtml("<ul><li>item 1</li><li>item 2</li></ul>", null, new HtmlListTagHandler()));`
*
*
* Implementation based on code by Juha Kuitunen (https://bitbucket.org/Kuitsi/android-textview-html-list),
* released under Apache License v2.0. Refactored & improved by Matthias Stevens (InThePocket.mobi).
*
*
* **Known issues:**
* * The indentation on nested `<ul>`s isn't quite right (TODO fix this)
* * the `start` attribute of `<ol>` is not supported. Doing so is tricky because
* [Html.TagHandler.handleTag] does not expose tag attributes.
* The only way to do it would be to use reflection to access the attribute information kept by the XMLReader
* (see: http://stackoverflow.com/a/24534689/1084488).
*
* https://bitbucket.org/Kuitsi/android-textview-html-list/src/master/app/src/main/java/fi/iki/kuitsi/listtest/MyTagHandler.java
*
*/
class ExtraTagHandler : TagHandler {
/**
* Keeps track of lists (ol, ul). On bottom of Stack is the outermost list
* and on top of Stack is the most nested list
*/
private val lists = Stack<ListTag>()
/**
* @see android.text.Html.TagHandler.handleTag
*/
override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader) {
if (UL_TAG.equals(tag, ignoreCase = true)) {
if (opening) { // handle <ul>
lists.push(Ul())
} else { // handle </ul>
lists.pop()
}
} else if (OL_TAG.equals(tag, ignoreCase = true)) {
if (opening) { // handle <ol>
lists.push(Ol()) // use default start index of 1
} else { // handle </ol>
lists.pop()
}
} else if (LI_TAG.equals(tag, ignoreCase = true)) {
if (opening) { // handle <li>
lists.peek().openItem(output)
} else { // handle </li>
lists.peek().closeItem(output, lists.size)
}
} else {
Log.d("TagHandler", "Found an unsupported tag $tag")
}
}
/**
* Abstract super class for [Ul] and [Ol].
*/
private abstract class ListTag {
/**
* Opens a new list item.
*
* @param text
*/
open fun openItem(text: Editable) {
if (text.length > 0 && text[text.length - 1] != '\n') {
text.append("\n")
}
val len = text.length
text.setSpan(this, len, len, Spanned.SPAN_MARK_MARK)
}
/**
* Closes a list item.
*
* @param text
* @param indentation
*/
fun closeItem(text: Editable, indentation: Int) {
if (text.length > 0 && text[text.length - 1] != '\n') {
text.append("\n")
}
val replaces = getReplaces(text, indentation)
val len = text.length
val listTag = getLast(text)
val where = text.getSpanStart(listTag)
text.removeSpan(listTag)
if (where != len) {
for (replace in replaces) {
text.setSpan(replace, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
protected abstract fun getReplaces(text: Editable?, indentation: Int): Array<Any>
/**
* Note: This knows that the last returned object from getSpans() will be the most recently added.
*
* @see Html
*/
private fun getLast(text: Spanned): ListTag? {
val listTags = text.getSpans(0, text.length, ListTag::class.java)
return if (listTags.size == 0) {
null
} else listTags[listTags.size - 1]
}
}
/**
* Class representing the unordered list (`<ul>`) HTML tag.
*/
private class Ul : ListTag() {
override fun getReplaces(text: Editable?, indentation: Int): Array<Any> {
// Nested BulletSpans increases distance between BULLET_SPAN and text, so we must prevent it.
var bulletMargin = INDENT_PX
if (indentation > 1) {
bulletMargin = INDENT_PX - BULLET_SPAN.getLeadingMargin(true)
if (indentation > 2) {
// This get's more complicated when we add a LeadingMarginSpan into the same line:
// we have also counter it's effect to BulletSpan
bulletMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX
}
}
return arrayOf(
LeadingMarginSpan.Standard(LIST_ITEM_INDENT_PX * (indentation - 1)),
BulletSpan(bulletMargin)
)
}
}
/**
* Class representing the ordered list (`<ol>`) HTML tag.
*/
private class Ol
/**
* Creates a new `<ul>` with start index of 1.
*/ @JvmOverloads constructor(private var nextIdx: Int = 1) : ListTag() {
override fun openItem(text: Editable) {
super.openItem(text)
text.append(Integer.toString(nextIdx++)).append(". ")
}
override fun getReplaces(text: Editable?, indentation: Int): Array<Any> {
var numberMargin = LIST_ITEM_INDENT_PX * (indentation - 1)
if (indentation > 2) {
// Same as in ordered lists: counter the effect of nested Spans
numberMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX
}
return arrayOf(LeadingMarginSpan.Standard(numberMargin))
}
/**
* Creates a new `<ul>` with given start index.
*
* @param nextIdx
*/
}
companion object {
private const val OL_TAG = "hol"
private const val UL_TAG = "hul"
private const val LI_TAG = "hli"
/**
* List indentation in pixels. Nested lists use multiple of this.
*/
private const val INDENT_PX = 10
private const val LIST_ITEM_INDENT_PX = INDENT_PX * 2
private val BULLET_SPAN = BulletSpan(INDENT_PX)
}
}

View File

@ -1,19 +1,28 @@
package com.gh.common.util
import android.content.Context
import android.annotation.SuppressLint
import android.text.TextUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SubjectEntity
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.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
/**
* 首页补充游戏库辅助类
*/
object GameRepositoryHelper {
object GameSubstituteRepositoryHelper {
private const val KEY_GAME_REPOSITORY = "game_repository"
private const val KEY_GAME_REPOSITORY = "game_substitute_repository"
private var mSubstitutableGameIdSet = hashSetOf<String>()
private var mApi = RetrofitManager.getInstance(HaloApp.getInstance().application).api
private val mSensitiveApi = RetrofitManager.getInstance(HaloApp.getInstance().application).sensitiveApi
private var mApplicationContext = HaloApp.getInstance().application
var gameCollectionList: List<SubjectEntity> = arrayListOf()
@ -25,11 +34,8 @@ object GameRepositoryHelper {
* 获取游戏补充库
*/
@JvmStatic
fun getGameRepository(context: Context) {
RetrofitManager.getInstance(context)
.api
.reserveColumns
fun updateGameSubstituteRepository() {
mSensitiveApi.reserveColumns
.subscribeOn(Schedulers.io())
.subscribe(object : Response<List<SubjectEntity>>() {
override fun onResponse(response: List<SubjectEntity>?) {
@ -38,27 +44,41 @@ object GameRepositoryHelper {
updateGameRepository(response)
}
})
}
@JvmStatic
@SuppressLint("CheckResult")
fun updateSubstitutableGames() {
mApplicationContext.doOnMainProcessOnly {
val single = if (UserManager.getInstance().isLoggedIn) {
mApi.getIdListOfPlayedGames(UserManager.getInstance().userId, Utils.getTime(mApplicationContext))
} else {
mApi.getIdListOfDownloadedGames(HaloApp.getInstance().gid, Utils.getTime(mApplicationContext))
}
single.subscribeOn(Schedulers.io()).subscribe(object : BiResponse<List<String>>() {
override fun onSuccess(data: List<String>) {
mSubstitutableGameIdSet = data.toHashSet()
}
})
}
}
/**
* 刷新内存中的游戏库即从 SP 中再读一次
*/
@JvmStatic
fun refreshGameRepository() = loadSavedRepository()
fun refreshRepositoryFromLocal() = loadSavedRepository()
private fun loadSavedRepository() {
gameCollectionList = SPUtils.getString(KEY_GAME_REPOSITORY).toObject() ?: arrayListOf()
}
fun updateGameRepository(subjects: List<SubjectEntity>?) {
private fun updateGameRepository(subjects: List<SubjectEntity>?) {
if (subjects == null) return
SPUtils.setString(KEY_GAME_REPOSITORY, subjects.toJson())
gameCollectionList = subjects
}
/**
@ -66,7 +86,7 @@ object GameRepositoryHelper {
* @param collectionId 补充游戏库相应专题 ID
* @param gameIdList 该专题里已经包含的游戏 ID 列表
*/
fun getOneUniqueGame(collectionId: String?, gameIdList: HashSet<String>): GameEntity? {
private fun getOneUniqueGame(collectionId: String?, gameIdList: HashSet<String>): GameEntity? {
collectionId?.let {
val collection = gameCollectionList.find { it.id == collectionId }
collection?.let {
@ -82,10 +102,13 @@ object GameRepositoryHelper {
return null
}
fun replaceInstalledApp(gameList: MutableList<GameEntity>,
alreadyDisplayedGameIdSet: HashSet<String>,
relatedCollectionId: String,
shouldLogReplaceEvent: Boolean) {
/**
* 替换游戏包括 已安装历史下载历史已安装等类型
*/
fun replaceGames(gameList: MutableList<GameEntity>,
alreadyDisplayedGameIdSet: HashSet<String>,
relatedCollectionId: String,
shouldLogReplaceEvent: Boolean) {
val positionOfTheGameToReplaceList = arrayListOf<Int>()
// 标记需要替换的已安装游戏
@ -96,23 +119,32 @@ object GameRepositoryHelper {
continue
}
var isThisPositionAdded = false
var isThisPositionLabeled = false
// 从 游戏ID 判断当前游戏是否需要被替换
if (mSubstitutableGameIdSet.contains(game.id)) {
positionOfTheGameToReplaceList.add(index)
isThisPositionLabeled = true
}
// 检查是否已安装该游戏里同包名的 APK
for (apk in game.getApk()) {
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
// 将该位置的游戏标记为需要替换
positionOfTheGameToReplaceList.add(index)
isThisPositionAdded = true
break
if (!isThisPositionLabeled) {
for (apk in game.getApk()) {
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
// 将该位置的游戏标记为需要替换
positionOfTheGameToReplaceList.add(index)
isThisPositionLabeled = true
break
}
}
}
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
if (!isThisPositionAdded) {
if (!isThisPositionLabeled) {
var relatedPackageList = arrayListOf<String>()
for (entity in PackageHelper.relatedPackageList) {
if (entity.gameId == game.id) {
relatedPackageList = ArrayList(entity.packages)
relatedPackageList = ArrayList(entity.packages!!)
break
}
}
@ -139,14 +171,17 @@ object GameRepositoryHelper {
}
}
private fun isThisGameUnique(game: GameEntity, gameIdList: HashSet<String>): Boolean {
// 若该补充游戏已经存在关联关系,判定为非唯一
// 判断该游戏是否出现在已安装列表
if (mSubstitutableGameIdSet.contains(game.id)) return false
// 该补充游戏是否已经存在关联关系
for (relatedId in game.relatedGameIds!!) {
if (gameIdList.contains(relatedId)) {
return false
}
}
for (apk in game.getApk()) {
// 检查本地是否已安装该游戏,已过滤那部分框架服务的包名
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {

View File

@ -0,0 +1,50 @@
package com.gh.common.util
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.HomePluggableFilterEntity
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
object HomePluggableHelper {
private val mHomePluggableFilterDao = AppDatabase.getInstance(HaloApp.getInstance().application).homePluggableFilterDao()
@JvmStatic
fun setHomePluggableFilterData(gameEntity: GameEntity, isNever: Boolean) {
val apkList = gameEntity.getApk()
if (apkList.isNotEmpty()) {
val apk = apkList.first()
val tag = if (isNever) "never" else apk.version ?: ""
mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever))
}
}
@JvmStatic
fun showHomePluggable(gameEntity: GameEntity): Boolean {
val apkList = gameEntity.getApk()
if (apkList.isNotEmpty()) {
val apk = apkList.first()
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
if (filterData?.active == true) {
val filterTag = filterData.tag
return filterTag != "never" && apk.version != filterTag
}
}
return true
}
@JvmStatic
fun getPermanentInactivePluggablePackage() = mHomePluggableFilterDao.getDataByTag("never")
@JvmStatic
fun activationFilterData() {
val filterList = mHomePluggableFilterDao.getDataByActive(false)
if (filterList != null) {
for (entity in filterList) {
entity.active = true
}
mHomePluggableFilterDao.addData(filterList)
}
}
}

View File

@ -283,7 +283,7 @@ public class LogUtils {
uploadToReservation(object);
}
private static void uploadToCommunity(JSONObject object) {
uploadToCommunity(object, false);
}
@ -419,4 +419,89 @@ public class LogUtils {
}
uploadVideoStreaming(object);
}
private static void uploadShare(JSONObject object) {
Meta meta = MetaUtil.INSTANCE.getMeta();
JSONObject metaObject = new JSONObject();
try {
metaObject.put("android_id", meta.getAndroid_id());
metaObject.put("android_sdk", meta.getAndroid_sdk());
metaObject.put("android_version", meta.getAndroid_version());
metaObject.put("appVersion", meta.getAppVersion());
metaObject.put("channel", meta.getChannel());
metaObject.put("gid", meta.getGid());
metaObject.put("imei", meta.getImei());
metaObject.put("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
metaObject.put("model", meta.getModel());
metaObject.put("network", meta.getNetwork());
metaObject.put("os", meta.getOs());
metaObject.put("userId", meta.getUserId());
object.put("event", "SHARE");
object.put("meta", metaObject);
object.put("timestamp", System.currentTimeMillis() / 1000);
} catch (JSONException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
LoghubUtils.log(object, "event", false);
}
public static void uploadShareEnter(String entrance, String url, String title, String summary, String resourceId) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("action", "entrance_source");
payloadObject.put("entrance", entrance);
payloadObject.put("url", url);
payloadObject.put("title", title);
payloadObject.put("summary", summary);
payloadObject.put("resource_id", resourceId);
object.put("payload", payloadObject);
} catch (JSONException e) {
e.printStackTrace();
}
uploadShare(object);
}
public static void uploadShareType(String shareType, String entrance, String url, String title, String summary, String resourceId) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("action", "share_type");
payloadObject.put("share_type", shareType);
payloadObject.put("entrance", entrance);
payloadObject.put("url", url);
payloadObject.put("title", title);
payloadObject.put("summary", summary);
payloadObject.put("resource_id", resourceId);
object.put("payload", payloadObject);
} catch (JSONException e) {
e.printStackTrace();
}
uploadShare(object);
}
public static void uploadShareResult(String shareType, String entrance, String shareResult, String url, String title, String summary, String resourceId) {
JSONObject object = new JSONObject();
JSONObject payloadObject = new JSONObject();
try {
object.put("action", "share_result");
payloadObject.put("share_type", shareType);
payloadObject.put("entrance", entrance);
payloadObject.put("share_result", shareResult);
payloadObject.put("url", url);
payloadObject.put("title", title);
payloadObject.put("summary", summary);
payloadObject.put("resource_id", resourceId);
object.put("payload", payloadObject);
} catch (JSONException e) {
e.printStackTrace();
}
uploadShare(object);
}
}

View File

@ -23,7 +23,7 @@ import com.tencent.tauth.Tencent
import com.tencent.tauth.UiError
import org.json.JSONException
import org.json.JSONObject
import java.lang.ref.WeakReference
/**
* 第三方登录辅助类
@ -37,12 +37,12 @@ object LoginHelper {
private var mTencent: Tencent // QQ
private var mIWXAPI: IWXAPI // 微信
private var mSsoHandler: SsoHandler? = null // 微博 // TODO 完成回调时清掉这个 handler
private var mSsoHandler: WeakReference<SsoHandler>? = null // 微博
private var mQqLoginListener: IUiListener
private var mAccessToken: Oauth2AccessToken? = null // weibo
private var mLoginCallback: LoginCallback? = null
private var mLoginCallback: WeakReference<LoginCallback>? = null
init {
val context = HaloApp.getInstance().application.applicationContext
@ -64,11 +64,11 @@ object LoginHelper {
content.put("access_token_expire", Utils.getTime(context) + o.getLong("expires_in"))
content.put("access_token", o.getString("access_token"))
mLoginCallback?.onLoginSuccess(LoginTag.qq, content) // 回调QQ登录成功
mLoginCallback?.get()?.onLoginSuccess(LoginTag.qq, content) // 回调QQ登录成功
} catch (e: JSONException) {
val errorString = "QQ登录数据回调异常$e"
mLoginCallback?.onLoginFailure(LoginTag.qq, errorString) // 回调QQ登录失败
mLoginCallback?.get()?.onLoginFailure(LoginTag.qq, errorString) // 回调QQ登录失败
Utils.log(errorString)
e.printStackTrace()
@ -77,12 +77,12 @@ object LoginHelper {
}
override fun onCancel() {
mLoginCallback?.onLoginFailure(LoginTag.qq,"登录取消")
mLoginCallback?.get()?.onLoginFailure(LoginTag.qq, "登录取消")
Utils.log("QQ 登录取消")
}
override fun onError(p0: UiError?) {
mLoginCallback?.onLoginFailure(LoginTag.qq,"登录失败")
mLoginCallback?.get()?.onLoginFailure(LoginTag.qq, "登录失败")
Utils.log("QQ 登录失败")
}
}
@ -99,23 +99,23 @@ object LoginHelper {
@JvmStatic
fun onWechatLoginSuccess(content: JSONObject) {
mLoginCallback?.onLoginSuccess(LoginTag.wechat, content)
mLoginCallback?.get()?.onLoginSuccess(LoginTag.wechat, content)
}
@JvmStatic
fun onWechatLoginFailure(error: String) {
mLoginCallback?.onLoginFailure(LoginTag.wechat, error)
mLoginCallback?.get()?.onLoginFailure(LoginTag.wechat, error)
}
@JvmStatic
fun onWeiboLoginCallback(requestCode: Int, resultCode: Int, data: Intent?) {
mSsoHandler?.authorizeCallBack(requestCode, resultCode, data)
mSsoHandler?.get()?.authorizeCallBack(requestCode, resultCode, data)
}
// QQ登录
@JvmStatic
fun loginWithQQ(loginCallback: LoginCallback, activity: Activity) {
mLoginCallback = loginCallback
mLoginCallback = WeakReference(loginCallback)
if (!mTencent.isSessionValid) {
Utils.log("QQLogin")
mTencent.login(activity, "all", mQqLoginListener)
@ -132,7 +132,7 @@ object LoginHelper {
// 微信登录
@JvmStatic
fun loginWithWechat(loginCallback: LoginCallback) {
mLoginCallback = loginCallback
mLoginCallback = WeakReference(loginCallback)
val register = mIWXAPI.registerApp(Config.WECHAT_APPID)
val req = SendAuth.Req()
@ -149,9 +149,9 @@ object LoginHelper {
// 微博登录
@JvmStatic
fun loginWithWeibo(loginCallback: LoginCallback, context: Activity) {
mLoginCallback = loginCallback
mSsoHandler = SsoHandler(context)
mSsoHandler?.authorizeClientSso(object : WbAuthListener {
mLoginCallback = WeakReference(loginCallback)
mSsoHandler = WeakReference(SsoHandler(context))
mSsoHandler?.get()?.authorizeClientSso(object : WbAuthListener {
override fun onSuccess(token: Oauth2AccessToken?) {
token?.let {
RuntimeUtils.getInstance().runOnUiThread {
@ -170,17 +170,17 @@ object LoginHelper {
content.put("access_token_expire", Utils.getTime(context) + token.expiresTime)
content.put("refresh_token", token.refreshToken)
// content.put("refresh_token_expire", Utils.getTime(mContext) + 86400 * 30); // refresh_token 有效期30天
mLoginCallback?.onLoginSuccess(LoginTag.weibo, content)// 微博 登录回调
mLoginCallback?.get()?.onLoginSuccess(LoginTag.weibo, content)// 微博 登录回调
}
}
}
override fun onFailure(p0: WbConnectErrorMessage?) {
mLoginCallback?.onLoginFailure(LoginTag.weibo, "微博登录需要客户端支持,请先安装微博")
mLoginCallback?.get()?.onLoginFailure(LoginTag.weibo, "微博登录需要客户端支持,请先安装微博")
}
override fun cancel() {
mLoginCallback?.onLoginFailure(LoginTag.weibo, "取消授权")
mLoginCallback?.get()?.onLoginFailure(LoginTag.weibo, "取消授权")
}
})
// 第一次启动本应用AccessToken 不可用

View File

@ -4,6 +4,8 @@ import android.content.Context;
import android.graphics.Color;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.NewsEntity;
import com.gh.gamecenter.retrofit.Response;
@ -78,7 +80,7 @@ public class NewsUtils {
/**
* 设置新闻类型
*/
public static void setNewsType(TextView textView, String type, int priority, int position) {
public static void setNewsType(TextView textView, @Nullable String type, int priority, int position) {
if (priority != 0) {
if (position == 0) {
textView.setText(R.string.article_top);
@ -92,7 +94,7 @@ public class NewsUtils {
}
textView.setTextColor(Color.WHITE);
switch (type) {
switch (type != null ? type : "") {
case "活动":
textView.setBackgroundResource(R.drawable.textview_orange_style);
break;

View File

@ -0,0 +1,88 @@
package com.gh.common.util
import com.alibaba.sdk.android.oss.ClientConfiguration
import com.alibaba.sdk.android.oss.ClientException
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.ServiceException
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask
import com.alibaba.sdk.android.oss.model.PutObjectRequest
import com.alibaba.sdk.android.oss.model.PutObjectResult
import com.gh.gamecenter.entity.OssEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
object OssUploadUtils {
//上传文件类型
enum class UploadType(val value: String) {
GAME("game")//后缀apk
}
//获取Oss配置
private fun getOssUpdateConfig(type: UploadType): Single<OssEntity> {
return RetrofitManager.getInstance(HaloApp.getInstance().application)
.api
.getOssUpdateConfig(type.value)
.subscribeOn(Schedulers.io())
}
//异步上传文件
@JvmStatic
fun uploadFile(path: String, uploadType: UploadType, listener: OnUploadFileListener?): Disposable {
return getOssUpdateConfig(uploadType)
.subscribeOn(Schedulers.io())
.flatMap { mOssEntity ->
Single.create<String> {
val conf = ClientConfiguration()
conf.connectionTimeout = 15 * 1000
conf.socketTimeout = 15 * 1000
conf.maxConcurrentRequest = 5
conf.maxErrorRetry = 2
val credentialProvider = OSSStsTokenCredentialProvider(mOssEntity.accessKeyId, mOssEntity.accessKeySecret, mOssEntity.securityToken)
val oss = OSSClient(HaloApp.getInstance().application, mOssEntity.endPoint, credentialProvider, conf)
// 构造上传请求
val put = PutObjectRequest(mOssEntity.bucket, mOssEntity.key, path)
val task: OSSAsyncTask<*> = oss.asyncPutObject(put, object : OSSCompletedCallback<PutObjectRequest?, PutObjectResult> {
override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult) {
it.onSuccess(mOssEntity.domain + mOssEntity.key)
}
override fun onFailure(request: PutObjectRequest?, clientExcepion: ClientException?, serviceException: ServiceException?) {
clientExcepion?.printStackTrace()
serviceException?.printStackTrace()
if (serviceException != null) {
it.onError(Throwable(message = clientExcepion?.message + "/" + serviceException.message))
}
}
})
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { url, throwable ->
if (url.isNotEmpty()) {
listener?.onSuccess(url)
return@subscribe
}
if (throwable != null) {
listener?.onError(throwable)
}
}
}
interface OnUploadFileListener {
fun onSuccess(url: String)
fun onError(e: Throwable?)
}
}

View File

@ -0,0 +1,135 @@
package com.gh.common.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.widget.TextView;
import androidx.core.content.res.ResourcesCompat;
import com.gh.gamecenter.R;
import com.halo.assistant.HaloApp;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import com.squareup.picasso.Transformation;
public class PicassoImageGetter implements Html.ImageGetter {
private TextView textView = null;
public PicassoImageGetter() {
}
public PicassoImageGetter(TextView target) {
textView = target;
}
@Override
public Drawable getDrawable(String source) {
BitmapDrawablePlaceHolder drawable = new BitmapDrawablePlaceHolder();
Context context = HaloApp.getInstance().getApplication();
Picasso.with(context)
.load(source)
.transform(new CircleTransformation())
.placeholder(ResourcesCompat.getDrawable(context.getResources(), R.drawable.personal_user_default_icon, context
.getTheme()))
.into(drawable);
return drawable;
}
private class BitmapDrawablePlaceHolder extends BitmapDrawable implements Target {
protected Drawable drawable;
@Override
public void draw(final Canvas canvas) {
if (drawable != null) {
Paint.FontMetricsInt fmPaint = textView.getPaint().getFontMetricsInt();
float fontHeight = fmPaint.descent - fmPaint.ascent;
float textSize = textView.getTextSize();
if (fontHeight - textSize > 0) {
canvas.translate((fontHeight - textSize) / 2, 0);
}
drawable.draw(canvas);
}
}
@SuppressWarnings("SuspiciousNameCombination")
public void setDrawable(Drawable drawable) {
try {
this.drawable = drawable;
Paint.FontMetricsInt fmPaint = textView.getPaint().getFontMetricsInt();
int fontHeight = fmPaint.descent - fmPaint.ascent;
int textSize = (int) textView.getTextSize();
drawable.setBounds(0, 0, textSize, textSize);
setBounds(0, 0, fontHeight, fontHeight);
if (textView != null) {
textView.setText(textView.getText());
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
setDrawable(new BitmapDrawable(HaloApp.getInstance()
.getApplication()
.getResources(), bitmap));
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
setDrawable(placeHolderDrawable);
}
}
private class CircleTransformation implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap.Config config = source.getConfig() != null ? source.getConfig() : Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(size, size, config);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circle";
}
}
}

View File

@ -36,43 +36,23 @@ import io.reactivex.schedulers.Schedulers;
import retrofit2.HttpException;
public class PlatformUtils {
private static PlatformUtils mInstance;
private Context context;
private ArrayMap<String, String> platformMap;
private ArrayMap<String, Integer> platformPicMap;
private ArrayMap<String, String> platformPicUrlMap;
private ArrayMap<String, String> platformColorMap;
private boolean isCheck = false;
private boolean isUpdate = false;
private PlatformUtils(Context con) {
this.context = con.getApplicationContext();
initMap();
}
private void initMap() {
ArrayMap<String, Integer> platformPicMap = new ArrayMap<>();
platformPicMap.put("360", R.drawable.platform_360);
platformPicMap.put("37wan", R.drawable.platform_37);
platformPicMap.put("91", R.drawable.platform_91);
platformPicMap.put("9u", R.drawable.platform_9u);
platformPicMap.put("anzhi", R.drawable.platform_anzhi);
platformPicMap.put("baidu", R.drawable.platform_baidu);
platformPicMap.put("dangle", R.drawable.platform_dl);
platformPicMap.put("ewan", R.drawable.platform_ewan);
platformPicMap.put("gf", R.drawable.platform_gf);
platformPicMap.put("gf-w", R.drawable.platform_gfw);
platformPicMap.put("huawei", R.drawable.platform_hw);
platformPicMap.put("mi", R.drawable.platform_mi);
platformPicMap.put("oppo", R.drawable.platform_oppo);
platformPicMap.put("ouwan", R.drawable.platform_ouwan);
platformPicMap.put("pps", R.drawable.platform_pps);
platformPicMap.put("vivo", R.drawable.platform_vivo);
platformPicMap.put("wdj", R.drawable.platform_wdj);
ArrayMap<String, String> platformColorMap = new ArrayMap<>();
platformColorMap.put("360", "#218FA4");
platformColorMap.put("37wan", "#F5BD20");
@ -91,24 +71,20 @@ public class PlatformUtils {
platformColorMap.put("pps", "#FF8C27");
platformColorMap.put("vivo", "#3FA5E3");
platformColorMap.put("wdj", "#5ABA3F");
ArrayMap<String, String> platformMap = new ArrayMap<>();
ArrayMap<String, String> platformPicUrlMap = new ArrayMap<>();
SharedPreferences sharedPreferences = context.getSharedPreferences(
"gh_platform", Context.MODE_PRIVATE);
SharedPreferences sharedPreferences = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
Set<String> set = sharedPreferences.getStringSet("platform", null);
if (set == null) {
Properties properties = new Properties();
try {
properties
.load(context.getAssets().open("platform.properties"));
properties.load(context.getAssets().open("platform.properties"));
Set<String> pset = new HashSet<>();
for (Object object : properties.keySet()) {
platformMap.put(object.toString(),
(String) properties.get(object));
pset.add(object.toString() + "="
+ (String) properties.get(object) + "=" + "=");
platformMap.put(object.toString(), (String) properties.get(object));
pset.add(object.toString() + "=" + (String) properties.get(object) + "=" + "=");
}
Editor editor = sharedPreferences.edit();
editor.putStringSet("platform", pset);
@ -133,11 +109,10 @@ public class PlatformUtils {
// checkPlatformPic(urls);
}
}
updatePlatform(platformMap, platformPicMap, platformPicUrlMap,
platformColorMap);
updatePlatform(platformMap, platformPicUrlMap, platformColorMap);
}
private void checkPlatformPic(final ArrayList<String> urls) {
isCheck = true;
File file = new File(FileUtils.getPlatformPicDir(context));
@ -154,53 +129,41 @@ public class PlatformUtils {
}
}
if (urls.size() != 0) {
AppExecutor.getIoExecutor().execute(new Runnable() {
@Override
public void run() {
int success = 0;
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
String savePath = FileUtils.getPlatformPicDir(context)
+ File.separator
+ url.substring(url.lastIndexOf("/") + 1);
int code = FileUtils.downloadFile(url, savePath);
if (code == HttpURLConnection.HTTP_OK) {
success++;
}
AppExecutor.getIoExecutor().execute(() -> {
int success = 0;
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
String savePath = FileUtils.getPlatformPicDir(context) + File.separator + url
.substring(url.lastIndexOf("/") + 1);
int code = FileUtils.downloadFile(url, savePath);
if (code == HttpURLConnection.HTTP_OK) {
success++;
}
if (success == urls.size()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
}
});
}
isCheck = false;
}
if (success == urls.size()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(() -> EventBus.getDefault().post(new EBReuse("PlatformChanged")));
}
isCheck = false;
});
} else {
isCheck = false;
}
}
private void updatePlatform(ArrayMap<String, String> pMap,
ArrayMap<String, Integer> pPMap, ArrayMap<String, String> pUMap,
ArrayMap<String, String> pCMap) {
private void updatePlatform(ArrayMap<String, String> pMap, ArrayMap<String, String> pUMap, ArrayMap<String, String> pCMap) {
platformMap = pMap;
platformPicMap = pPMap;
platformPicUrlMap = pUMap;
platformColorMap = pCMap;
}
public static PlatformUtils getInstance(Context context) {
if (mInstance == null) {
mInstance = new PlatformUtils(context);
}
return mInstance;
}
public String getPlatformColor(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return "#BB3D42";
@ -209,26 +172,16 @@ public class PlatformUtils {
if (color != null) {
return color;
}
int themeColor = ContextCompat.getColor(HaloApp.getInstance().getApplication(), R.color.theme);
int themeColor = ContextCompat.getColor(HaloApp.getInstance()
.getApplication(), R.color.theme);
return String.format("#%06X", 0xFFFFFF & themeColor);
}
public int getPlatformPic(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return R.drawable.platform_gf;
}
Integer id = platformPicMap.get(platform);
if (id != null) {
return id;
}
return 0;
}
public String getPlatformPicUrl(String platform) {
return platformPicUrlMap.get(platform);
}
public String getPlatformName(String platform) {
if ("".equals(platform) || "官方版".equals(platform)) {
return "官方版";
@ -242,38 +195,40 @@ public class PlatformUtils {
}
return platform;
}
public void getPlatform() {
if (isUpdate) {
return;
}
isUpdate = true;
RetrofitManager.getInstance(context).getApi().getGamePlatform()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<PlatformEntity>>() {
@Override
public void onResponse(List<PlatformEntity> response) {
Set<String> platformSet = new HashSet<>();
for (PlatformEntity platformEntity : response) {
platformSet.add(platformEntity.toString());
}
SharedPreferences sp = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
sp.edit().putStringSet("platform", platformSet).apply();
initMap();
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
String today = format.format(new Date());
sp.edit().putString("refresh_time", today).apply();
isUpdate = false;
RetrofitManager.getInstance(context)
.getApi()
.getGamePlatform()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<PlatformEntity>>() {
@Override
public void onResponse(List<PlatformEntity> response) {
Set<String> platformSet = new HashSet<>();
for (PlatformEntity platformEntity : response) {
platformSet.add(platformEntity.toString());
}
@Override
public void onFailure(HttpException e) {
isUpdate = false;
}
});
SharedPreferences sp = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
sp.edit().putStringSet("platform", platformSet).apply();
initMap();
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
String today = format.format(new Date());
sp.edit().putString("refresh_time", today).apply();
isUpdate = false;
}
@Override
public void onFailure(HttpException e) {
isUpdate = false;
}
});
}
}

View File

@ -48,9 +48,9 @@ object ReservationHelper {
ReservationRepository.removeReservationFromMemoryAndRefresh(game.id)
if (deleteReservation) {
MtaHelper.onEvent("预约游戏", "取消预约", game.name)
// MtaHelper.onEvent("预约游戏", "取消预约", game.name)
} else {
MtaHelper.onEvent("预约游戏", "删除预约", game.name)
// MtaHelper.onEvent("预约游戏", "删除预约", game.name)
}
refreshCallback.onCallback()
@ -73,9 +73,10 @@ object ReservationHelper {
"暂不删除",
{ emptyCallback.onCallback() },
null,
trackMtaEvent = true,
mtaEvent = "预约游戏",
mtaKey = "删除预约弹窗")
trackMtaEvent = true
// , mtaEvent = "预约游戏",
// mtaKey = "删除预约弹窗"
)
}
@JvmStatic
@ -88,9 +89,10 @@ object ReservationHelper {
"暂不取消",
{ emptyCallback.onCallback() },
null,
trackMtaEvent = true,
mtaEvent = "预约游戏",
mtaKey = "取消预约弹窗")
trackMtaEvent = true
// , mtaEvent = "预约游戏",
// mtaKey = "取消预约弹窗"
)
}

View File

@ -31,6 +31,7 @@ import com.facebook.imagepipeline.image.CloseableImage;
import com.gh.common.constant.Config;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WeiBoShareActivity;
import com.gh.gamecenter.entity.ShareEntity;
import com.gh.gamecenter.eventbus.EBShare;
import com.lightgame.utils.Utils;
import com.sina.weibo.sdk.WbSdk;
@ -83,24 +84,39 @@ public class ShareUtils {
R.drawable.share_cancel_logo
};
public enum ShareType {
news,
game, // 普通游戏
plugin, // 插件游戏
tools,
askInvite,
askNormal, // 问答问题/答案
shareGh,
communityArticle,
video
public enum ShareEntrance {
news("资讯文章"),
game("游戏详情"), // 普通游戏
plugin("游戏详情"), // 插件游戏
tools("工具箱"),
askInvite("邀请回答"),
askNormal("问题详情"), //问答问题
answerNormal("回答详情"), //问答答案
shareGh("APP分享"),
communityArticle("文章详情"),
video("视频"),
web("web链接");
private String name;
ShareEntrance(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
private String[] arrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "新浪微博", "短信", "复制链接", "取消"};
private PopupWindow popupWindow;
private WeakReference<PopupWindow> popupWindow;
private ShareType mShareType;
public static ShareType shareType;//全局保存shareType分享成功后判断分享的类型
private ShareEntrance mShareEntrance;
public static String shareType = "";//分享类型(事件上报用)
public static ShareEntrance shareEntrance;//分享入口(事件上报和视频分享统计用)
public static String resourceId = "";//分享内容的id(事件上报用)
public static ShareEntity shareEntity;//分享信息(事件上报用)
private WeakReference<Activity> mActivity;
@ -110,25 +126,31 @@ public class ShareUtils {
@Override
public void onComplete(Object o) {
Utils.toast(mContext, R.string.share_success_hint);
EventBus.getDefault().post(new EBShare(ShareUtils.shareType));
EventBus.getDefault().post(new EBShare(ShareUtils.shareEntrance));
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "success",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
}
@Override
public void onError(UiError uiError) {
Utils.toast(mContext, R.string.share_fail_hint);
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "fail",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
}
@Override
public void onCancel() {
Utils.toast(mContext, R.string.share_cancel_hint);
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "cancel",
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
}
};
private ShareUtils(Context context) {
mTencent = Tencent.createInstance(Config.TENCENT_APPID, context); //初始化QQ分享
mIWXAPI = WXAPIFactory.createWXAPI(context, Config.WECHAT_APPID); //初始化微信分享
WbSdk.install(context, new AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
mContext = context.getApplicationContext();
mTencent = Tencent.createInstance(Config.TENCENT_APPID, mContext); //初始化QQ分享
mIWXAPI = WXAPIFactory.createWXAPI(mContext, Config.WECHAT_APPID); //初始化微信分享
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
}
public static ShareUtils getInstance(Context context) {
@ -153,17 +175,20 @@ public class ShareUtils {
return false;
}
public void showShareWindowsCallback(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareType shareType, ShareCallBack callBack) {
public void showShareWindowsCallback(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id, ShareCallBack callBack) {
if (activity.isFinishing()) return;
this.mActivity = new WeakReference<>(activity);
this.shareIcon = icon;
this.shareUrl = url;
this.mSummary = shareSummary;
this.mTitle = shareTitle;
this.mShareType = shareType;
ShareUtils.shareType = mShareType;
this.mShareEntrance = shareEntrance;
ShareUtils.shareEntrance = mShareEntrance;
ShareUtils.resourceId = id;
ShareUtils.shareEntity = new ShareEntity(shareUrl, mTitle, mSummary);
LogUtils.uploadShareEnter(mShareEntrance.getName(), shareUrl, mTitle, mSummary, id);
View contentView = View.inflate(activity, R.layout.share_popup_layout, null);
View contentView = View.inflate(mActivity.get(), R.layout.share_popup_layout, null);
contentView.setFocusable(true);
contentView.setFocusableInTouchMode(true);
RecyclerView shareRecyclerView = contentView.findViewById(R.id.share_rv);
@ -191,7 +216,7 @@ public class ShareUtils {
}
});
if (mShareType == ShareType.shareGh) {
if (mShareEntrance == ShareEntrance.shareGh) {
RelativeLayout layout = (RelativeLayout) view;
layout.addView(contentView);
arrLabel[6] = "邮件";
@ -206,41 +231,41 @@ public class ShareUtils {
arrLogo[7] = R.drawable.share_cancel_logo;
}
popupWindow = new SharePopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
, LinearLayout.LayoutParams.MATCH_PARENT, true);
popupWindow.setAnimationStyle(R.style.popwindow_exit_only_anim_style);
popupWindow = new WeakReference<>(new SharePopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
, LinearLayout.LayoutParams.MATCH_PARENT, true));
popupWindow.get().setAnimationStyle(R.style.popwindow_exit_only_anim_style);
//解决PopupWindow无法覆盖状态栏
popupWindow.setClippingEnabled(false);
popupWindow.get().setClippingEnabled(false);
int bottomLocation = -DisplayUtils.retrieveNavigationHeight(activity);
if (!DisplayUtils.isNavigationBarShow(activity)) {
bottomLocation = 0;
}
try {
popupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
popupWindow.get().showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
} catch (Exception e) {
e.printStackTrace();
}
contentView.setOnClickListener(v -> popupWindow.dismiss());
contentView.setOnClickListener(v -> popupWindow.get().dismiss());
contentView.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0
&& popupWindow != null
&& popupWindow.isShowing()) {
&& popupWindow.get().isShowing()) {
if (callBack != null) {
callBack.onCancel();
}
popupWindow.dismiss();
popupWindow.get().dismiss();
}
return false;
});
}
public void showShareWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareType shareType) {
showShareWindowsCallback(activity, view, url, icon, shareTitle, shareSummary, shareType, null);
public void showShareWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id) {
showShareWindowsCallback(activity, view, url, icon, shareTitle, shareSummary, shareEntrance, id, null);
}
//QQ分享
@ -248,11 +273,12 @@ public class ShareUtils {
Utils.toast(mContext, R.string.share_skip);
Bundle params = new Bundle();
switch (mShareType) {
switch (mShareEntrance) {
case plugin:
mSummary += "(光环加速版)";
break;
case askNormal:
case answerNormal:
case video:
case communityArticle:
mTitle += " - 光环助手";
@ -271,8 +297,8 @@ public class ShareUtils {
mTencent.shareToQQ(activity, params, QqShareListener);
}
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
}
}
@ -289,11 +315,12 @@ public class ShareUtils {
WXMediaMessage msg = new WXMediaMessage(webpage);
webpage.webpageUrl = shareUrl;
switch (mShareType) {
switch (mShareEntrance) {
case plugin:
mSummary += "(光环加速版)";
break;
case askNormal:
case answerNormal:
case video:
case communityArticle:
mTitle += " - 光环助手";
@ -310,8 +337,8 @@ public class ShareUtils {
req.scene = SendMessageToWX.Req.WXSceneSession;
loadBitMap(shareIcon, msg, req);
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
}
}
@ -323,14 +350,14 @@ public class ShareUtils {
ImageUtils.display(mContext, iconUrl, new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(Bitmap bitmap) {
if (mShareType == ShareType.video) {
if (mShareEntrance == ShareEntrance.video) {
// 分享类型为视频时裁为正方形
int dimension = Math.min(bitmap.getWidth(), bitmap.getHeight());
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
}
Bitmap compressBp = compressBitmap(bitmap);
if (mShareType == ShareType.askNormal || mShareType == ShareType.askInvite) {
if (mShareEntrance == ShareEntrance.askNormal || mShareEntrance == ShareEntrance.askInvite) {
msg.thumbData = ImageUtils.bmpToByteArray(compressBp, true);
} else {
Bitmap resultBp = addBackGround(compressBp);
@ -397,11 +424,12 @@ public class ShareUtils {
Utils.toast(mContext, R.string.share_skip);
Bundle params = new Bundle();
switch (mShareType) {
switch (mShareEntrance) {
case plugin:
mSummary += "(光环加速版)";
break;
case askNormal:
case answerNormal:
case video:
case communityArticle:
mTitle += " - 光环助手";
@ -425,8 +453,8 @@ public class ShareUtils {
mTencent.shareToQzone(activity, params, QqShareListener);
}
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
}
}
@ -444,7 +472,7 @@ public class ShareUtils {
webpage.webpageUrl = shareUrl;
switch (mShareType) {
switch (mShareEntrance) {
case plugin:
msg.title = mSummary + "(光环加速版)";
break;
@ -452,6 +480,7 @@ public class ShareUtils {
msg.title = mSummary;
break;
case askNormal:
case answerNormal:
case video:
case communityArticle:
msg.title = mTitle + " - 光环助手";
@ -469,8 +498,8 @@ public class ShareUtils {
req.scene = SendMessageToWX.Req.WXSceneTimeline;
loadBitMap(shareIcon, msg, req);
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
}
}
@ -485,22 +514,23 @@ public class ShareUtils {
shareIcon,
mTitle,
mSummary,
mShareType.toString());
mShareEntrance.toString());
activity.startActivity(intent);
}
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
}
}
//短信分享
private void shortMessageShare() {
String smsBody;
switch (mShareType) {
switch (mShareEntrance) {
case news:
case tools:
case web:
smsBody = mTitle + shareUrl;
break;
case plugin:
@ -514,6 +544,7 @@ public class ShareUtils {
break;
case askInvite:
case askNormal:
case answerNormal:
case video:
case communityArticle:
smsBody = mTitle + " - 光环助手" + shareUrl;
@ -531,18 +562,20 @@ public class ShareUtils {
e.printStackTrace();
}
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
}
}
//复制文字链接
private void copyLink(String copyContent) {
shareType = "copy_link";
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
ClipboardManager cmb = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(copyContent);
if (mShareType != ShareType.shareGh) {
if (mShareEntrance != ShareEntrance.shareGh) {
Utils.toast(mContext, "复制成功");
popupWindow.dismiss();
popupWindow.get().dismiss();
} else {
Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享");
}
@ -567,7 +600,7 @@ public class ShareUtils {
holder.shareLogo.setImageResource(arrLogo[position]);
holder.shareLabel.setText(arrLabel[position]);
holder.itemView.setOnClickListener(v -> {
if (mShareType == ShareUtils.ShareType.shareGh) {
if (mShareEntrance == ShareEntrance.shareGh) {
MtaHelper.onEvent("我的光环_新", "分享光环", arrLabel[position]);
}
if (listener != null) {
@ -575,23 +608,33 @@ public class ShareUtils {
}
switch (holder.getPosition()) {
case 0:
shareType = "wechat_friend";
MtaHelper.onEvent("内容分享", "微信好友", mTitle);
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
wechatShare();
break;
case 1:
shareType = "wechat_moment";
MtaHelper.onEvent("内容分享", "微信朋友圈", mTitle);
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
wechatMomentsShare();
break;
case 2:
shareType = "qq_friend";
MtaHelper.onEvent("内容分享", "QQ好友", mTitle);
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
qqShare();
break;
case 3:
shareType = "qq_zone";
MtaHelper.onEvent("内容分享", "QQ空间", mTitle);
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
qZoneShare();
break;
case 4:
shareType = "sina_weibo";
MtaHelper.onEvent("内容分享", "新浪微博", mTitle);
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
sinaWeiboShare();
break;
case 5:
@ -600,11 +643,11 @@ public class ShareUtils {
break;
case 6:
MtaHelper.onEvent("内容分享", "复制链接", mTitle);
if (mShareType == ShareType.askInvite) {
if (mShareEntrance == ShareEntrance.askInvite) {
copyLink(mTitle + " - 光环助手" + shareUrl);
} else if (mShareType == ShareType.askNormal) {
} else if (mShareEntrance == ShareEntrance.askNormal || mShareEntrance == ShareEntrance.answerNormal) {
copyLink(shareUrl);
} else if (mShareType != ShareType.shareGh) {
} else if (mShareEntrance != ShareEntrance.shareGh) {
copyLink(shareUrl);
} else {
try {
@ -617,10 +660,11 @@ public class ShareUtils {
}
break;
case 7:
if (mShareType != ShareType.shareGh) {
popupWindow.dismiss();
if (mShareEntrance != ShareEntrance.shareGh) {
popupWindow.get().dismiss();
} else {
copyLink("推荐光环助手,绿色安全的手游加速助手:" + shareUrl);
shareType = "copy_link";
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
}
break;
}
@ -655,12 +699,12 @@ 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);
@ -670,5 +714,5 @@ public class ShareUtils {
getContentView().postDelayed(super::dismiss, 0);
}
}
}

View File

@ -2,6 +2,7 @@ package com.gh.common.util
import android.content.Context
import android.content.SharedPreferences
import com.google.gson.reflect.TypeToken
import com.halo.assistant.HaloApp
object SPUtils {
@ -90,7 +91,20 @@ object SPUtils {
@JvmStatic
fun getStringSet(key: String): Set<String> {
return sp.getStringSet(key, HashSet())?: HashSet()
return sp.getStringSet(key, HashSet()) ?: HashSet()
}
@JvmStatic
fun setMap(key: String, map: Map<String, String>) {
val mapJson = GsonUtils.toJson(map)
setString(key, mapJson)
}
@JvmStatic
fun getMap(key: String): MutableMap<String, String> {
val mapJson = getString(key)
val type = object : TypeToken<MutableMap<String, String>>() {}.type
return GsonUtils.gson.fromJson(mapJson, type) ?: mutableMapOf()
}
@JvmStatic

View File

@ -12,6 +12,7 @@ import android.text.style.StyleSpan
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.gh.common.view.CenterImageSpan
import com.halo.assistant.HaloApp
class SpanBuilder(content: String) {
private var spannableString: SpannableStringBuilder = SpannableStringBuilder(content)
@ -58,8 +59,8 @@ class SpanBuilder(content: String) {
}
//添加图标
fun image(context: Context, start: Int, end: Int, @DrawableRes res: Int): SpanBuilder {
val imageSpan = CenterImageSpan(context, res)
fun image(start: Int, end: Int, @DrawableRes res: Int): SpanBuilder {
val imageSpan = CenterImageSpan(HaloApp.getInstance().application, res)
spannableString.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
return this
}

View File

@ -35,4 +35,19 @@ public class SpeedUtils {
}
}
public static String getRemainSecondTime(long totalSize, long currentSize, long speed) {
long remainSize = totalSize - currentSize;
long remainTime;
if (speed != 0) {
remainTime = remainSize / speed;
} else {
return "-s";
}
int hour = (int) (remainTime / 3600);
remainTime = (remainTime - hour * 3660);
int minute = (int) (remainTime / 60);
int second = (int) (remainTime - minute * 60);
return second + "s";
}
}

View File

@ -66,7 +66,7 @@ public class TagUtils {
return;
}
isUpdate = true;
RetrofitManager.getInstance(context).getApi().getTags()
RetrofitManager.getInstance(context).getSensitiveApi().getTags()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<TagEntity>>() {

View File

@ -133,23 +133,38 @@ object TextHelper {
Utils.toast(application, "已复制:$arg")
}
}): SpannableStringBuilder {
val builder = SpannableStringBuilder(text)
return updateSpannableStringWithHighlightedSpan(context, builder, wrapper, highlightColorId, highlightedTextClickListener)
}
var modifiedText = text
if (modifiedText.endsWith(wrapper)) {
fun updateSpannableStringWithHighlightedSpan(
context: Context,
ssb: SpannableStringBuilder,
wrapper: String = "###",
@ColorRes
highlightColorId: Int = R.color.theme_font,
highlightedTextClickListener: SimpleCallback<String>? = object : SimpleCallback<String> {
override fun onCallback(arg: String) {
val application = HaloApp.getInstance().application
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cmb.text = arg
Utils.toast(application, "已复制:$arg")
}
}): SpannableStringBuilder {
if (ssb.endsWith(wrapper)) {
// 若高亮符在最后一位就在后面加一个空格,避免整行都能点击
modifiedText = "$modifiedText "
ssb.append(" ")
}
val sBuilder = SpannableStringBuilder(modifiedText)
val wrapperTextLength = wrapper.length
val matcher = Pattern.compile("$wrapper(.+?)$wrapper", Pattern.DOTALL).matcher(modifiedText)
val matcher = Pattern.compile("$wrapper(.+?)$wrapper", Pattern.DOTALL).matcher(ssb)
val pair = TreeMap<Int, Int>()
while (matcher.find()) {
// 保存起始位置和结束位置
pair[matcher.start(1)] = matcher.end(1)
sBuilder.setSpan(object : ClickableSpan() {
ssb.setSpan(object : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.color = ContextCompat.getColor(context, highlightColorId)
@ -174,12 +189,12 @@ object TextHelper {
val end = reversePair[key]
end?.let {
sBuilder.replace(end, end + wrapperTextLength, "")
sBuilder.replace(key - wrapperTextLength, key, "")
ssb.replace(end, end + wrapperTextLength, "")
ssb.replace(key - wrapperTextLength, key, "")
}
}
return sBuilder
return ssb
}
/**

View File

@ -60,7 +60,7 @@ object TimeUtils {
/**
* 判断时间戳是多少天前
*/
fun getBeforeDays(timestamp: Long):Int{
fun getBeforeDays(timestamp: Long): Int {
var days: Long = 0
val format = SimpleDateFormat("yyyyMMdd HH:mm", Locale.getDefault())
try {
@ -73,4 +73,15 @@ object TimeUtils {
return days.toInt()
}
/**
* 格式化视频时长
*/
@JvmStatic
fun formatVideoDuration(length: Long): String {
val minute = length / 60
val second = length % 60
return String.format(Locale.CHINA, "%02d:%02d", minute, second)
}
}

View File

@ -7,10 +7,13 @@ import com.halo.assistant.HaloApp
object ToastUtils {
/** 之前显示的内容 */
private var mOldMsg: String? = null
/** Toast对象 */
private var mToast: Toast? = null
/** 第一次时间 */
private var mOneTime: Long = 0
/** 第二次时间 */
private var mTwoTime: Long = 0
@ -19,19 +22,34 @@ object ToastUtils {
* @param message
*/
fun showToast(message: String) {
showToast(message, -1)
}
/**
* 显示Toast
* @param message
* @param gravity
*/
fun showToast(message: String, gravity: Int = -1, yOffset: Int = 0) {
if (mToast == null) {
mToast = Toast.makeText(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
mToast!!.show()
mOneTime = System.currentTimeMillis()
} else {
mTwoTime = System.currentTimeMillis()
if (message == mOldMsg) {
if (mTwoTime - mOneTime > Toast.LENGTH_SHORT) {
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
mToast!!.show()
}
} else {
mOldMsg = message
mToast!!.setText(message)
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
mToast!!.show()
}
}

View File

@ -0,0 +1,127 @@
package com.gh.common.util;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
public class UriUtils {
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}

View File

@ -0,0 +1,18 @@
package com.gh.common.videolog
import androidx.room.*
@Dao
interface VideoRecordDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertMany(eventList: List<VideoRecordEntity>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(event: VideoRecordEntity)
@Query("SELECT * FROM VideoRecord")
fun getAll(): List<VideoRecordEntity>
@Delete
fun deleteMany(eventList: List<VideoRecordEntity>)
}

View File

@ -0,0 +1,18 @@
package com.gh.common.videolog
import android.os.Parcelable
import androidx.annotation.Keep
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize
import java.util.*
@Keep
@Parcelize
@Entity(tableName = "VideoRecord")
data class VideoRecordEntity(
@PrimaryKey
val id: String = UUID.randomUUID().toString(),
var videoId: String = "",
var time: Long = 0
) : Parcelable

View File

@ -0,0 +1,76 @@
package com.gh.common.videolog
import android.annotation.SuppressLint
import android.app.Application
import com.gh.common.util.toRequestBody
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import java.util.concurrent.Executors
object VideoRecordUtils {
private const val STORE_SIZE = 20
private lateinit var mApplication: Application
private val videoRecordSet by lazy { hashSetOf<VideoRecordEntity>() }
private val videoRecordExecutor by lazy { Executors.newSingleThreadExecutor() }
private val videoRecordDao by lazy { AppDatabase.getInstance(mApplication).videoRecordDao() }
@JvmStatic
fun init(application: Application) {
mApplication = application
videoRecordExecutor.execute {
val recordList = videoRecordDao.getAll()
videoRecordSet.addAll(recordList)
}
}
fun log(videoId: String) {
videoRecordExecutor.execute {
try {
val entity = VideoRecordEntity(videoId = videoId, time = System.currentTimeMillis() / 1000L)
videoRecordSet.add(entity)
videoRecordDao.insert(entity)
} catch (e: Exception) {
e.printStackTrace()
}
if (videoRecordSet.size >= STORE_SIZE) {
commitVideoRecord()
}
}
}
fun commitVideoRecord() {
if (videoRecordSet.isEmpty()) return
videoRecordExecutor.execute {
uploadVideoRecord()
val exposureList = videoRecordSet.toList()
videoRecordSet.removeAll(exposureList)
videoRecordDao.deleteMany(exposureList)
}
}
@SuppressLint("CheckResult")
fun uploadVideoRecord(time: Long = 0) {
if (!UserManager.getInstance().isLoggedIn) return
val requestMap = HashMap<String, Any>()
val videoIds = videoRecordSet.toList().map { it.videoId }
requestMap["g_id"] = HaloApp.getInstance().gid
requestMap["time"] = time
requestMap["video_id"] = videoIds
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.uploadVideoLog(requestMap.toRequestBody())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
}
})
}
}

View File

@ -8,7 +8,9 @@ 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.util.DisplayUtils
import com.gh.common.util.ImageUtils
import com.gh.common.util.rxTimer
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SettingsEntity

View File

@ -21,8 +21,10 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
: ConstraintLayout(context, attrs, defStyleAttr) {
private var mSizeTv: TextView
private var mNewestTv: TextView
private var mRecommendedTv: TextView
var newestTv: TextView
var ratingTv: TextView //目前只在专题页面显示
var recommendedTv: TextView
private var mOnConfigFilterSetupListener: OnConfigFilterSetupListener? = null
@ -30,23 +32,33 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
View.inflate(context, R.layout.layout_config_filter, this)
mSizeTv = findViewById(R.id.size_tv)
mNewestTv = findViewById(R.id.newest_tv)
mRecommendedTv = findViewById(R.id.recommended_tv)
newestTv = findViewById(R.id.newest_tv)
ratingTv = findViewById(R.id.rating_tv)
recommendedTv = findViewById(R.id.recommended_tv)
mSizeTv.setOnClickListener {
showSelectionPopupWindow(this, mSizeTv, mSizeTv.text.toString())
}
mNewestTv.setOnClickListener {
mOnConfigFilterSetupListener?.onSetupSortType(SortType.NEWEST)
toggleHighlightedTextView(mNewestTv, true)
toggleHighlightedTextView(mRecommendedTv, false)
ratingTv.setOnClickListener {
mOnConfigFilterSetupListener?.onSetupSortType(SortType.RATING)
toggleHighlightedTextView(ratingTv, true)
toggleHighlightedTextView(newestTv, false)
toggleHighlightedTextView(recommendedTv, false)
}
mRecommendedTv.setOnClickListener {
newestTv.setOnClickListener {
mOnConfigFilterSetupListener?.onSetupSortType(SortType.NEWEST)
toggleHighlightedTextView(ratingTv, false)
toggleHighlightedTextView(newestTv, true)
toggleHighlightedTextView(recommendedTv, false)
}
recommendedTv.setOnClickListener {
mOnConfigFilterSetupListener?.onSetupSortType(SortType.RECOMMENDED)
toggleHighlightedTextView(mNewestTv, false)
toggleHighlightedTextView(mRecommendedTv, true)
toggleHighlightedTextView(ratingTv, false)
toggleHighlightedTextView(newestTv, false)
toggleHighlightedTextView(recommendedTv, true)
}
}
@ -54,7 +66,7 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
mOnConfigFilterSetupListener = onConfigFilterSetupListener
}
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
if (highlightIt) {
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.text_blue_background)
targetTextView.setTextColor(Color.WHITE)
@ -140,7 +152,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
enum class SortType {
RECOMMENDED,
NEWEST
NEWEST,
RATING
}
enum class SortSize(val value: String) {

View File

@ -31,7 +31,7 @@ class EllipsizeTextView : AppCompatTextView {
val width = paint.measureText(text.subSequence(secondLastLineEnd, lastLineEnd).toString() + "...")
if (width > layout.width) {
val lastLineText = text.subSequence(secondLastLineEnd, lastLineEnd)
for (i in 0 until lastLineText.length) {
for (i in lastLineText.indices) {
val cutWidth = paint.measureText(text.subSequence(secondLastLineEnd, lastLineEnd - i).toString() + "...")
if (cutWidth <= layout.width) {
charSequence = text.subSequence(0, lastLineEnd - i)
@ -41,7 +41,7 @@ class EllipsizeTextView : AppCompatTextView {
}
} else {
charSequence = text.subSequence(0, lastLineEnd)
text = charSequence
text = SpannableStringBuilder().append(charSequence).append("...")
}
}
}

View File

@ -8,100 +8,132 @@ import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.view.View;
import com.gh.gamecenter.R;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import com.gh.gamecenter.R;
public class ExpandTextView extends AppCompatTextView {
private CharSequence mSnapshotText;
private String mEndText = "...";
private CharSequence mShrankText = "";
private String mExpandText = mEndText + "全文";
private CharSequence mExpandedText = "";
private boolean mUseGradientAlphaEndText = false;
private boolean mShowExpandTextRegardlessOfMaxLines = false; // 不论文字超过 maxLines 都显示"...展开"文字
private int mMaxLines = 3; // 由于sdk版本限制(getMaxLines) 这里设置默认值
private static int DEFAULT_ADDITIONAL_END_TEXT_COUNT = 2;
private boolean mInitLayout = false;
private boolean mIsExpanded = false; // 位于 recyclerView 时需要自行在外层管理是否已展开
private ExpandCallback mExpandCallback;
private SelfCalculateMaxLinesCallback mMaxLinesCalculatedCallback;
private Rect mLastVisibleLineRect;
private Rect mLastActualLineRect;
private static int DEFAULT_ADDITIONAL_END_TEXT_COUNT = 2;
public ExpandTextView(Context context) {
super(context);
}
public ExpandTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mMaxLines = getMaxLines();
}
mLastVisibleLineRect = new Rect();
mLastActualLineRect = new Rect();
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandTextView);
mUseGradientAlphaEndText = ta.getBoolean(R.styleable.ExpandTextView_useGradientAlphaEndText, false);
mEndText = ta.getString(R.styleable.ExpandTextView_endText) == null ? mEndText : ta.getString(R.styleable.ExpandTextView_endText);
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta
.getString(R.styleable.ExpandTextView_expandText);
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta.getString(R.styleable.ExpandTextView_expandText);
ta.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mShowExpandTextRegardlessOfMaxLines && !mIsExpanded) {
updateMaxLines();
}
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() - getExtraBottomPadding());
}
private void updateMaxLines() {
mMaxLines = getLineCount() - 1;
setMaxLines(mMaxLines);
mMaxLinesCalculatedCallback.onMaxLinesCalculated(mMaxLines);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mInitLayout && !mIsExpanded && getLineCount() > mMaxLines) {
if (mMaxLines > 0
&& ((mShowExpandTextRegardlessOfMaxLines && !mIsExpanded) || (mInitLayout && !mIsExpanded && getLineCount() > mMaxLines))) {
mSnapshotText = getText();
mInitLayout = false;
showExpandButton();
}
}
public void setExpendText(String text) {
public void setExpandText(String text) {
this.mExpandText = text;
}
public void setExpandCallback(ExpandCallback callback) {
this.mExpandCallback = callback;
}
/**
* 适用于不使用 maxLines 而是整段收起时的文字来确定“...更多”的位置的样式
* @param shrankText 收起时的文字 (“...更多”跟在 shrankText 后)
* @param expandedText 展开时的文字
*/
public void setShrankTextAndExpandedText(CharSequence shrankText, CharSequence expandedText) {
mShrankText = shrankText;
mExpandedText = expandedText;
mShowExpandTextRegardlessOfMaxLines = !TextUtils.isEmpty(shrankText);
if (!mIsExpanded && mShowExpandTextRegardlessOfMaxLines) {
setText(mShrankText);
} else {
setText(mExpandedText);
}
}
@Override
public void setText(CharSequence text, BufferType type) {
mInitLayout = true;
super.setText(text, type);
}
private void showExpandButton() {
String finalEndText = "";
TextPaint paint = getPaint();
Layout layout = getLayout();
int start = layout.getLineStart(0);
int lastLineEnd = layout.getLineEnd(mMaxLines - 1);
int lastLineStart = layout.getLineStart(mMaxLines - 1);
float lastLineRight = layout.getLineRight(mMaxLines - 1);
int viewWidth = getWidth() - getPaddingRight() - getPaddingLeft();
int additionalEndTextCount = 0;
float expandTextWidth;
if (mUseGradientAlphaEndText) {
additionalEndTextCount = DEFAULT_ADDITIONAL_END_TEXT_COUNT;
@ -109,15 +141,15 @@ public class ExpandTextView extends AppCompatTextView {
} else {
expandTextWidth = paint.measureText(mExpandText);
}
CharSequence content = mSnapshotText.subSequence(start, lastLineEnd);
if (viewWidth - lastLineRight > expandTextWidth) {
if (mUseGradientAlphaEndText) {
finalEndText = content.toString()
.substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
.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;
@ -130,10 +162,10 @@ public class ExpandTextView extends AppCompatTextView {
if (mUseGradientAlphaEndText) {
subSequence = lastLineText.subSequence(0, i - additionalEndTextCount);
subSequenceWidth = paint.measureText(subSequence.toString());
finalEndText = lastLineText.subSequence(i - additionalEndTextCount, i) + mEndText;
expandTextWidth = paint.measureText(finalEndText + mExpandText);
if (viewWidth - subSequenceWidth > expandTextWidth) {
finalEndText = finalEndText.replace("\n", "");
content = mSnapshotText.subSequence(start, lastLineStart + i - additionalEndTextCount) + finalEndText + mExpandText;
@ -142,7 +174,7 @@ public class ExpandTextView extends AppCompatTextView {
} else {
subSequence = lastLineText.subSequence(0, i);
subSequenceWidth = paint.measureText(subSequence.toString());
if (viewWidth - subSequenceWidth > expandTextWidth) {
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
break;
@ -150,18 +182,18 @@ public class ExpandTextView extends AppCompatTextView {
}
}
}
SpannableStringBuilder msp = new SpannableStringBuilder(mSnapshotText);
int length = msp.length();
int startPosition;
startPosition = content.length() - finalEndText.length() - mExpandText.length();
startPosition = Math.max(startPosition, 0);
int expandTextStartPosition;
expandTextStartPosition = content.length() - finalEndText.length() - mExpandText.length();
expandTextStartPosition = Math.max(expandTextStartPosition, 0);
// 避免越界
if (startPosition >= length) return;
msp.replace(startPosition, length, finalEndText + mExpandText);
if (expandTextStartPosition >= length) return;
msp.replace(expandTextStartPosition, length, finalEndText + mExpandText);
msp.setSpan(new ClickableSpan() {
@Override
public void updateDrawState(@NonNull TextPaint ds) {
@ -169,24 +201,49 @@ public class ExpandTextView extends AppCompatTextView {
ds.setColor(ContextCompat.getColor(getContext(), R.color.theme_font));
ds.setUnderlineText(false);
}
@Override
public void onClick(@NonNull View widget) {
mIsExpanded = true;
setMaxLines(Integer.MAX_VALUE);
setText(mSnapshotText);
if (mShowExpandTextRegardlessOfMaxLines) {
setText(mExpandedText);
} else {
setText(mSnapshotText);
}
if (mExpandCallback != null) {
mExpandCallback.onExpand();
}
}
}, startPosition + mEndText.length(), msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
msp.setSpan(new GradientAlphaTextSpan(), startPosition, startPosition + finalEndText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}, expandTextStartPosition + mEndText.length(), msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
int paintColor = 0;
// 找到第一个位置与 endTextStartPosition 贴合的 ForegroundSpan / ClickableSpan ,
// 获取颜色赋值给 GradientAlphaTextSpan
Object[] objects = msp.getSpans(0, expandTextStartPosition, Object.class);
if (objects.length != 0) {
for (Object span : objects) {
int startPosition = msp.getSpanStart(span);
int endPosition = msp.getSpanEnd(span);
if (expandTextStartPosition >= startPosition && expandTextStartPosition <= endPosition) {
if (span instanceof ForegroundColorSpan) {
paintColor = ((ForegroundColorSpan) span).getForegroundColor();
break;
} else if (span instanceof ClickableSpan) {
paintColor = getResources().getColor(R.color.theme_font);
break;
}
}
}
}
msp.setSpan(new GradientAlphaTextSpan(paintColor), expandTextStartPosition, expandTextStartPosition + finalEndText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(msp);
setMovementMethod(CustomLinkMovementMethod.getInstance());
}
/**
* 获取 maxLines + lineSpacingExtra + movementMethod 一起使用时产生的大小与 lineSpacingExtra 一样的底部空间
*/
@ -196,16 +253,16 @@ public class ExpandTextView extends AppCompatTextView {
int lastVisibleLineIndex = Math.min(getMaxLines(), getLineCount()) - 1;
// 获取实际文字的最后一行的 index
int lastActualLineIndex = getLineCount() - 1;
if (lastVisibleLineIndex >= 0) {
Layout layout = getLayout();
int lastVisibleLineBaseline = getLineBounds(lastVisibleLineIndex, mLastVisibleLineRect);
getLineBounds(lastActualLineIndex, mLastActualLineRect);
int heightBetweenLastVisibleLineRectAndLastActualLineRect = (mLastActualLineRect.bottom - mLastVisibleLineRect.bottom);
if (getMeasuredHeight() == getLayout().getHeight() - heightBetweenLastVisibleLineRectAndLastActualLineRect) {
result = mLastVisibleLineRect.bottom - (lastVisibleLineBaseline + layout.getPaint()
.getFontMetricsInt().descent + getPaddingBottom());
.getFontMetricsInt().descent + getPaddingBottom());
if (getLineSpacingExtra() > result) {
result = 0;
} else {
@ -215,21 +272,29 @@ public class ExpandTextView extends AppCompatTextView {
}
return result;
}
/**
* 此方法仅更改标记,不做实际展开的操作
*/
public void setIsExpanded(boolean isExpanded) {
mIsExpanded = isExpanded;
}
public void setExpandMaxLines(int maxLines) {
mMaxLines = maxLines;
setMaxLines(maxLines);
}
public void setSelfCalculateMaxLinesCallback(SelfCalculateMaxLinesCallback callback) {
mMaxLinesCalculatedCallback = callback;
}
public interface ExpandCallback {
void onExpand();
}
public interface SelfCalculateMaxLinesCallback {
void onMaxLinesCalculated(int maxLines);
}
}

View File

@ -0,0 +1,32 @@
package com.gh.common.view
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
import com.gh.common.util.tryCatchInRelease
/**
* 游戏列表标签的容器(特定功能的View)
*
* 一行内,防止标签显示越界
*/
class GameTagContainerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
tryCatchInRelease {
var childContentWidth = 0
for (i in 0 until childCount) {
val tag = getChildAt(i)
val tagLp = tag.layoutParams
if (tagLp is LayoutParams) {
tag.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
val tagWidth = tagLp.leftMargin + tagLp.rightMargin + tag.measuredWidth
childContentWidth += tagWidth
}
}
if (childContentWidth > width && childCount > 1) {
removeViewAt(childCount - 1)
}
}
}
}

View File

@ -1,20 +1,17 @@
package com.gh.common.view
import android.graphics.Canvas
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Shader
import android.graphics.*
import android.text.style.ReplacementSpan
import androidx.core.graphics.ColorUtils
class GradientAlphaTextSpan() : ReplacementSpan() {
class GradientAlphaTextSpan(var textColor: Int) : 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 originalColor = if (textColor == 0) paint.color else textColor
val originalColorWithAlphaChanged = ColorUtils.setAlphaComponent(paint.color, 1)
val textWidth = paint.measureText(text, start, end).toInt()

View File

@ -1,4 +1,5 @@
package com.gh.common.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
@ -7,7 +8,8 @@ import androidx.core.view.MotionEventCompat;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.ViewCompat;
import wendu.dsbridge.DWebView;
import com.gh.common.view.dsbridge.DWebView;
public class NestedScrollWebView extends DWebView implements NestedScrollingChild {

View File

@ -25,7 +25,8 @@ import androidx.core.view.NestedScrollingParentHelper;
import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import wendu.dsbridge.DWebView;
import com.gh.common.view.dsbridge.DWebView;
/**
* Copyright (c) Tuenti Technologies. All rights reserved.

View File

@ -65,7 +65,9 @@ class WelcomeDialog : BaseDialogFragment() {
EntranceUtils.HOST_COMMUNITY -> {
DirectUtils.directToCommunity(requireContext(), CommunityEntity(mWelcomeEntity?.link!!, mWelcomeEntity?.text!!))
}
else -> DialogUtils.showLowVersionDialog(context)
// else -> DialogUtils.showLowVersionDialog(context)
else -> DirectUtils.directToLinkPage(requireContext(), mWelcomeEntity
?: WelcomeDialogEntity(), EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
}
mDismissByClickImage = true

View File

@ -7,11 +7,11 @@ import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import java.lang.reflect.Field;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import java.lang.reflect.Field;
/**
* Auto Scroll View Pager
* <ul>

View File

@ -0,0 +1,11 @@
package com.gh.common.view.dsbridge;
/**
* Created by du on 16/12/31.
*/
public interface CompletionHandler<T> {
void complete(T retValue);
void complete();
void setProgressData(T value);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
package com.gh.common.view.dsbridge;
/**
* Created by du on 16/12/31.
*/
public interface OnReturnValue<T> {
void onValue(T retValue);
}

View File

@ -206,7 +206,8 @@ public class ScrollPageHelper extends PagerSnapHelper {
} else if (snapLastItem && endOfList) {
return child;
} else if (endOfList) {
return null;
// return null;
return child;
} else {
return reverseLayout ? layoutManager.findViewByPosition(firstChild - offset)
: layoutManager.findViewByPosition(firstChild + offset);
@ -262,7 +263,8 @@ public class ScrollPageHelper extends PagerSnapHelper {
} else if (snapLastItem && startOfList) {
return child;
} else if (startOfList) {
return null;
// return null;
return child;
} else {
return reverseLayout ? layoutManager.findViewByPosition(lastChild + offset)
: layoutManager.findViewByPosition(lastChild - offset);

View File

@ -8,6 +8,12 @@ import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.gh.common.AppExecutor;
import com.gh.common.exposure.ExposureEvent;
import com.gh.common.exposure.ExposureUtils;
@ -17,14 +23,15 @@ import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DeviceUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.GdtHelper;
import com.gh.common.util.HomePluggableHelper;
import com.gh.common.util.MD5Utils;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.SPUtils;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.entity.HomePluggableFilterEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.manager.PackagesManager;
@ -54,11 +61,6 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.ProcessLifecycleOwner;
public class DownloadManager implements DownloadStatusListener {
private static DownloadManager mInstance;
@ -107,7 +109,7 @@ public class DownloadManager implements DownloadStatusListener {
public void onTaskError(DownloadEntity entity) {
// 下载进度超出是任务出错,但不需要去掉状态栏通知 https://gitlab.ghzs.com/pm/halo-app-issues/issues/496
if (entity.getStatus() == DownloadStatus.overflow) {
MtaHelper.onEventWithBasicDeviceInfo("下载无法完成", "游戏", entity.getName());
// MtaHelper.onEventWithBasicDeviceInfo("下载无法完成", "游戏", entity.getName());
} else {
downloadingMap.remove(entity.getUrl());
}
@ -138,7 +140,6 @@ public class DownloadManager implements DownloadStatusListener {
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
//TODO unregister this
DownloadStatusManager.getInstance().registerTaskStatusListener(this);
// 只有下载模块需要这坨东西,因此移动到这里初始化
@ -152,7 +153,6 @@ public class DownloadManager implements DownloadStatusListener {
statusMap = new ArrayMap<>();
downloadingMap = new ArrayMap<>();
// TODO 这里的 handler 类的 case 可能会被多次调用,原因未知
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
@ -271,7 +271,7 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getPlatform(), traceEvent, downloadType);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
// 将下载事件放入 downloadEntity 中供下载完成时取出使用
downloadEntity.setExposureTrace(gson.toJson(downloadExposureEvent));
@ -432,6 +432,7 @@ public class DownloadManager implements DownloadStatusListener {
* @param url 下载链接
* @return null表示下载列表中不存在该任务否则返回下载任务
*/
@Nullable
public DownloadEntity getDownloadEntityByUrl(String url) {
if (TextUtils.isEmpty(url)) return null;
return mDownloadDao.get(url);
@ -494,11 +495,13 @@ public class DownloadManager implements DownloadStatusListener {
*
* @return null表示没有下载任务
*/
@NonNull
public List<DownloadEntity> getAll() {
if (CommonDebug.IS_DEBUG) {
CommonDebug.logMethodName(this);
}
return mDownloadDao.getAll();
List<DownloadEntity> all = mDownloadDao.getAll();
return all != null ? all : new ArrayList<>();
}
public ArrayMap<String, DownloadEntity> getEntryMap(String name) {
@ -649,6 +652,7 @@ public class DownloadManager implements DownloadStatusListener {
// 所以还是老老实实地以 startService 为主吧
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
mContext.startForegroundService(serviceIntent);
} else {
mContext.startService(serviceIntent);
@ -671,20 +675,13 @@ public class DownloadManager implements DownloadStatusListener {
// 当满足系统版本大于 8.0 、应用在后台运行时以前台服务开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
mContext.startForegroundService(serviceIntent);
} else {
mContext.startService(serviceIntent);
}
}
public void disableDownloadSpeedLimit() {
// DownloadSpeedController.disableSpeedLimit();
}
public void updateSpeedLimitationReleaseDelay(int delay) {
// DownloadSpeedController.updateLimitationReleaseDelay(delay);
}
public void checkRetryDownload() {
if (!NetworkUtils.isWifiConnected(mContext)) return;
@ -732,10 +729,24 @@ public class DownloadManager implements DownloadStatusListener {
if (showRedPoint) return "";
if (updateList != null) {
// 首页永久忽略的插件化列表
List<HomePluggableFilterEntity> permanentInactiveUpdateList = HomePluggableHelper.getPermanentInactivePluggablePackage();
for (GameUpdateEntity updateEntity : updateList) {
if (updateEntity.isShowPlugin(PluginLocation.only_index)
&& !mUpdateMarks.contains(updateEntity.getId() + updateEntity.getPackageName())) {
return "";
if (updateEntity.isShowPlugin(PluginLocation.only_index) && !mUpdateMarks.contains(updateEntity.getId() + updateEntity.getPackageName())) {
// 判断该更新的的包名是否被永久忽略
if (permanentInactiveUpdateList != null) {
boolean isPluggablePermanentInactive = false;
for (HomePluggableFilterEntity filterEntity : permanentInactiveUpdateList) {
if (filterEntity.getPkgName().equals(updateEntity.getPackageName())) {
isPluggablePermanentInactive = true;
}
}
if (!isPluggablePermanentInactive) {
return "";
}
} else {
return "";
}
}
}
}

View File

@ -164,7 +164,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
downloadNotice,
mEntrance, "下载多平台弹窗")
}
MtaHelper.onEvent(MTA_KEY, "点击", mViewModel.gameEntity.name + "_" + downloadNotice.title)
// MtaHelper.onEvent(MTA_KEY, "点击", mViewModel.gameEntity.name + "_" + downloadNotice.title)
}
}
@ -280,13 +280,13 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
}
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)
}
// 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() {

View File

@ -6,6 +6,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.base.OnViewClickListener
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.DirectUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.throwExceptionInDebug
import com.gh.gamecenter.NewsDetailActivity
@ -92,11 +93,12 @@ class DownloadDialogAdapter(context: Context,
mContext.startActivity(QaActivity.getIntent(mContext, data.linkText, qaCollectionId = data.linkId))
}
else -> {
Utils.toast(mContext, "暂不支持类型:" + data.linkType)
//Utils.toast(mContext, "暂不支持类型:" + data.linkType)
DirectUtils.directToLinkPage(mContext, data.getLinkEntity(), mEntrance, mPath)
}
}
MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", viewModel.gameEntity.name + "_" + data.title)
// MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", viewModel.gameEntity.name + "_" + data.title)
}
}
is DownloadDialogInstructionItemViewHolder -> {

View File

@ -7,6 +7,7 @@ import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.PackageUtils
import com.gh.common.util.goneIf
import com.gh.common.util.throwExceptionInDebug
import com.gh.common.util.toColor
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DownloadDialogInstalledItemBinding
@ -30,6 +31,7 @@ class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalled
throwExceptionInDebug("apkLink 不应该出现在这里")
} else if (apkCollection != null || apkEntity.downloadInstruction.isNotEmpty()) {
binding.collection.visibility = View.VISIBLE
binding.collectionPluggableHint.visibility = View.GONE
binding.downloadStatusIcon.visibility = View.GONE
binding.progressbar.visibility = View.GONE
binding.pluggable.visibility = View.GONE
@ -45,7 +47,14 @@ class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalled
}
binding.collection.text = if (apkCollection != null) {
"查看合集"
if (apkCollection.showPluggableHint) {
binding.collectionPluggableHint.visibility = View.VISIBLE
binding.collection.setTextColor(R.color.text_05CBA3.toColor())
gameEntity.pluginDesc + "此版本"
} else {
binding.collection.setTextColor(R.color.text_cccccc.toColor())
"查看合集"
}
} else "查看详情"
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.COLLECTION)
} else {

View File

@ -190,11 +190,11 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
}
val downloadEntity = DownloadManager.getInstance(it.context).getDownloadEntityByUrl(apkEntity.url)
if (downloadEntity.status == DownloadStatus.pause) {
if (downloadEntity?.status == DownloadStatus.pause) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_暂停中"
} else if (downloadEntity.status == DownloadStatus.waiting) {
} else if (downloadEntity?.status == DownloadStatus.waiting) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_等待中"
} else if (downloadEntity.status == DownloadStatus.subscribe) {
} else if (downloadEntity?.status == DownloadStatus.subscribe) {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_排队中"
} else {
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_下载中"
@ -203,6 +203,8 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
}
DownloadDialogItemStatus.INSTALL -> {
val downloadEntity = DownloadManager.getInstance(it.context).getDownloadEntityByUrl(apkEntity.url)
?: return@setOnClickListener
if (FileUtils.isEmptyFile(downloadEntity.path)) {
Utils.toast(it.context, R.string.install_failure_hint)
DownloadManager.getInstance(it.context).cancel(apkEntity.url)
@ -260,7 +262,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
}
}
throwExceptionInDebug("无法识别当前状态", mtaValue == "未知")
MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", mtaValue)
// MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", mtaValue)
}
}

View File

@ -13,7 +13,7 @@ class DownloadDialogPlatformRequestItemViewHolder(val binding: DownloadDialogPla
binding.content.setOnClickListener {
val intent = VoteActivity.getIntent(it.context, gameEntity.name, gameEntity.id)
it.context.startActivity(intent)
MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", gameEntity.name + "_求版本")
// MtaHelper.onEvent(DownloadDialog.MTA_KEY, "点击", gameEntity.name + "_求版本")
}
}
}

View File

@ -61,15 +61,13 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
var isInstalled = false
apk.apkCollection?.saveApkEntity?.let {
for (entity in it) {
isInstalled = PackagesManager.isInstalled(entity.packageName)
&& Config.getSettings()?.gameDownloadBlackList?.contains(entity.packageName) != true
isInstalled = isInstalled(entity.packageName)
if (isInstalled) break
}
}
isInstalled
} else {
PackagesManager.isInstalled(apk.packageName)
&& Config.getSettings()?.gameDownloadBlackList?.contains(apk.packageName) != true
isInstalled(apk.packageName)
}
if (installed) {
mInstalledApkList.add(apk)
@ -78,6 +76,24 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
}
}
// 判断是否显示合集插件化提示
mInstalledApkList.forEach { apk ->
if (apk.apkCollection != null) {
var hasPluggable = false
var installedPlugin = false
apk.apkCollection?.saveApkEntity?.forEach { collectionApk ->
if (PackageUtils.isCanPluggable(collectionApk)) {
hasPluggable = true
} else if (PackageUtils.getGhId(collectionApk.packageName) == gameEntity.id) {
installedPlugin = true
}
if (apk.apkCollection?.saveApkEntity?.last() == collectionApk) {
apk.apkCollection?.showPluggableHint = hasPluggable && !installedPlugin
}
}
}
}
mInstalledApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
mOtherApkList.sortWith(Comparator { o1, o2 -> o2.order - o1.order })
@ -132,7 +148,7 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
return SORT_PLUGGABLE
} else if (PackageUtils.isCanUpdate(apkEntity, gameEntity.id)) {
return SORT_UPDATE
} else if (PackageUtils.getMetaData(getApplication(), packageName, "gh_id") == gameEntity.id) {
} else if (PackageUtils.getGhId(packageName) == gameEntity.id) {
return SORT_NORMAL_LAUNCH
}
}
@ -224,6 +240,14 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
}
}
// 仅用于多平台面板的已安装判断
private fun isInstalled(packageName: String): Boolean {
val ghId = PackageUtils.getGhId(packageName)
return PackagesManager.isInstalled(packageName)
&& (ghId == null || ghId == gameEntity.id)
&& Config.getSettings()?.gameDownloadBlackList?.contains(packageName) != true
}
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

View File

@ -21,8 +21,10 @@ class BlockActivity : NormalActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setToolbarMenu(R.menu.menu_download)
}
DownloadManager.getInstance(this).updateSpeedLimitationReleaseDelay(10)
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, BlockActivity::class.java, GameFragment::class.java)
}
override fun showDownloadMenu(): Boolean {

View File

@ -6,7 +6,6 @@ import android.os.Bundle;
import com.gh.base.fragment.BaseFragment_TabLayout;
import com.gh.common.util.EntranceUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.download.DownloadFragment;
/**
@ -49,11 +48,4 @@ public class DownloadManagerActivity extends NormalActivity {
bundle.putString(EntranceUtils.KEY_PACKAGENAME, packageName);
return getTargetIntent(context, DownloadManagerActivity.class, DownloadFragment.class, bundle);
}
@Override
protected void onResume() {
super.onResume();
DownloadManager.getInstance(this).disableDownloadSpeedLimit();
}
}

View File

@ -12,7 +12,6 @@ import com.gh.common.exposure.ExposureType;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.halo.assistant.HaloApp;
@ -30,7 +29,6 @@ public class GameDetailActivity extends NormalActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DownloadManager.getInstance(this).updateSpeedLimitationReleaseDelay(10);
DisplayUtils.transparentStatusBar(this);
}

View File

@ -8,6 +8,7 @@ import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -18,6 +19,7 @@ import com.ethanhua.skeleton.Skeleton;
import com.ethanhua.skeleton.ViewSkeletonScreen;
import com.gh.base.OnRequestCallBackListener;
import com.gh.base.ToolBarActivity;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.util.ApkActiveUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.common.util.DeviceTokenUtils;
@ -82,6 +84,8 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
DownloadProgressBar mDownloadPb;
@BindView(R.id.list_skeleton)
View mListSkeleton;
@BindView(R.id.detail_ll_bottom)
View mDetailBottom;
private ViewSkeletonScreen mSkeleton;
@ -210,6 +214,11 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
checkLibaoStatus();
}
}
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mDetailBottom.getLayoutParams();
params.topMargin = 0;
mDetailBottom.setLayoutParams(params);
}
@Override
@ -348,8 +357,14 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
// 获取游戏摘要
private void getGameDigest() {
if (mLibaoEntity.getGame() == null) return;
String gameId = mLibaoEntity.getGame().getId();
RetrofitManager.getInstance(this).getApi().getGameNewsDigest(gameId)
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
return;
}
RetrofitManager.getInstance(this).getSensitiveApi().getGameNewsDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

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;
@ -45,6 +48,7 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.HomePluggableHelper;
import com.gh.common.util.LogUtils;
import com.gh.common.util.LunchType;
import com.gh.common.util.MtaHelper;
@ -116,8 +120,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;
@ -214,8 +216,9 @@ public class MainActivity extends BaseActivity {
// checkTinkerPath(); // 看情况是否需要显示补丁弹窗
// 必须放在这里,否会导致获取baseActivity不是本应用包名
DownloadManager.getInstance(this).initDownloadService();
// 必须放在这里,否会导致获取 baseActivity 不是本应用包名
// postDelayed 是为了让 ProcessLifecycleOwner 知道准确状态,避免调用 startForegroundService
handler.postDelayed(() -> DownloadManager.getInstance(this).initDownloadService(), 0);
checkNotificationPermission();
@ -258,6 +261,8 @@ public class MainActivity extends BaseActivity {
PlatformUtils.getInstance(getApplicationContext());
// 友盟记录启动
PushAgent.getInstance(this).onAppStart();
HomePluggableHelper.activationFilterData();
});
@ -712,12 +717,12 @@ public class MainActivity extends BaseActivity {
kv6.put("安装或卸载", "安装完成");
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
DataUtils.onMtaEvent(this,
"插件化_新",
"位置", mDownloadEntity.getEntrance(),
"游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
"操作", "安装完成",
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "安装完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
}
// 没有光环 ID 的都记录一下游戏 ID供'我的游戏'区分同包名不同插件用
@ -733,7 +738,7 @@ public class MainActivity extends BaseActivity {
if (mSp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
// 安装后关注游戏
DownloadEntity finalDownloadEntity = mDownloadEntity;
RetrofitManager.getInstance(this).getApi().getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
RetrofitManager.getInstance(this).getSensitiveApi().getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<List<GameDigestEntity>>() {
@ -760,12 +765,12 @@ public class MainActivity extends BaseActivity {
kv6.put("安装或卸载", "卸载完成");
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
DataUtils.onMtaEvent(this,
"插件化_新",
"位置", mDownloadEntity.getEntrance(),
"游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
"操作", "卸载完成",
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
// DataUtils.onMtaEvent(this,
// "插件化_新",
// "位置", mDownloadEntity.getEntrance(),
// "游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
// "操作", "卸载完成",
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
startActivity(PackageUtils.getInstallIntent(this, mDownloadEntity.getPath()));
}

View File

@ -18,15 +18,11 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.ethanhua.skeleton.Skeleton;
import com.ethanhua.skeleton.ViewSkeletonScreen;
import com.gh.base.OnRequestCallBackListener;
import com.gh.base.ToolBarActivity;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryHelper;
import com.gh.common.util.ApkActiveUtils;
import com.gh.common.util.CheckLoginUtils;
@ -40,6 +36,7 @@ import com.gh.common.util.EntranceUtils;
import com.gh.common.util.GdtHelper;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.ShareUtils;
import com.gh.common.view.FixLinearLayoutManager;
import com.gh.common.view.VerticalItemDecoration;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.adapter.viewholder.DetailViewHolder;
@ -68,6 +65,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -257,7 +257,7 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
// init RecyclerView
mDetailRv.setHasFixedSize(true);
mDetailRv.setLayoutManager(new LinearLayoutManager(this));
mDetailRv.setLayoutManager(new FixLinearLayoutManager(this));
mDetailRv.addItemDecoration(new VerticalItemDecoration(this, 8, false));
adapter = new NewsDetailAdapter(this, this, mEntrance);
mDetailRv.setAdapter(adapter);
@ -323,7 +323,7 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
shareIcon = gameEntity.getIcon();
}
showShare(url, shareIcon, adapter.getNewsDetailEntity().getTitle(),
"来自光环助手(最强卡牌神器)", ShareUtils.ShareType.news);
"来自光环助手(最强卡牌神器)", ShareUtils.ShareEntrance.news, adapter.getNewsDetailEntity().getId());
}
break;
case R.id.menu_collect:
@ -613,11 +613,15 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
}
private void getGameDetail(String gameId) {
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
return;
}
if (TextUtils.isEmpty(gameId)) {
mDetailBottomLl.setVisibility(View.GONE);
return;
}
RetrofitManager.getInstance(this).getApi().getGameNewsDigest(gameId)
RetrofitManager.getInstance(this).getSensitiveApi().getGameNewsDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -7,11 +7,11 @@ import android.text.TextUtils;
import android.view.MenuItem;
import android.view.MotionEvent;
import androidx.fragment.app.Fragment;
import com.gh.base.ToolBarActivity;
import com.gh.gamecenter.normal.NormalFragment;
import androidx.fragment.app.Fragment;
/**
* Created by khy on 17/10/17.
*/
@ -108,7 +108,9 @@ public abstract class NormalActivity extends ToolBarActivity {
@Override
public void onBackPressed() {
if (mTargetFragment instanceof NormalFragment && !((NormalFragment) mTargetFragment).onBackPressed()) {
if (mTargetFragment.isAdded()
&& mTargetFragment instanceof NormalFragment
&& !((NormalFragment) mTargetFragment).onBackPressed()) {
super.onBackPressed();
}
}

View File

@ -22,4 +22,8 @@ class QaActivity : NormalActivity() {
return getTargetIntent(context, QaActivity::class.java, HelpContainerFragment::class.java, args)
}
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, QaActivity::class.java, HelpContainerFragment::class.java)
}
}

View File

@ -141,7 +141,7 @@ open class SearchActivity : BaseActivity() {
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(DisplayType.GAME_DETAIL)
MtaHelper.onEvent("游戏搜索", "默认搜索", key)
// MtaHelper.onEvent("游戏搜索", "默认搜索", key)
}
SearchType.HOT -> {
mSearchKey = key
@ -154,7 +154,7 @@ open class SearchActivity : BaseActivity() {
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(DisplayType.GAME_DETAIL)
MtaHelper.onEvent("游戏搜索", "历史搜索", key)
// MtaHelper.onEvent("游戏搜索", "历史搜索", key)
}
SearchType.MANUAL -> {
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
@ -173,7 +173,7 @@ open class SearchActivity : BaseActivity() {
toast("请输入搜索内容")
}
}
MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
// MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
}
}
mIsAutoSearchDisabled = false

View File

@ -67,7 +67,7 @@ public class ShareGhActivity extends ToolBarActivity {
QRCodeUtils.setQRCode(this, getString(R.string.gh_website_url_100), mGhQrcode);
ShareUtils.getInstance(this).showShareWindows(this, mShareRl, getString(R.string.gh_website_url_300)
, getString(R.string.gh_icon_url), "玩手游不用肝的感觉真好"
, "绿色安全的手游加速助手", ShareUtils.ShareType.shareGh);
, "绿色安全的手游加速助手", ShareUtils.ShareEntrance.shareGh, "");
}
@OnClick(R.id.gh_address_tv)

View File

@ -12,6 +12,7 @@ import com.gh.common.util.EntranceUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.RunningUtils;
import com.gh.gamecenter.entity.CommunityEntity;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.VideoLinkEntity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
@ -96,7 +97,7 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
break;
case HOST_GAME:
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, false, "libao".equals(to));
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, false, "libao".equals(to),null);
break;
case HOST_COLUMN:
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
@ -104,10 +105,17 @@ public class SkipActivity extends BaseActivity {
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
String content = String.format("%s-%s-V%s",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION));
String gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID);
String packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5);
String content = (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) ?
String.format("%s-%s-V%s",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION)) :
String.format("%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(KEY_GAME_NAME),
TextUtils.isEmpty(platformName) ? platform : platformName,
uri.getQueryParameter(KEY_VERSION), gameId, packageMd5);
DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER);
break;
case HOST_DOWNLOAD:
@ -265,6 +273,36 @@ public class SkipActivity extends BaseActivity {
columnId = uri.getQueryParameter("column_id");
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_BLOCK:
name = uri.getQueryParameter("name");
SubjectRecommendEntity entity = new SubjectRecommendEntity();
entity.setLink(path);
entity.setName(name);
entity.setText(name);
DirectUtils.directToBlock(this, entity);
break;
case EntranceUtils.HOST_SERVER_BLOCK:
DirectUtils.directToGameServers(this,ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_AMWAY_BLOCK:
DirectUtils.directToAmway(this, null, ENTRANCE_BROWSER, "浏览器");
break;
case EntranceUtils.HOST_HELP:
name = uri.getQueryParameter("name");
DirectUtils.directToQa(this, name, path);
break;
case EntranceUtils.HOST_HELP_COLLECTION:
name = uri.getQueryParameter("name");
DirectUtils.directToQaCollection(this, name, path);
break;
case EntranceUtils.HOST_GAME_UPLOAD:
DirectUtils.directGameUpload(this, ENTRANCE_BROWSER, "浏览器");
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;

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