Compare commits

...

442 Commits

Author SHA1 Message Date
9d622d2be9 消息中心标黄内容复制后去除前后空格 2019-01-30 09:46:52 +08:00
800525227d update MessageSpannableTextView 2019-01-29 18:25:09 +08:00
c9dec9a31e 草稿刷新时定位到列表顶部 2019-01-29 16:23:57 +08:00
2ae4fda6e8 优化ListViewModel 2019-01-28 19:26:02 +08:00
609702715f Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-28 17:59:06 +08:00
ec7e138208 光环助手V3.6.1 RELEASE(20190128-1200)测试问题汇总(2.4) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/443 2019-01-28 17:58:25 +08:00
bfd64a8bce 修复开服表曝光的提交问题 2019-01-28 17:12:15 +08:00
5571b6481f Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-28 11:31:25 +08:00
6d6574988c 光环助手V3.6.1 RELEASE(20190125-1850)测试问题汇总(4.5.9.10.13) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/442#note_16676 2019-01-28 11:31:13 +08:00
af8d075bf2 修复了下载插件化应用时的卡顿问题 2019-01-26 17:44:12 +08:00
b7db66e90b 专题答案列表显示发布时间 2019-01-26 11:32:20 +08:00
13ac4658d9 通过微信分享前先检测用户是否安装微信 2019-01-25 18:22:02 +08:00
8ad3420822 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-25 15:40:16 +08:00
f842ced67e 更换反馈图标 添加渠道号 2019-01-25 15:39:48 +08:00
e0081e56df Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-25 14:22:52 +08:00
3202764f22 屏蔽安卓 5.0 以下设备的视频播放功能 2019-01-25 14:22:39 +08:00
f477876359 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-25 14:08:26 +08:00
86ffcb92f8 admin api host -> 3.6.1
1月25补充优化
2019-01-25 14:08:18 +08:00
a2088e5cd9 修复问题详情页面的答案没有显示发布时间的问题 2019-01-25 09:58:38 +08:00
6e1247f393 消息客服跳转过滤无链接数据 2019-01-24 18:19:27 +08:00
c33faa4918 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-24 15:39:57 +08:00
d0aeb1c411 修改反馈文案
修复插件化完成后更新不及时问题
2019-01-24 15:39:33 +08:00
485924527e 避免发送无用的关注请求 2019-01-24 15:19:15 +08:00
ca1bfda326 更换反馈图标 2019-01-23 18:31:27 +08:00
c7c786d662 修改社区搜索路径关键字 2019-01-23 17:47:02 +08:00
acf9fe308c 光环助手V3.6.1数据统计需求(光环数据后台) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/440 2019-01-23 16:59:53 +08:00
3b32231709 修复嵌套 recyclerview 因为焦点获取而触发莫名位移的问题 2019-01-23 16:43:18 +08:00
9dae198af2 修复曝光下载完成事件里 payload 没有游戏 id 的问题 2019-01-23 14:50:53 +08:00
29bfd5bb93 处理空指针异常 2019-01-23 11:49:51 +08:00
8da51d7f5a 回答数量限制弹窗优化
优化消息中心标黄判断
2019-01-23 11:30:42 +08:00
91964a0ffc Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-22 19:17:26 +08:00
479ef20859 dev api host -> 3.6.1
光环助手V3.6.1-消息中心优化(测试未通过)  https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/435
2019-01-22 19:17:08 +08:00
f458b7dcb8 将MTA的[游戏详情]计算事件换成普通事件[游戏详情_新] 2019-01-22 18:24:31 +08:00
2d25ff7836 开服表添加曝光统计 2019-01-22 18:13:46 +08:00
57dd5d0584 关注游戏区分自动和手动 2019-01-22 18:13:18 +08:00
757efec05e 回答卡片增加回答发布时间 2019-01-22 18:12:21 +08:00
4979045be2 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-21 17:00:59 +08:00
f59af60f70 游戏详情增加社区跳转提示 2019-01-21 17:00:04 +08:00
60bc2a02f4 修复一些闪退问题 2019-01-21 16:21:34 +08:00
996be3906e versionCode->60 versionName->3.6.1 2019-01-21 15:55:50 +08:00
14a054bdbc 游戏详情 增加加载骨架 2019-01-21 15:50:36 +08:00
07a9fd6273 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-21 14:43:21 +08:00
a067f7bc43 礼包详情/专题详情 增加加载骨架 2019-01-21 14:43:11 +08:00
a5eefbb6f4 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-21 10:57:35 +08:00
8d9f83c432 处理值转换异常 2019-01-21 10:57:24 +08:00
ae0df36a89 处理非空异常 2019-01-21 10:56:44 +08:00
72539671a1 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-21 10:31:43 +08:00
94277a4aeb 游戏分类增加加载骨架 2019-01-21 10:31:25 +08:00
e276d148cf 统一文本输入框的超出字数逻辑 2019-01-20 18:34:34 +08:00
a7152034e8 修复上传弹窗重复显示问题 2019-01-20 16:54:16 +08:00
4a5e9da34a 可以由后台控制关闭资讯相关的功能 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/434 2019-01-20 14:23:29 +08:00
1422365cc5 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-20 10:17:36 +08:00
7f55ff6340 根据包名过滤下载按钮状态 2019-01-20 10:17:23 +08:00
4722626fb7 添加百度信息流激活统计请求 2019-01-17 17:07:08 +08:00
39d87ad98d 图片加载支持 gif 2019-01-17 17:06:20 +08:00
85333b9eed 更新七陌客服 SDK 2019-01-17 16:03:58 +08:00
c99ae6db3e 修复游戏列表下载状态异常问题 2019-01-17 15:25:48 +08:00
c5be98adc2 修复手机没有图片选择应用时调用会崩溃的问题 2019-01-16 19:08:18 +08:00
5321aa2e9f Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-16 19:00:50 +08:00
345707ef42 光环前端需求汇总(2019年1月第3周)1.9.11 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/432 2019-01-16 18:35:22 +08:00
6a9d05d916 修复部分以 .html 结尾的下载链接无法下载的问题 2019-01-16 15:45:40 +08:00
faf2a89706 修复了 GID 初始化顺序不一造成的闪退问题 2019-01-15 11:29:57 +08:00
ada51f90f1 修复了一个数组越界造成的闪退问题 2019-01-15 10:08:18 +08:00
53962116d5 修复了我的游戏中同包名游戏显示错误前缀以及安装包名刷新不及时的问题 2019-01-10 15:26:15 +08:00
3ea52745b3 如果已安装的是光环助手的游戏包那么对应的已安装列表只会存在一条已安装信息 2019-01-10 09:53:21 +08:00
a8f2289b27 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2019-01-09 18:16:31 +08:00
6dd56b5d16 光环前端需求汇总(2019年1月第2周)(1.3.4.5.6.7) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/428#note_15724 2019-01-09 18:15:45 +08:00
eb739cf6cb 修复了插件化弹窗安装状态更新不及时的问题 2019-01-09 17:08:18 +08:00
4853cd9047 修复了文章详情 gif 图片会闪烁的问题 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/424 2019-01-07 12:03:40 +08:00
4e0f14aeed 首页 tab 添加水波纹效果 2019-01-05 18:01:28 +08:00
5e37dac0f6 处理空指针异常 2019-01-05 10:06:01 +08:00
22bfa9051a 修复由于列表重用机制导致的游戏名字长度异常问题 2019-01-04 14:23:32 +08:00
0a1dca3aa3 修复游戏详情大家都在玩列表会显示下载'暂无'字样的游戏的问题 2019-01-04 10:55:15 +08:00
0b20896330 3.6封包 2018-12-29 19:00:46 +08:00
3b934578dd 修改游戏列表样式 2018-12-29 17:51:34 +08:00
c42e1a76bf 3.6封包 2018-12-29 09:21:23 +08:00
d3f2395d9c 捕抓删包异常 2018-12-28 20:41:01 +08:00
b5ba1e877f 将时间敏感的SP写入操作从 apply 换成 commit 2018-12-28 20:17:57 +08:00
eba27d8969 微调游戏列表间距 2018-12-28 18:32:01 +08:00
fe1d4d3406 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-28 17:41:34 +08:00
28418b0d49 update .gitignore 2018-12-28 17:41:16 +08:00
f35396c0e3 修复了关注页面,存在红点且为首次加载时重复加载的问题 2018-12-28 17:33:32 +08:00
67cc464607 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-28 15:57:51 +08:00
b0fa0392b7 调整首页游戏间距
我回答过的问题,最后答案都被隐藏了,在问题详情不要显示 [我来回答] 按钮
2018-12-28 15:57:38 +08:00
0fc4fddfe7 处理部分错误错误码 2018-12-28 11:42:27 +08:00
f092966c88 赞同列表弹窗的宽度改为80%屏幕宽度 2018-12-28 11:29:11 +08:00
0e1cb515ab 游戏列表摘要文案显示为灰色 2018-12-28 10:37:38 +08:00
35115d0581 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-27 18:19:43 +08:00
b1d1fc0e36 修复问答-关注切换社区关注用户可能多次调用刷新数据的问题 2018-12-27 18:19:30 +08:00
91f84cdd5c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-27 18:08:42 +08:00
ad2c155e54 光环助手V3.6 RELEASE(20181227-1530)测试问题汇总 https://gitlab.ghzhushou.com/pm/issues-Inbox/issues/838 2018-12-27 18:08:30 +08:00
fc4b383292 修复问答-关注切换社区关注用户可能多次调用刷新数据的问题,微调 UI 2018-12-27 18:08:09 +08:00
1a868d3f12 修复问答-关注切换社区关注用户可能多次调用刷新数据的问题 2018-12-27 17:53:34 +08:00
e4dd96e21a Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-27 15:12:18 +08:00
8705f8d2e2 横向游戏列表游戏名加粗
游戏搜索显示游戏标签
版主修改历史优化
2018-12-27 15:12:10 +08:00
65fab5e990 修复关注页面赞同折叠的显示问题 2018-12-27 11:18:49 +08:00
1d92b070eb 将 listViewModel 里更新加载状态的方法由 postValue 换成 setValue 以避免快速多次调用触发分页问题 2018-12-27 10:27:23 +08:00
d72102784e Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-26 20:01:57 +08:00
d7351bf93e 修复了问答关注推荐用户界面即时关注了新用户依旧存在的问题 2018-12-26 20:01:47 +08:00
6bf40ca237 修复同一个包存在多个更新的问题
修复已安装列表出现下载按钮问题
版主修改标签增加默认标签
2018-12-26 17:34:44 +08:00
4be93781b2 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-26 14:26:04 +08:00
13fc6b8453 版主历史版本增加初始内容(未修改),修改app更新逻辑 2018-12-26 14:25:56 +08:00
34cbbdffb9 修复一个重复调用列表 onRefresh 造成的显示问题 2018-12-26 12:04:41 +08:00
e45eadb6e3 3.6 (20181225-1850) 问题汇总 (6,7,12,13,14) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/420 2018-12-26 10:51:56 +08:00
7bf2ef1007 修复点赞数量为零的情况,社区投票 已开通的toast文案修改 2018-12-26 10:33:25 +08:00
23c46cc4b2 修改邀请错误文案 2018-12-25 15:20:53 +08:00
259adbf145 光环助手V3.6 RELEASE(20181224-1145)测试问题汇总(前端)(2,3,6,10,11,13,14) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/419 2018-12-25 15:12:00 +08:00
95acc64e42 光环助手V3.6 RELEASE(20181224-1145)测试问题汇总(前端)(7.8.16)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/419 2018-12-25 15:02:10 +08:00
974d4fcefa 修复查看礼包闪退问题 2018-12-24 15:22:49 +08:00
298733b192 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-24 11:22:34 +08:00
2ec4c75049 实现下拉刷新更新轮播图(首页-游戏,首页-问答) 2018-12-24 11:22:25 +08:00
bfac5398fc 优化曝光模块代码 2018-12-24 10:43:53 +08:00
d029b1692a 优化曝光模块代码 2018-12-23 16:19:55 +08:00
d7006f25f7 光环助手V3.6 DEV(20181220-1000)测试问题汇总(前端)(10.11.12.14.30.36) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/417#note_14957 2018-12-23 14:30:00 +08:00
ef56910da0 修复曝光事件里 gid 可能为空的问题 2018-12-23 10:20:11 +08:00
dbf73a0385 修复发现页面闪退问题 2018-12-22 18:03:19 +08:00
41b8cae6bd 光环助手V3.6 DEV(20181220-1000)测试问题汇总(前端)(23.24.26.27.28.38) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/417 2018-12-22 17:52:39 +08:00
0bea685ce1 优化信息流推荐关注 2018-12-21 18:09:59 +08:00
acd39aa969 完成光环助手V3.6 DEV(20181220-1000)测试问题汇总(前端) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/417 的 4、5、7、6、8、17、18 2018-12-21 17:22:32 +08:00
fd59e71714 光环助手V3.6 DEV(20181220-1000)测试问题汇总(前端)(9.25.31.33.34.35.37) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/417 2018-12-21 17:03:05 +08:00
47c37a1a7e 优化信息流 推荐关注,admin api 升为v3d6 2018-12-21 10:58:58 +08:00
774f9bac80 修复问答-推荐 重复刷新问题 2018-12-21 10:36:16 +08:00
316eb738ec Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-20 17:32:26 +08:00
af493d9dfb 登录事件触发地点修改,优化信息流推荐关注 2018-12-20 17:32:05 +08:00
3d626abbc2 修复自动搜索不显示广告的问题 2018-12-20 15:40:38 +08:00
a392f7f8d8 修復初始化闪退问题 2018-12-20 11:42:01 +08:00
8f8f4c645a 发现页面分割线,改为0.5dp 2018-12-19 16:54:54 +08:00
1cae62fb99 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/res/layout/fragment_discover.xml
2018-12-19 16:38:50 +08:00
6db72fa7e7 光环助手V3.6 DEV(20181213-1500)测试问题汇总(UI) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/415 2018-12-19 16:34:10 +08:00
6ee300c70e 将问答顶部几个 tab 的宽度变成自适应 2018-12-19 15:43:43 +08:00
0f16790535 基本完成广告入口需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/412 2018-12-19 14:55:36 +08:00
524742b8ea 光环助手V3.6 DEV(20181213-1500)测试问题汇总(前端)(9.10.16.17.24)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/413 2018-12-18 19:41:31 +08:00
8c08bbea6a Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-18 16:02:36 +08:00
d6c2bd6634 修复反馈闪退问题 2018-12-18 16:02:21 +08:00
4aeb42dee9 精简部分无用代码 2018-12-18 14:26:34 +08:00
0de7f40958 修复 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/413 的 3、4、5、6、19(2)、20、22、25 点 2018-12-18 14:25:51 +08:00
07fd8d986e 捕抓异常 2018-12-18 14:23:16 +08:00
c821923cd0 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-17 17:10:47 +08:00
6ce247d8d1 更改引导图 部分登录入口统计修改 2018-12-17 17:10:34 +08:00
473d8c43df Merge branch 'fix_background_service' into 'dev'
尝试解决 https://gitlab.ghzhushou.com/halo/assistant-android/issues/7

See merge request !2
2018-12-17 16:22:11 +08:00
e082b321eb 尝试解决 https://gitlab.ghzhushou.com/halo/assistant-android/issues/7
1. 当设备满足系统版本为 8.0+ 且应用在后台运行时,使用 startForegroundService() 启动 DownloadService ,否则使用原来的 startService() 启动 DownloadService

2. 当应用从后台切换回前台并且 DownloadService 是前台服务时,手动调用 Service.stopForeground() 来去掉前台服务标记
2018-12-17 16:18:05 +08:00
fd236857d4 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailActivity.kt
2018-12-14 17:35:27 +08:00
9290934ec3 光环助手V3.6数据统计需求(登录入口统计) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/407 2018-12-14 17:20:39 +08:00
b6d9118d05 修复一个在华为设备上注册过多 broadcast receiver 会崩溃的问题 2018-12-14 11:50:38 +08:00
544d21613a 增加腾讯广告用户分群 SDK 2018-12-14 10:56:32 +08:00
68a7720ea9 补充开服表 MTA 事件 2018-12-13 18:00:03 +08:00
01a537c0f6 修复打包失败问题(使用javax包下的内容导致) 2018-12-13 17:21:40 +08:00
11bd2a5831 versionName->3.6
versionCode->50
2018-12-13 16:26:08 +08:00
d615a07f27 基本完成 3.6 MTA 统计需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/408 2018-12-13 10:56:40 +08:00
ef941a7651 微调菜单UI 2018-12-13 09:42:56 +08:00
928ed40dd4 社区上报阅读数据增加相关字段 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/406#note_14390 2018-12-12 17:17:36 +08:00
03f3f174c3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-12 16:24:13 +08:00
6a1a38fb5e 问答-推荐增加推荐关注完成 2018-12-12 16:23:59 +08:00
9f4ca9a3bb Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-12 15:06:58 +08:00
670786cc2d 完善点赞引导和关注引导 2018-12-12 15:06:52 +08:00
cc3b4ba7e9 禁言状态提醒从 toast 改为 dialog 2018-12-12 10:55:19 +08:00
b8d5246230 当引用的评论被隐藏 内容显示未该内容已被删除 2018-12-11 16:46:12 +08:00
37665acd3c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-11 15:03:59 +08:00
5aef4d649a 优化版主管理问题详情权限问题 2018-12-11 15:03:46 +08:00
90c050590a 搜索列表添加曝光统计 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/405 2018-12-11 14:33:50 +08:00
3115152f32 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-11 10:52:26 +08:00
923562ad8e 礼包增加查看状态,客服私信增加问题类型,社区推荐轮播图大小设为按比例缩放 2018-12-11 10:52:01 +08:00
1b2b9b3b91 更换显示游戏"新服"的字段,消息推送点击标记已读 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/402 2018-12-11 10:12:08 +08:00
8412044b88 增加检查登录的 extensions 2018-12-11 10:10:24 +08:00
ceb2384eb8 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
2018-12-10 16:18:45 +08:00
1244efd015 基本完成社区版主权限答案部分 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/395 2018-12-10 16:17:24 +08:00
1cc572f774 版主修改历史/详情 对接数据接口,app更新对比改用VersionCode 2018-12-10 16:16:20 +08:00
f43c9e5d67 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-09 17:40:56 +08:00
22387e8e60 光环助手V3.6优化需求汇总(20181206)(1.2.5.7.8.9.10.13.21.22)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/402#note_14212 2018-12-09 17:40:47 +08:00
9284af351a Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-08 15:44:51 +08:00
07cbd3c031 捕获写入曝光数据库的异常 2018-12-08 15:44:36 +08:00
1d03d171e0 发送游戏页面增加定位权限申请(避免在某些设备上没有权限闪退 2018-12-08 15:42:46 +08:00
1abb783f4c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-07 16:07:55 +08:00
d37c809973 版主隐藏问题对接数据接口 2018-12-07 16:07:43 +08:00
0feffda7f3 完成 V3.6 部分优化 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/402 2018-12-07 16:06:54 +08:00
b5bfbfaff6 基本完成社区关注 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/391 补充部分 2018-12-06 18:05:09 +08:00
25a4171631 更新 GID 库 2018-12-06 18:04:13 +08:00
8622aa787a 版主修改问题对接数据接口 2018-12-06 17:42:23 +08:00
dd44a34e18 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-06 11:55:25 +08:00
da91e7de1d 优化版主问题标签 2018-12-06 11:55:16 +08:00
c32798cbb0 捕抓异常,避免闪退 2018-12-06 10:15:11 +08:00
a03754d02b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-05 18:08:58 +08:00
a9351b29ab 问答推荐增加“推荐关注”(尚未对接网络数据) 2018-12-05 18:08:51 +08:00
84a27b504d 基本完成 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/400 答案详情引导修改 2018-12-05 17:59:57 +08:00
91e2432b48 微调问答关注页面 UI 2018-12-05 15:54:46 +08:00
505da678f0 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-05 14:19:53 +08:00
e0b44bf41c 整理app更新相关/礼包详情代码 2018-12-05 14:19:44 +08:00
f856ff5957 微调回答详情点赞动画特效 2018-12-05 10:21:48 +08:00
65fdb90ccb 回答详情添加动画效果,具体触发逻辑还得等后台确定接口 2018-12-05 10:12:34 +08:00
82372dc33b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-04 17:53:32 +08:00
14fb79b90c 更改过滤已隐藏包的逻辑 2018-12-04 17:53:19 +08:00
050c7f9d86 处理非空异常 2018-12-04 17:03:08 +08:00
6efd3a3239 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-03 15:36:12 +08:00
f1c0888309 修复对获取服务器时间这个接口的解析问题 2018-12-03 15:35:58 +08:00
1e9ade68f7 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-03 15:07:45 +08:00
58a0fd8fdb 修复游戏详情截图尺寸不对问题 2018-12-03 15:07:35 +08:00
cd523bd552 修复对获取服务器时间这个接口的解析问题 2018-12-03 14:59:16 +08:00
22f68d098c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-12-03 11:17:18 +08:00
5d3657938d 删除tinker_version_name(由于app推送更新方式变更,不再需要tinker_version_name) 2018-12-03 11:16:26 +08:00
f2002ff1ce 修复初始化问题 2018-12-03 10:51:08 +08:00
49600213b7 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/qa/AskViewModel.kt
2018-11-30 18:18:17 +08:00
4d87edb1fd 删除部分无用代码 完成部分todo 2018-11-30 18:16:18 +08:00
b536f263f2 修复一个初始化异常问题 2018-11-30 16:36:10 +08:00
65c1300c63 去掉用不到的 iosched 2018-11-30 10:43:45 +08:00
f1cc12eea3 微调代码结构 2018-11-30 10:34:48 +08:00
0c5dd84c27 略微调整代码结构 2018-11-30 10:21:23 +08:00
df8753e1c4 优化管理员修改问题,修复资讯中心三张图片的Item无法显示问题 2018-11-29 17:21:54 +08:00
eb9dba3bc7 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-11-28 18:41:00 +08:00
86247e4a61 回退问答-推荐访问路径 增加问题历史和历史详情 2018-11-28 18:40:45 +08:00
fc46584735 修复初始化问题 2018-11-28 18:25:06 +08:00
dab87d46fa 修复初始化问题 2018-11-28 18:07:10 +08:00
1968f4b7f3 将应用初始化的操作移动到子线程,缩短启动速度 2018-11-28 17:41:11 +08:00
3b1556f931 将 annotationProcessor 换成 kapt
(文档 https://kotlinlang.org/docs/reference/kapt.html#using-in-gradle 说 kapt 可以完全替换掉 annotationProcessor,尝试去掉来确定 butterknife 偶发找不到 id 是不是这个造成的)
2018-11-28 16:33:41 +08:00
249332848c 修正问答统计访问路径(问答-推荐),修改编辑问题-标签选择 2018-11-27 19:02:54 +08:00
26058934cd 完善打特殊包的脚本 2018-11-26 17:12:11 +08:00
11298d26e7 更新 proguard 规则以适配新的 LogHub 依赖 2018-11-26 14:37:00 +08:00
394d558707 修复用户使用 AppOps 绕过外部存储权限授予限制,使游戏下载到内部存储 '/data/user/...' ,造成游戏无法安装/安装崩溃的问题 2018-11-26 11:39:21 +08:00
058d55ea82 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-11-26 10:31:49 +08:00
903109f8d5 增加打特殊包的脚本 2018-11-26 10:31:30 +08:00
4876abb0ed 更新 gid 依赖,修复崩溃问题 2018-11-26 10:27:07 +08:00
f75490aec2 捕获获取安装包信息的异常 2018-11-26 10:26:17 +08:00
b2e3ae684d 删除strings.xml重复参数 2018-11-25 18:36:14 +08:00
5b4f5e0ef8 下载状态相关字符串抽离到 Strings.xml 2018-11-25 18:25:27 +08:00
5fb6f7dbb2 默认隐藏游戏列表排序数值 2018-11-23 17:13:06 +08:00
c8e32fd968 更改游戏列表开服标签的实现方式 2018-11-22 19:17:18 +08:00
15f4f58164 整理社区选择‘投票中’代码 2018-11-22 15:52:26 +08:00
291410cc1c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-11-22 15:24:32 +08:00
dd9d6cc452 光环助手V3.6-问答社区优化需求汇总[社区投票优化] https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/394 2018-11-22 15:24:22 +08:00
8866d7f71e 修复 9.0 部分设备没有读写权限会崩溃的问题 2018-11-21 17:34:15 +08:00
83bcd89c0c 微调问答邀请列表的 UI 2018-11-21 16:58:08 +08:00
0a2160e18a 修复在部分无法获取 IMEI 的机器上无法加载网络数据的问题 2018-11-21 16:57:25 +08:00
acab1d89aa 光环助手V3.6-问答社区优化需求汇总(Bug汇总) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/394 2018-11-21 15:53:20 +08:00
42176d334e 统一游戏列表样式,删除无用代码 2018-11-20 17:18:57 +08:00
5db3563400 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-11-19 17:41:49 +08:00
50f26101cb 首页游戏增加预览样式以及调整部分首页游戏样式 2018-11-19 17:41:30 +08:00
20915963f8 基本完成社区首页新增的[关注]时间线功能 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/391 2018-11-19 15:07:27 +08:00
e0fce2c2bf Merge branch 'install_helper' into dev 2018-11-15 11:08:28 +08:00
069340ecd1 修改包名 2018-11-15 11:07:48 +08:00
ca5a34e09d 删除部分todo 2018-11-15 10:41:10 +08:00
08fe5e8f83 PackageViewModel 增加重试功能 2018-11-14 16:30:31 +08:00
12623fd383 PackageRepository 添加光环助手更新逻辑 2018-11-14 11:33:25 +08:00
d52bd00ab9 删除无用代码 2018-11-14 10:12:06 +08:00
11963ef040 InstallManager相关的应用全部整合到PackagesManager 2018-11-13 18:26:27 +08:00
03ce6f80a1 下载管理-游戏更新接入PackageViewModel
重构PackageManager相关
2018-11-13 16:30:30 +08:00
42ea33612d 更新 logHubHelper ,支持无网发送失败时有网重试 2018-11-13 10:13:57 +08:00
1cc0c51390 重构本地已安装的相关数据(更新/插件化/已安装的游戏列表)
已对接:首页插件化区域,我的游戏页面
2018-11-12 16:52:26 +08:00
62740ffcb6 tinkerVersionName->3.5.1 2018-11-08 14:48:33 +08:00
727616c764 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/kaifu/KaiFuVpFragment.java
2018-11-08 11:33:44 +08:00
1b6fd03ba3 修复开服表存在置顶项进入直接点击下一开服会一直滚动到底部的问题 2018-11-08 11:26:54 +08:00
53bb1dee01 修复总开复表存在热门开服点击下一节直接跳到底部问题 2018-11-08 11:26:40 +08:00
467950ae2c 优化首页游戏以及板块页面交互问题 2018-11-07 18:14:37 +08:00
5248ad3b6a 选择社区列表增加“上拉加载”状态 2018-11-06 17:44:55 +08:00
3e41af7f41 社区推荐修改默认刷新文案 2018-11-06 15:08:01 +08:00
c01a9c1140 横向游戏列表加上礼包图标, 问题推荐增加默认刷新文案 2018-11-06 14:50:22 +08:00
36def0a511 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-11-06 10:09:29 +08:00
077f768d09 光环助手V3.5 RELEASE(20181101-1540)(2.4.5.6.7.8.9.12)测试问题汇总 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/387 2018-11-06 10:09:12 +08:00
c2eafeb9a4 修复一些空指针异常问题 2018-11-02 09:42:29 +08:00
526538a2a4 打tinker包 2018-11-01 15:38:54 +08:00
f84b3a6be1 versionCode 升为40 2018-11-01 15:17:48 +08:00
78f3b286ad Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-11-01 14:42:39 +08:00
83246b49dc 添加GH_TEST2渠道号 2018-11-01 14:41:59 +08:00
bb2ac7753f 游戏详情评分页面根据包名判断是否安装应用 2018-11-01 14:41:52 +08:00
8120b06403 游戏详情评分页面根据包名判断是否安装应用 2018-11-01 14:36:32 +08:00
03575b169c 游戏详情评分页面根据报名判断是否安装应用 2018-11-01 11:55:44 +08:00
5932c7b0a7 收藏,回答和文章 即时刷新 2018-11-01 10:53:04 +08:00
aac03abf14 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-31 08:00:44 +08:00
e1e51131fb 修复:平台下载面板 白色小点看不到 2018-10-31 08:00:30 +08:00
cb5747a2fb UI 微调 2018-10-31 07:54:50 +08:00
d5c8df3d1b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-31 07:05:24 +08:00
dad84e1d5a UI 微调 2018-10-31 07:04:59 +08:00
4ad03c196c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-31 05:46:07 +08:00
7168f5391d 光环助手V3.5 RELEASE(20181031-0240)测试问题汇总(前端)(3.7.8.10.11.13 补充1.3.4)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/385 2018-10-31 05:45:56 +08:00
2c5a21ec2a 修复了一些 UI 问题, 1、2、4、5、12 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/385 2018-10-31 05:15:28 +08:00
e80af77b8d 游戏详情-评论,全部评论区域,如果是自己的评论,要在昵称右边显示一个 [你的评论] 的标签 2018-10-31 03:04:54 +08:00
2ef43e821c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-31 02:31:38 +08:00
42e6b88220 光环助手V3.5 RELEASE(20181030-2215)测试问题汇总(前端)(5.6.9.13.14.15)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/384 2018-10-31 02:30:56 +08:00
a4a280ed34 UI 微调 2018-10-31 02:26:45 +08:00
94c3f0e4aa UI 微调 2018-10-31 02:24:18 +08:00
52783ccefc 修复了1、17 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/384 2018-10-31 02:07:55 +08:00
1926236d0b 修复社区问题无法加载GIF问题 2018-10-30 22:03:10 +08:00
446ee1d145 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/res/layout/fragment_comment_detail.xml
2018-10-30 19:46:47 +08:00
5fb5f10d9a 光环助手V3.5 RELEASE(20181029-1825)测试问题汇总(UI)(2.5.7.8.9.10.11.12.14)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/381 2018-10-30 19:45:20 +08:00
6da8d873d3 UI 微调 2018-10-30 19:38:10 +08:00
db23aecad9 查看对话增加原链接 2018-10-30 18:25:21 +08:00
31bd279b4b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-30 17:27:43 +08:00
8b2d249ea6 修复同包名出现多个更新应用的问题 1, 2 https://gitlab.ghzhushou.com/pm/yunying/issues/183 2018-10-30 17:27:33 +08:00
ab817169e8 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-30 17:20:00 +08:00
408e44636e 光环助手V3.5 RELEASE(20181029-1825)测试问题汇总(前端)(1.11.12.13.14.15.16.17.19.20.21.22.23.25.27.28.29.30(禁止输入空格).31.32.34)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/380 2018-10-30 17:19:32 +08:00
6145092086 修复了游戏详情的显示问题 4、5、6、7、10 点 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/380 2018-10-30 16:01:56 +08:00
a038fae17c 消息中心红点优化 2018-10-29 18:18:45 +08:00
779b844138 更换引导图 游戏详情关注图标 游戏动态-评论图标 举报图标 2018-10-29 17:30:05 +08:00
3fe52c36ef Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-29 16:56:37 +08:00
fa0c843126 光环助手V3.5 RELEASE(20181026-1720)测试问题汇总(前端)(1.2.3.11.16.17.20.21)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/378 2018-10-29 16:56:28 +08:00
6e0047c632 去掉引导页的 noHistory 配置,原因是开启会造成 6.0 设备在获取应用权限时崩溃 2018-10-29 16:26:38 +08:00
66d2ae99a6 UI 微调 2018-10-29 11:25:23 +08:00
b636bed83b 适配 Android 8.0 的 Receiver 限制 2018-10-29 09:59:20 +08:00
16fc9c0b09 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-28 18:47:10 +08:00
ee3b06d4aa Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# 请输入一个提交信息以解释此合并的必要性,尤其是将一个更新后的上游分支
# 合并到主题分支。
#
# 以 '#' 开头的行将被忽略,而且空提交说明将会终止提交。
2018-10-28 18:46:59 +08:00
ccc367a376 光环助手V3.5 RELEASE(20181024-1820)测试问题汇总(UI) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/377 2018-10-28 18:44:22 +08:00
054d0c74fc 微调游戏详情页介绍 tab 的样式 2018-10-28 16:58:06 +08:00
5d9554a46d Add todo. 2018-10-28 16:10:56 +08:00
47a77a5085 修复邀请达人没有头部标题的问题以及外部跳转至社区失败的问题 2018-10-28 16:10:45 +08:00
ef3854ae8d Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-28 15:09:22 +08:00
9b0a95aa54 光环助手V3.5 RELEASE(20181024-1820)测试问题汇总(前端)(6.7.8.16.18.19.20.21.28) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/376 2018-10-28 15:09:11 +08:00
26bc1299ff 修复部分测试汇总提及的问题 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/376 2018-10-28 14:14:56 +08:00
74c9cfc5b6 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-26 18:31:39 +08:00
a930a795db 修复个人主页-我的回答userId没有赋值问题 2018-10-26 18:31:24 +08:00
0a5e201936 调整邀请达人的回答和赞同字段 2018-10-26 18:20:29 +08:00
0989a27fdb Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-26 18:04:32 +08:00
e9a8b80476 修复游戏无法关注问题 2018-10-26 18:04:16 +08:00
36b0676bfc 修复了文章评论举报问题 2018-10-26 18:02:07 +08:00
8702440474 删除社区轮播图关联的提示 2018-10-26 17:43:19 +08:00
3413100602 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-26 17:17:26 +08:00
882f5bc28e 光环助手V3.5-社区文章问题汇总(1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.22.23.24)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/375 2018-10-26 17:17:07 +08:00
1ffb36e1a3 修复数据库升级的字段问题 2018-10-26 10:52:34 +08:00
b02ded094f 修复数据库升级的字段问题 2018-10-26 10:41:57 +08:00
36d9f9100c 游戏详情游戏介绍过长支持展开收回 2018-10-25 17:31:14 +08:00
83d695ee94 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-25 17:15:10 +08:00
4d76cf46f9 光环助手V3.5-游戏详情问题汇总(完成:7.8.9.11.12.13.14.15) https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/374 2018-10-25 17:15:02 +08:00
fa5a1daf68 修复 loghub 只能提交到一个库的问题 2018-10-25 16:06:24 +08:00
4563261c52 处理崩溃异常以及修复部分游戏详情页页问题 2018-10-25 14:58:06 +08:00
ab5f323159 暂时退回 targetSdk 26, 设置为 27 会出现 Only fullscreen opaque activities can request orientation 错误
https://stackoverflow.com/questions/48072438/java-lang-illegalstateexception-only-fullscreen-opaque-activities-can-request-o
2018-10-24 18:04:16 +08:00
17aed59317 微调文章详情和答案的关注按钮样式 2018-10-24 16:49:58 +08:00
788817f485 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-24 16:44:06 +08:00
8dfe0cd068 publish Api 升为3.5, 游戏评分整理 2018-10-24 16:43:55 +08:00
2674ba9d99 微调评论列表项 UI 2018-10-24 15:51:15 +08:00
c7c74de382 完成 MTA 统计需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/366 2018-10-24 14:57:00 +08:00
60c5b9cb9d Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-24 12:01:56 +08:00
5c309142f3 更新部分社区相关接口 优化控制插件化 2018-10-24 12:01:43 +08:00
098c4f7f3c 修复详情页图片不是16:9的问题 2018-10-24 10:49:32 +08:00
ac5deca5ae Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-23 19:14:12 +08:00
82d4c1c94a 优化下载面板插件排序 2018-10-23 19:14:02 +08:00
9118119901 基本完成 MTA 统计需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/366 2018-10-23 18:33:25 +08:00
02d61989fd 修复编辑器自动替换 "+" 为 "" 的问题 2018-10-22 18:16:32 +08:00
eb826dc612 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-22 17:38:44 +08:00
d5dd930932 社区文章相关优化 2018-10-22 17:38:30 +08:00
04ebf421a1 修复编辑器自动替换 "+" 为 "" 的问题 2018-10-22 16:16:05 +08:00
93d9a2ebc1 修复编辑器自动替换 "+" 为 "" 的问题 2018-10-22 16:11:01 +08:00
b7697742c6 将一个读写存储操作移至获取存储权限后 2018-10-22 11:40:05 +08:00
a21543ff79 修复由于更新 targetSdk 造成无法接受到网络状态变更以及应用状态变更的问题
https://stackoverflow.com/questions/10888768/package-added-broadcastreceiver-doesnt-work
2018-10-22 10:59:10 +08:00
218f234a18 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-22 09:45:52 +08:00
815d895729 修复一部分 MTA 的统计问题 2018-10-22 09:45:45 +08:00
6c4bdef80d Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-19 19:27:23 +08:00
6cd801287c 光环助手V3.5 DEV(20181011-1800)测试问题汇总(前端)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/370
(完成:1.10,11,13,14,15,20,22,25,27,28,29,30,31,32,35,36,)
2018-10-19 19:16:53 +08:00
dd7b93615d 修复专题列表没有统计到曝光事件的问题 2018-10-19 17:35:30 +08:00
682b57597a Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/qa/recommends/AskRecommendsSubjectPageAdapter.java
2018-10-19 14:29:05 +08:00
2de0b6311f 光环助手V3.5数据统计需求(光环数据后台) 完成 2018-10-19 14:26:50 +08:00
d3195411bb Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-19 10:42:25 +08:00
e0527b00d5 统一跳转至回答详情以及问题详情的来源格式 (去掉括号) 2018-10-19 10:42:16 +08:00
9d27c3cac4 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescCommentsAdapter.kt
2018-10-19 10:07:20 +08:00
8e681a9639 社区问题/社区回答 去除重复统计 只保留有阅读时长的统计 2018-10-19 10:03:35 +08:00
48ade5861a 调整游戏详情介绍页面的代码结构 2018-10-19 09:42:18 +08:00
28e55fa01a Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-18 20:31:52 +08:00
64288af285 光环助手V3.5数据统计需求(光环数据后台)-- 还有部分需要再次检查确认 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/367 2018-10-18 20:31:39 +08:00
27f9f88c37 基本完成游戏详情[介绍]功能优化 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/362 2018-10-18 18:21:52 +08:00
32da86ec5c 曝光添加 Gid 2018-10-18 18:19:43 +08:00
da440cdea8 GameDetailEntity添加GameId 2018-10-18 09:34:49 +08:00
6c651cff01 修复智能推荐推荐异常问题,游戏详情动态为空时自动跳转到介绍页面 2018-10-17 17:43:14 +08:00
a153e18059 社区专题详情修改,游戏详情问答专题兼容社区文章 2018-10-17 15:19:13 +08:00
48275aff5f 光环助手V3.5-首页增加“智能推荐”专题 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/359 2018-10-17 10:26:44 +08:00
b5747cab84 消息中心增加社区文章以及游戏评论的交互 2018-10-16 17:36:27 +08:00
5d22031a32 在信息流、社区专题和个人主页中新增社区文章显示样式 2018-10-16 16:10:53 +08:00
340123aec2 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-15 18:21:57 +08:00
e1827395b5 游戏评分模块完成 2018-10-15 18:21:50 +08:00
bfb6940402 游戏详情添加视频播放功能 2018-10-15 18:03:08 +08:00
f7c096cd9d 游戏评论编辑优化 2018-10-15 09:43:50 +08:00
aa15ce42ce 游戏评分优化页面细节 2018-10-13 10:37:17 +08:00
cebdc97b83 游戏详情增加评分功能(页面完成) 2018-10-12 18:39:58 +08:00
3cfdbca8f5 增加星星库 2018-10-12 10:13:31 +08:00
0645c32a45 游戏详情重构 2018-10-11 18:27:36 +08:00
2a985eb6aa 统一部分内部多类型跳转 2018-10-11 16:09:28 +08:00
647bc29ef1 整理代码 删除无用代码 2018-10-11 10:24:25 +08:00
b9a074aceb versionCode ->33 2018-10-11 09:57:01 +08:00
8207e510dd Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-10 15:47:20 +08:00
1348a58175 光环助手V3.5优化需求汇总(20181007)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/357 2018-10-10 15:46:36 +08:00
4b5b2fd3bd 更新光环 ID 库 2018-10-10 14:53:04 +08:00
8bb852e2ff 信息流的最底部,显示一句话:到底了哦~点击回到顶部;点击即回到最顶部,并自动下拉刷新一次 2018-10-09 18:29:46 +08:00
51b3c0d789 删除“答案精选”逻辑,所有接口添加请求头“DEVICE” 2018-10-09 18:19:05 +08:00
5e7a5a4a38 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-09 17:48:23 +08:00
65a4de0e33 控制插件化是否显示(完成)https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/350#note_10980 2018-10-09 17:48:16 +08:00
b5d8e1cd2e 修复在"下载管理-游戏更新"页面更新游戏没有记录下载曝光事件的问题 2018-10-09 17:37:03 +08:00
c11aede298 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-09 16:33:01 +08:00
0db8171898 为专题大图添加曝光统计,同时修复部分路径为 null 的情况 2018-10-09 16:29:30 +08:00
a24482d9b3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-09 15:41:52 +08:00
7662fe3645 避免 kotlin 参数为空错误 2018-10-09 14:51:42 +08:00
0950fe64cc 下载面板增加跳转类型 2018-10-09 14:48:38 +08:00
b25e85ddb1 支持网页跳转至社区文章 2018-10-08 16:52:28 +08:00
deedd0d413 对接社区轮播图数据 2018-10-08 16:16:56 +08:00
07a7908486 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/357 (3,8,13) 2018-10-07 18:31:53 +08:00
1eea91a6d0 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-10-07 15:46:59 +08:00
3fbba5d164 增加我的草稿 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/342 (1,2) 2018-10-07 15:46:48 +08:00
30295699b6 基本完成隐藏社区优化功能 2018-10-06 11:55:50 +08:00
37ca59a1e5 测试通过游戏更新通知支持非插件游戏 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/351 2018-09-30 11:38:38 +08:00
6b0e854f26 补充申请安装权限 2018-09-30 10:03:12 +08:00
7ad972dd23 增加我的草稿(未完成) 2018-09-29 17:16:36 +08:00
c2168eaf02 基本完成隐藏社区机制优化 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/347 2018-09-29 16:27:14 +08:00
60625a7bff 光环助手V3.5-插件管理与插件化优化(未测试) 2018-09-29 14:18:23 +08:00
43ee952763 社区文章详情增加分享 2018-09-28 17:46:21 +08:00
8720c63f63 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-28 16:58:39 +08:00
6778142d62 社区文章增加修改功能 2018-09-28 16:58:24 +08:00
e6b6e00bf2 接上了后台的唯一 ID 接口 2018-09-28 16:22:42 +08:00
a91cee40ba 基本完成开服表优化需求 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/348 2018-09-28 10:13:42 +08:00
c03b6521d5 增加文章详情评论 2018-09-27 18:32:21 +08:00
c33ff5fa20 优化文章与草稿的交互,文章详情对接点赞收藏等数据 2018-09-27 15:31:26 +08:00
281d98edcd 优化文章编辑/增加 与草稿的交互 2018-09-26 19:21:19 +08:00
7b84e36387 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-26 16:18:04 +08:00
71a122b671 问答首页推荐增加按时间排序页面 2018-09-26 16:11:26 +08:00
f113328619 回答评论详情接入置顶字段 2018-09-26 14:46:41 +08:00
ad9d8259e6 完成本地是否非插件游戏是否有更新的判断逻辑,待接口返回测试 2018-09-26 11:40:11 +08:00
75834b7668 修复更新 targetSdk 后不能安装应用的问题 2018-09-26 11:38:10 +08:00
6ac86c9ce6 光环助手V3.5-问答社区首页优化(信息流排序未完成) 2018-09-25 16:42:11 +08:00
8e3b5ae664 社区文章增加收藏功能(我的收藏已添加社区文章) 2018-09-25 11:40:03 +08:00
f22d8b5a47 新增文章详情 2018-09-21 18:30:09 +08:00
2260a72c1d Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-21 15:38:36 +08:00
4ead5238bc 新增 我的文章,撰写文章,文章草稿 2018-09-21 15:35:27 +08:00
851f6f1940 取消对查看对话页面对输入框的手动高度调节 2018-09-20 17:46:42 +08:00
63f69a6bd5 初步完成的唯一标识的本地逻辑 2018-09-20 16:51:41 +08:00
01800715f8 把'帐号在其它设备登录'独立到新的统计事件中 2018-09-18 18:24:39 +08:00
157b1b8d8b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-18 17:26:52 +08:00
ffcd191135 RichEditor 兼容文章详情(交互与答案详情一致) 2018-09-18 17:26:34 +08:00
769097544e UI 优化 3、4、5、6 https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/342 2018-09-18 16:16:52 +08:00
adc93021e7 光环助手V3.5优化需求汇总(20180907) (1,2) 2018-09-17 17:12:10 +08:00
a3f5b5c2c0 合并 2018-09-17 17:11:02 +08:00
c08a312111 更新 Loghub Jar 包 2018-09-17 15:19:39 +08:00
3c71d9ae93 更新 Loghub Jar 包 2018-09-17 15:17:26 +08:00
fe8205adae init 2018-09-14 19:10:10 +08:00
75c332ade1 光环助手V3.5-文章详情优化 2018-09-14 18:22:43 +08:00
e0202ccda5 完成回答详情评论列表只有输入框跟随软键盘升降的需求 http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/340 2018-09-14 18:05:08 +08:00
275da32584 修复同包名关注问题 2018-09-14 11:56:59 +08:00
2f6f508a56 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-14 11:10:41 +08:00
9b7e8841c4 光环助手V3.5-下载功能优化汇总 2018-09-14 11:10:22 +08:00
48653665b3 完成 UI 调整 http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/340 2018-09-14 10:41:33 +08:00
5e1a68de63 UI 微调 http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/340 2018-09-13 16:54:02 +08:00
caa9dd4db4 UI 调整,部分显示细节需要等待接口返回 http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/338 2018-09-13 10:25:04 +08:00
cb891bc063 Merge branch 'update_targetSDK' into 'dev'
Update targetSdk and fix MTA bugs.

See merge request !1
2018-09-12 14:48:52 +08:00
2ee3adef14 1.消息中心新增未读机制
2.版本升级到3.5
3.社区搜索历史完成
2018-09-11 16:35:57 +08:00
53618e0117 1.社区搜索,增加搜索历史
2.反馈30分钟内提交过内容完全相同的反馈,出现弹窗提醒
3.多种跳转类型的地方,增加低版本兼容
2018-09-10 17:49:50 +08:00
7c6a2e9767 又修复了一系列 MTA 统计问题 2018-09-08 16:16:27 +08:00
c44aa52f5f 还是修复 MTA 统计的一些问题 2018-09-08 10:20:55 +08:00
7f6efad8c8 还是修复 MTA 统计的一些问题 2018-09-08 10:11:02 +08:00
f9d82d163f 修复 MTA 统计的一些问题 2018-09-08 09:51:10 +08:00
42d0f3cf74 更改 targetSDK 至27和更新 MTA 库 2018-09-07 18:07:17 +08:00
739 changed files with 29735 additions and 14054 deletions

3
.gitignore vendored
View File

@ -7,4 +7,5 @@ local.properties
captures/
build/
release-app/
scripts/apk-channel/
scripts/apk-channel/
app/src/test/java/com/gh/gamecenter

View File

@ -1,4 +1,10 @@
### Ver 3.1
# 版本升级备忘
### Ver 2.5
* 此处写本次更新所做的业务和代码修改
### Ver 2.6
* xx
### Ver 3.0
* 升级账号系统(登录流程/用户信息相关/用户账号相关操作(评论,礼包...))
@ -10,8 +16,18 @@
* 游戏下载平台面板修改(加快弹出速度,不再读取本地平台图片)
* 接入bugly(tinker)
### Ver 2.6
* xx
### VER 3.1
### VER 3.2
### VER 3.3
### VER 3.4
### VER 3.5
### Ver 2.5
* 此处写本次更新所做的业务和代码修改
### Ver 3.6
* 首页游戏增加预览骨架,游戏ITEM样式微调和开服标签
* 首页问答增加关注页面
* 重构游戏更新管理(游戏更新/插件化/已安装的游戏),具体细节参考PackageRepository & PackageViewModel
* 重构APP更新管理(已VersionVode为更新基准,小版本更新改为光环后台控制)
- 删除TINKER_VERISON_NAME
- tinker打包方式变更(以小版本作为Base包,防止与数据后台小版本更新发生冲突)
* 社区增加版主功能(版主可以对存在的相关内容进行修改/隐藏操作,内容包括问题/回答/回答评论)
* 社区互动引导优化(问答推荐增加`推荐关注`,回答详情增加一些交互动效)

View File

@ -63,4 +63,7 @@
- ~~把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题~~
- ~~rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) 解决方法->com.gh.gamecenter.retrofit.Response~~
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
- 搞清楚 GameManager 的用途,看能不能去掉
- 重构一下 MainActivity

View File

@ -68,7 +68,6 @@ android {
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
buildConfigField "String", "MTA_APPKEY", "\"${MTA_APPKEY}\""
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
buildConfigField "String", "PATCH_VERSION_NAME", "\"${PATCH_VERSION_NAME}\""
}
@ -92,7 +91,7 @@ android {
signingConfig signingConfigs.debug
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E1\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E2\""
}
release {
debuggable false
@ -102,7 +101,7 @@ android {
signingConfig signingConfigs.release
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E1\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E2\""
}
}
@ -178,9 +177,17 @@ rebuildChannel {
// releaseOutputDir = Release渠道包输出目录
}
repositories {
flatDir {
dirs 'libs/aars'
}
}
dependencies {
implementation fileTree(include: '*.jar', dir: 'libs')
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
testImplementation 'junit:junit:4.12'
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
debugImplementation "com.facebook.stetho:stetho:${stetho}"
@ -212,12 +219,11 @@ dependencies {
implementation "com.j256.ormlite:ormlite-core:${ormlite}"
implementation "com.jakewharton:butterknife:${butterKnife}"
annotationProcessor "com.jakewharton:butterknife-compiler:${butterKnife}"
kapt "com.jakewharton:butterknife-compiler:${butterKnife}"
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
implementation "org.greenrobot:eventbus:${eventbus}"
annotationProcessor "org.greenrobot:eventbus-annotation-processor:${eventbusApt}"
kapt "org.greenrobot:eventbus-annotation-processor:${eventbusApt}"
implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
@ -254,15 +260,27 @@ dependencies {
implementation "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}"
implementation "net.cachapa.expandablelayout:expandablelayout:${expandableLayout}"
// 用于比较 versionName 是大于小于或等于
implementation "com.g00fy2:versioncompare:${versioncompare}"
implementation "top.zibin:Luban:${luban}"
// for video streaming
implementation "cn.jzvd:jiaozivideoplayer:${jiaoziVideoView}"
implementation "com.danikula:videocache:${videoCache}"
implementation "com.llew.huawei:verifier:1.0.6"
implementation 'com.ethanhua:skeleton:1.1.1'
implementation 'io.supercharge:shimmerlayout:2.1.0'
implementation project(':libraries:gid')
implementation project(':libraries:LGLibrary')
implementation project(':libraries:MTA')
implementation project(':libraries:QQShare')
implementation project(':libraries:TalkingData')
implementation project(':libraries:UmengPush')
implementation project(':libraries:WechatShare')
implementation project(':libraries:iosched')
implementation project(':libraries:LogHub')
implementation project(':libraries:im')
}

Binary file not shown.

View File

@ -197,4 +197,29 @@
-keep @android.support.annotation.Keep class *
-keepclassmembers class ** {
@android.support.annotation.Keep *;
}
}
-keep class com.gh.loghub.** { *; }
### greenDAO 3
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-keep class org.greenrobot.greendao.** { *; }
# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
# If you do not use RxJava:
-dontwarn rx.**
-dontwarn org.greenrobot.greendao.rx.**
-dontwarn org.greenrobot.greendao.**
### fastJson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
-keepattributes Signature
-keepattributes Annotation
### 广点通
-dontwarn com.qq.gdt.action.**
-keep class com.qq.gdt.action.** {*;}

View File

@ -47,6 +47,7 @@
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name = "android.permission.READ_LOGS" />
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name = "android.permission.REQUEST_INSTALL_PACKAGES" />
<supports-screens
android:anyDensity = "true"
@ -69,7 +70,6 @@
<activity
android:name = "com.gh.gamecenter.SplashScreenActivity"
android:configChanges = "keyboardHidden|orientation|screenSize"
android:noHistory = "true"
android:screenOrientation = "portrait"
android:theme = "@style/AppGuideTheme" >
<intent-filter >
@ -107,10 +107,7 @@
android:name = "com.gh.gamecenter.ConcernActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.subject.refactor.SubjectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.PluginActivity"
android:name = "com.gh.gamecenter.subject.SubjectActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.NewsSearchActivity"
@ -176,6 +173,7 @@
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.GameDetailActivity"
android:configChanges = "orientation|screenSize|keyboardHidden"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.SuggestSelectActivity"
@ -328,7 +326,7 @@
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.personalhome.fans.FollowersActivity"
android:name = "com.gh.gamecenter.personalhome.followers.FollowersActivity"
android:screenOrientation = "portrait" />
<activity
@ -343,6 +341,44 @@
android:name = "com.gh.gamecenter.personalhome.question.PersonalQuestionActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.article.edit.ArticleEditActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.article.MyArticleActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.article.draft.ArticleDraftActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.article.detail.ArticleDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.draft.CommunityDraftWrapperActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity"
android:windowSoftInputMode = "stateVisible"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.questions.edit.manager.HistoryDetailActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.questions.edit.manager.HistoryActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.comment.CommentActivity"
android:screenOrientation = "portrait"
android:theme = "@style/Theme.Transparent"
android:windowSoftInputMode = "adjustNothing" />
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
<activity
@ -362,19 +398,15 @@
</intent-filter >
</activity >
<activity
android:name = ".CommonActivity"
android:screenOrientation = "portrait" />
<receiver android:name = "com.gh.gamecenter.receiver.InstallAndUninstallReceiver" >
<intent-filter >
<action android:name = "android.intent.action.PACKAGE_ADDED" />
<action android:name = "android.intent.action.PACKAGE_REMOVED" />
<action android:name = "android.intent.action.PACKAGE_REPLACED" />
<data android:scheme = "package" />
</intent-filter >
</receiver >
<provider
android:name = "android.support.v4.content.FileProvider"
android:authorities = "${applicationId}"
android:exported = "false"
android:grantUriPermissions = "true" >
<meta-data
android:name = "android.support.FILE_PROVIDER_PATHS"
android:resource = "@xml/provider_paths" />
</provider >
<receiver
android:name = "com.gh.gamecenter.receiver.DownloadReceiver"
@ -390,11 +422,6 @@
<action android:name = "com.gh.gamecenter.INSTALL" />
</intent-filter >
</receiver >
<receiver android:name = "com.gh.gamecenter.receiver.NetworkStateReceiver" >
<intent-filter >
<action android:name = "android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter >
</receiver >
<receiver
android:name = "com.gh.gamecenter.receiver.ActivitySkipReceiver"
@ -411,30 +438,30 @@
</receiver >
<!--魅族push应用定义消息receiver声明 -->
<receiver android:name="com.gh.gamecenter.receiver.MeizuPushReceiver">
<intent-filter>
<receiver android:name = "com.gh.gamecenter.receiver.MeizuPushReceiver" >
<intent-filter >
<!-- 接收push消息 -->
<action android:name="com.meizu.flyme.push.intent.MESSAGE" />
<action android:name = "com.meizu.flyme.push.intent.MESSAGE" />
<!-- 接收register消息 -->
<action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
<action android:name = "com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
<!-- 接收unregister消息-->
<action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />
<action android:name = "com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />
<!-- 兼容低版本Flyme3推送服务配置 -->
<action android:name="com.meizu.c2dm.intent.REGISTRATION" />
<action android:name="com.meizu.c2dm.intent.RECEIVE" />
<action android:name = "com.meizu.c2dm.intent.REGISTRATION" />
<action android:name = "com.meizu.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}"/>
</intent-filter>
</receiver>
<category android:name = "${applicationId}" />
</intent-filter >
</receiver >
<receiver
android:name="com.gh.common.im.ImReceiver"
android:enabled="true">
<intent-filter android:priority="2147483647">
<action android:name="com.gh.im"/>
<action android:name="action_finish"/>
</intent-filter>
</receiver>
android:name = "com.gh.common.im.ImReceiver"
android:enabled = "true" >
<intent-filter android:priority = "2147483647" >
<action android:name = "com.gh.im" />
<action android:name = "action_finish" />
</intent-filter >
</receiver >
<service android:name = "com.gh.base.GHUmengNotificationService" />

View File

@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="user-scalable=no">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="normalize.css">
<link rel="stylesheet" type="text/css" href="style.css">

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -28,7 +28,7 @@ document.addEventListener("selectionchange", function() { RE.backuprange(); });
// Initializations
RE.callback = function() {
window.location.href = "re-callback://" + encodeURI(RE.getHtml());
window.location.href = "re-callback://" + encodeURIComponent(RE.getHtml());
}
RE.setHtml = function(contents) {
@ -226,6 +226,15 @@ RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
bigImg.style.cssText = "max-width: 20%; margin:15px 0 0 0; height: auto;"
img.parentNode.insertBefore(bigImg, img.parentNode.childNodes[0]);
i++;
if(img.parentNode != null) {
img.parentNode.style.cssText += "text-align: left;"
}
if(img.parentNode != null && img.parentNode.parentNode != null) {
img.parentNode.parentNode.style.cssText += "text-align: left;"
}
}
}
}

View File

@ -7,6 +7,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.Window;
import com.gh.common.util.DataUtils;
@ -164,7 +165,8 @@ public abstract class BaseActivity extends BaseToolBarActivity implements EasyPe
, StringUtils.buildString("", manufacturer, " - ", model, "")
, "知道了", "重新登录"
, null
, () -> startActivity(LoginActivity.getIntent(BaseActivity.this))
, () -> startActivity(LoginActivity.getIntent(BaseActivity.this,
"你的账号已在另外一台设备登录多设备-重新登录"))
);
mBaseHandler.postDelayed(() -> mIsExistLogoutDialog = false, 5000);
} catch (JSONException e) {
@ -208,4 +210,16 @@ public abstract class BaseActivity extends BaseToolBarActivity implements EasyPe
public void onPermissionsGranted(int requestCode, List<String> perms) {
}
public static String mergeEntranceAndPath(String entrance, String path) {
if (TextUtils.isEmpty(entrance) && TextUtils.isEmpty(path)) return "";
if (TextUtils.isEmpty(entrance) && !TextUtils.isEmpty(path)) {
return StringUtils.buildString("(", path, ")");
}
if (!TextUtils.isEmpty(entrance) && TextUtils.isEmpty(path)) {
return entrance;
}
return StringUtils.buildString(entrance, "+(", path, ")");
}
}

View File

@ -0,0 +1,112 @@
package com.gh.base;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.View;
import com.gh.base.adapter.FragmentAdapter;
import com.gh.common.view.TabIndicatorView;
import com.gh.gamecenter.R;
import com.lightgame.view.NoScrollableViewPager;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
/**
* Created by khy on 15/03/18.
*/
public abstract class BaseActivity_TabLayout extends BaseActivity implements ViewPager.OnPageChangeListener {
public static final String PAGE_INDEX = "PAGE_INDEX";
@BindView(R.id.activity_tab_layout)
protected TabLayout mTabLayout;
@BindView(R.id.activity_view_pager)
protected NoScrollableViewPager mViewPager;
@BindView(R.id.activity_tab_indicator)
protected TabIndicatorView mTabIndicatorView;
protected List<Fragment> mFragmentsList;
protected List<String> mTabTitleList;
protected int mCheckedIndex = 0;
protected abstract void initFragmentList(List<Fragment> fragments);
protected abstract void initTabTitleList(List<String> tabTitleList);
protected int provideIndicatorWidth() {
return 65;
}
protected View provideTabView(int position, String tabTitle) {
return null;
}
@Override
protected int getLayoutId() {
return R.layout.activity_tablayout_viewpager;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent() != null) mCheckedIndex = getIntent().getIntExtra(PAGE_INDEX, 0);
mFragmentsList = new ArrayList<>();
initFragmentList(mFragmentsList);
mTabTitleList = new ArrayList<>();
initTabTitleList(mTabTitleList);
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
mViewPager.addOnPageChangeListener(this);
mViewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), mFragmentsList, mTabTitleList));
mViewPager.setCurrentItem(mCheckedIndex);
mTabLayout.setupWithViewPager(mViewPager);
mTabIndicatorView.setupWithTabLayout(mTabLayout);
mTabIndicatorView.setupWithViewPager(mViewPager);
mTabIndicatorView.setIndicatorWidth(provideIndicatorWidth());
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
TabLayout.Tab tab = mTabLayout.getTabAt(i);
if (tab == null) continue;
View tabView = provideTabView(i, tab.getText() != null ? tab.getText().toString() : "");
if (tabView == null) continue;
tab.setCustomView(tabView);
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
}

View File

@ -7,7 +7,7 @@ import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.GameDetailActivity;
import com.gh.gamecenter.NewsDetailActivity;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.subject.refactor.SubjectActivity;
import com.gh.gamecenter.subject.SubjectActivity;
import com.umeng.message.UmengNotificationClickHandler;
import com.umeng.message.entity.UMessage;

View File

@ -23,15 +23,25 @@ import com.gh.gamecenter.entity.PushEntity
import com.gh.gamecenter.entity.PushMessageEntity
import com.gh.gamecenter.entity.PushMessageUnreadEntity
import com.gh.gamecenter.entity.PushNotificationEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.message.MessageUnreadRepository
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
import com.gh.gamecenter.receiver.UmengMessageReceiver
import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_CLICK
import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_REMOVE
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.Gson
import com.halo.assistant.HaloApp
import com.umeng.message.UmengMessageService
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.android.agoo.common.AgooConstants
import org.json.JSONObject
import retrofit2.HttpException
import java.util.*
class GHUmengNotificationService : UmengMessageService() {
@ -157,7 +167,25 @@ class GHUmengNotificationService : UmengMessageService() {
EntranceUtils.jumpActivity(context, bundle)
DataUtils.onMtaEvent(context, "消息弹窗",
type, "")
type, "Does not contains any parameter.")
// 标记已读
val jsonObject = JSONObject()
jsonObject.put("type", type)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(application).api.postMessageRead(UserManager.getInstance().userId, data?.id, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
MessageUnreadRepository.loadMessageUnreadData()
}
override fun onFailure(e: HttpException?) {
e?.printStackTrace()
}
})
Notifier.hide()
})

View File

@ -43,6 +43,8 @@ import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
public abstract class BaseFragment<T> extends Fragment implements OnRequestCallBackListener<T>,
View.OnClickListener, OnListClickListener, OnTitleClickListener {
public static final int RESULT_REFRESH = 9528;
protected View mCachedView;
protected boolean isEverPause;
@ -130,10 +132,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
initView(mCachedView);
}
//TODO 尴尬,必须的有subscribe才能register
// 必须的有subscribe才能register
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onDummyEvent(EBMiPush push) {
//
}
@Nullable

View File

@ -55,7 +55,7 @@ public abstract class BaseFragment_TabLayout extends NormalFragment implements V
@Override
protected int getLayoutId() {
return R.layout.fragment_taglyout_viewpager;
return R.layout.fragment_tablayout_viewpager;
}
@Override

View File

@ -17,5 +17,9 @@ object AppExecutor {
override fun execute(command: Runnable) {
mainThreadHandler.post(command)
}
fun executeWithDelay(command: Runnable, delay: Long) {
mainThreadHandler.postDelayed(command, delay)
}
}
}

View File

@ -1,20 +1,63 @@
package com.gh.common
import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import com.halo.assistant.HaloApp
import java.util.concurrent.Executors
/**
* 统计用户在当前 Fragment 的停留时间,在 onViewDestroy 或 onDestroy 里获取 elapsedTime 即可,单位为秒
*/
class TimeElapsedHelper(var fragment: Fragment) {
class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
constructor(fragment: Fragment) : this(fragment, null)
constructor(activity: Activity) : this(null, activity)
private var isWorking = false
var elapsedTime: Int = 0
var timeout: Int = 0
var timeoutCallback: TimeoutCallback? = null
init {
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(a: Activity?) {
}
override fun onActivitySaveInstanceState(a: Activity?, outState: Bundle?) {
}
override fun onActivityStopped(a: Activity?) {
}
override fun onActivityCreated(a: Activity?, savedInstanceState: Bundle?) {
}
override fun onActivityPaused(a: Activity?) {
if (activity == a) {
pauseCounting()
}
}
override fun onActivityResumed(a: Activity?) {
if (activity == a) {
resumeCounting()
}
}
override fun onActivityDestroyed(a: Activity?) {
if (activity == a) {
HaloApp.getInstance().application.unregisterActivityLifecycleCallbacks(this)
}
}
})
fragment?.fragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentResumed(fm: FragmentManager?, f: Fragment?) {
if (f === fragment) {
@ -42,6 +85,13 @@ class TimeElapsedHelper(var fragment: Fragment) {
while (isWorking) {
try {
elapsedTime++
if (timeout != 0 && timeout == elapsedTime) {
timeoutCallback?.run {
AppExecutor.uiExecutor.execute {
onTimeout()
}
}
}
Thread.sleep(1000)
} catch (e: Exception) {
e.printStackTrace()
@ -58,4 +108,8 @@ class TimeElapsedHelper(var fragment: Fragment) {
object TimeElapsedThreadHolder {
val threadService = Executors.newSingleThreadExecutor()
}
interface TimeoutCallback {
fun onTimeout()
}

View File

@ -4,6 +4,7 @@ package com.gh.common.constant;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.gh.common.util.GsonUtils;
@ -42,9 +43,8 @@ public class Config {
public static final String UMENG_APPKEY = BuildConfig.UMENG_APPKEY;
public static final String UMENG_MESSAGE_SECRET = BuildConfig.UMENG_MESSAGE_SECRET;
public static final String BUGLY_APPID = BuildConfig.BUGLY_APPID;
public static final String PATCH_VERSION_NAME = BuildConfig.PATCH_VERSION_NAME; // 补丁包版本 对应关于->版本号
// http://www.ghzs666.com/article/${articleId}.html
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // TODO ghzs/ghzs666 统一
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
public static final String PATCHES = "patches";
private static String SETTINGS_KEY = "settingsKey";
@ -59,7 +59,7 @@ public class Config {
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if ("all".equals(entity.getGame())) {
if (entity.isPluginfy() && "normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
if (entity.getPluginfy() && "normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
return true;
}
}
@ -109,13 +109,13 @@ public class Config {
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if (gameId.equals(entity.getGame())) {
if (entity.isPluginfy() && filterTime(entity.getTime())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
return true;
} else {
return false;
}
} else if ("all".equals(entity.getGame())) {
if (entity.isPluginfy() && filterTime(entity.getTime())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
return true;
}
}
@ -130,7 +130,7 @@ public class Config {
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if ("all".equals(entity.getGame())) {
if (entity.isPluginfy() && filterTime(entity.getTime())) {
if (entity.getPluginfy() && filterTime(entity.getTime())) {
return true;
}
}
@ -158,6 +158,7 @@ public class Config {
mSettingsEntity = settingsEntity;
}
@Nullable
public static SettingsEntity getSettings() {
if (mSettingsEntity == null) {
try {

View File

@ -15,6 +15,10 @@ public class Constants {
public static final String USER_TOKEN_KEY = "userTokenKey";
public static final String USER_INFO_KEY = "userInfoKey";
public static final String DEVICE_KEY = "deviceKey";
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
// 最近显示的弹窗信息
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
public static final String SP_LAST_OPENING_TIME = "last_opening_dialog_time";

View File

@ -26,6 +26,7 @@ public class ItemViewType {
public static final int GAME_PLUGIN = 18; // 游戏插件模块
public static final int ASK_REFRESH = 19; // 问答精选 刷新
public static final int ITEM_EMPTY = 20;
public static final int ASK_CONCERN = 21; // 问答精选 关注
/**
* 普通列表

View File

@ -24,10 +24,10 @@ import com.gh.common.util.GameUtils;
import com.gh.common.util.GameViewUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.KaiFuUtils;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.NewsUtils;
import com.gh.common.util.NumberUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.StringUtils;
import com.gh.common.view.DownloadDialog;
import com.gh.common.view.DownloadProgressBar;
@ -40,15 +40,15 @@ import com.gh.gamecenter.databinding.KaifuDetailItemRowBinding;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.KaiFuCalendarEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
@ -317,15 +317,13 @@ public class BindingAdapters {
progressBar.setText("暂无下载");
progressBar.setDownloadType(DownloadProgressBar.DownloadType.NONE);
} else {
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity);
String status = GameUtils.getDownloadBtnText(progressBar.getContext(), gameEntity, PluginLocation.only_game);
switch (status) {
case "插件化":
progressBar.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN);
break;
case "打开":
if (gameEntity.getApk().size() == 1) {
status = "启动";
}
case "启动":
progressBar.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
break;
default:
@ -347,7 +345,7 @@ public class BindingAdapters {
case neterror:
case waiting:
progressBar.setText(R.string.downloading);
if (downloadEntity.isPluggable() && PackageManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
if (downloadEntity.isPluggable() && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
progressBar.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN);
} else {
progressBar.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
@ -356,7 +354,7 @@ public class BindingAdapters {
case done:
progressBar.setText(R.string.install);
if (downloadEntity.isPluggable()
&& PackageManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
progressBar.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
} else {
progressBar.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
@ -387,13 +385,8 @@ public class BindingAdapters {
case NORMAL:
case PLUGIN:
if (gameEntity.getApk().size() == 1) {
if (NetworkUtils.isWifiConnected(v.getContext())) {
download(progressBar, gameEntity, traceEvent);
} else {
DialogUtils.showDownloadDialog(v.getContext(), () -> {
download(progressBar, gameEntity, traceEvent);
});
}
DialogUtils.checkDownload(v.getContext(), gameEntity.getApk().get(0).getSize(),
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe));
} else {
DownloadDialog.getInstance(v.getContext()).showPopupWindow(v, gameEntity,
"(我的光环:我的游戏)", "我的光环-我的游戏:" + gameEntity.getName(), traceEvent);
@ -416,13 +409,14 @@ public class BindingAdapters {
PackageUtils.launchSetup(v.getContext(), downloadEntity.getPath());
}
}
break;
}
});
}
// 开始下载
private static void download(DownloadProgressBar progressBar, GameEntity
gameEntity, ExposureEvent traceEvent) {
gameEntity, ExposureEvent traceEvent, boolean isSubscribe) {
String str = progressBar.getText();
String method;
if (str.contains("更新")) {
@ -444,6 +438,7 @@ public class BindingAdapters {
gameEntity,
method,
StringUtils.buildString("(我的光环:我的游戏)"), "我的光环-我的游戏:" + gameEntity.getName(),
isSubscribe,
downloadExposureEvent);
progressBar.setProgress(0);
@ -485,4 +480,16 @@ public class BindingAdapters {
layout.setRefreshing(false);
}
}
@BindingAdapter({"setGameName", "isShowPlatform"})
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform) {
if (isShowPlatform && game.getApk().size() > 0) {
view.setText(String.format("%s - %s", game.getName(),
PlatformUtils.getInstance(view.getContext()).getPlatformName(
game.getApk().get(0).getPlatform())));
} else {
view.setText(game.getName());
}
}
}

View File

@ -2,6 +2,7 @@ package com.gh.common.exposure
import android.arch.persistence.room.TypeConverter
import com.gh.common.exposure.meta.Meta
import com.gh.common.util.GsonUtils
import com.google.gson.Gson
import java.util.*
import kotlin.collections.ArrayList
@ -10,27 +11,27 @@ class ExposureConverters {
@TypeConverter
fun convertPayload2String(any: ExposureEntity): String {
return Gson().toJson(any)
return GsonUtils.getInstance().mGson.toJson(any)
}
@TypeConverter
fun convertString2Payload(string: String): ExposureEntity {
return Gson().fromJson(string, ExposureEntity::class.java)
return GsonUtils.getInstance().mGson.fromJson(string, ExposureEntity::class.java)
}
@TypeConverter
fun convertSource2String(sourceList: List<ExposureSource>): String {
return Gson().toJson(sourceList)
return GsonUtils.getInstance().mGson.toJson(sourceList)
}
@TypeConverter
fun convertString2Source(sourceList: String): List<ExposureSource> {
return ArrayList(Arrays.asList(Gson().fromJson(sourceList, Array<ExposureSource>::class.java))) as List<ExposureSource>
return ArrayList(Arrays.asList(GsonUtils.getInstance().mGson.fromJson(sourceList, Array<ExposureSource>::class.java))) as List<ExposureSource>
}
@TypeConverter
fun convertETrace2String(sourceList: List<ExposureEvent>?): String {
return Gson().toJson(sourceList)
return GsonUtils.getInstance().mGson.toJson(sourceList)
}
@TypeConverter
@ -50,12 +51,12 @@ class ExposureConverters {
@TypeConverter
fun convertMeta2String(any: Meta): String {
return Gson().toJson(any)
return GsonUtils.getInstance().mGson.toJson(any)
}
@TypeConverter
fun convertString2Meta(string: String): Meta {
return Gson().fromJson(string, Meta::class.java)
return GsonUtils.getInstance().mGson.fromJson(string, Meta::class.java)
}
}

View File

@ -4,7 +4,6 @@ import android.arch.persistence.room.*
@Dao
interface ExposureEventDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertMany(eventList: List<ExposureEvent>)

View File

@ -8,9 +8,6 @@ import io.reactivex.functions.Consumer
/**
* Exposure Event Listener for RecyclerView
*
* TODO 1. Pull down refresh change in first page without scroll down action
* TODO 2. Item change not triggered by user scroll action (vm data change etc.)
*/
class ExposureListener(var fragment: Fragment, var exposable: IExposable) : RecyclerView.OnScrollListener() {
@ -48,8 +45,7 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
}
/**
* Check disappearMap items together with according data in displayMap,
* log any items displayed long enough to be called a EXPOSURE
* Just commit the exposureEvent that is stored in listItem.
*/
private fun commitExposure(visibleState: ExposureThrottleBus.VisibleState) {
@ -59,8 +55,8 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
try {
exposable.getEventByPosition(pos)?.let { eventList.add(it) }
exposable.getEventListByPosition(pos)?.let { eventList.addAll(it) }
} catch (e: Exception) {
e.printStackTrace()
} catch (ignore: Exception) {
// Just ignore the error.
}
}

View File

@ -1,151 +1,130 @@
package com.gh.common.exposure
import android.app.Application
import com.aliyun.sls.android.sdk.LogException
import com.aliyun.sls.android.sdk.model.LogGroup
import com.gh.common.exposure.aliyun.LGLOG
import com.gh.common.exposure.aliyun.LGLOGClient
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.exposure.time.TimeUtil
import com.gh.gamecenter.BuildConfig
import com.gh.loghub.LgLOG
import com.gh.loghub.LoghubHelper
import com.google.gson.Gson
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.util.concurrent.Executors
import kotlin.concurrent.fixedRateTimer
/**
* ExposureManager tool to commit logs to aliyun loghub
* TODO handle logs that failed to be committed multiple times
* A handful tool for committing logs to aliyun loghub.
*
* 如何简单地统计列表中每个 item 的曝光事件?
*
* 1. Adapter 实现 IExposable 接口,在 BindView 阶段更新 ExposureEventExposureEvent 供 getEventByPosition(pos) 方法获取用
* 2. 构建一个 ExposureListener 并作为入参添加至 recyclerview 的 Scroll 回调中
* 3. 没了
*/
object ExposureManager {
private var TAG: String = ExposureManager::class.java.simpleName
private const val ACCESS_KEY_ID = "LTAIV3i0sNc4TPK1"
private const val ACCESS_KEY_SECRET = "8dKtTPeE5WYA6ZCeuIBcIVp7eB0ir4"
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 var LOG_STORE = BuildConfig.EXPOSURE_REPO
private val loghubHelper = LoghubHelper.getInstance()
private lateinit var client: LGLOGClient
private lateinit var db: ExposureEventDao
private val storeSet = hashSetOf<ExposureEvent>()
private val storeOpThread = Executors.newSingleThreadExecutor()
private val gson = Gson()
private val exposureCache = FixedSizeLinkedHashSet<String>(20)
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
private val exposureCache = FixedSizeLinkedHashSet<String>(100)
private val exposureSet = hashSetOf<ExposureEvent>()
private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
private val exposureExecutor = Executors.newSingleThreadExecutor()
/**
* Must be called early to init object then real use (for example in Application)
*/
fun init(application: Application) {
@JvmStatic
fun init() {
TimeUtil.init()
client = LGLOGClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, PROJECT)
db = ExposureDatabase.buildDatabase(application).logHubEventDao()
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
storeOpThread.execute {
val eventList = db.getAll()
storeSet.addAll(eventList)
exposureExecutor.execute {
val eventList = exposureDao.getAll()
exposureSet.addAll(eventList)
}
fixedRateTimer(name = "ExposureManager-Store-Checker", initialDelay = 500, period = STORE_FORCE_UPLOAD_PERIOD) {
checkAndUploadFromDatabase(true)
}
MetaUtil.init(application)
TimeUtil.init()
}
/**
* Log an Event
*/
fun log(event: ExposureEvent, uploadImmediately: Boolean = false) {
when (uploadImmediately) {
false -> store(event)
true -> upload(event)
commitSavedExposureEvent(true)
}
}
/**
* Log Many Events
* Log a single exposure event.
*/
fun log(eventList: List<ExposureEvent>, uploadImmediately: Boolean = false) {
when (uploadImmediately) {
false -> store(eventList)
true -> upload(eventList)
}
}
/**
* Store an Event to storeSet, upload when storeSet size exceeds STORE_SIZE
*/
private fun store(event: ExposureEvent) {
storeOpThread.execute {
fun log(event: ExposureEvent) {
exposureExecutor.execute {
if (!exposureCache.contains(event.id)) {
storeSet.add(event)
db.insert(event)
exposureCache.add(event.id)
// Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
try {
exposureSet.add(event)
exposureDao.insert(event)
exposureCache.add(event.id)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
Utils.log("Exposure", "遇到重复曝光事件,自动过滤 ${event.id} - ${event.payload.gameName}")
}
checkAndUploadFromDatabase()
}
}
/**
* Store Many Events to storeSet, upload when storeSet size exceeds STORE_SIZE
* Log a collection of exposure event.
*/
private fun store(eventList: List<ExposureEvent>) {
storeOpThread.execute {
fun log(eventList: List<ExposureEvent>) {
exposureExecutor.execute {
for (event in eventList) {
if (!exposureCache.contains(event.id)) {
storeSet.add(event)
db.insert(event)
exposureCache.add(event.id)
// Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
try {
exposureSet.add(event)
exposureDao.insert(event)
exposureCache.add(event.id)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
Utils.log("Exposure", "遇到重复曝光事件,自动过滤 ${event.id} - ${event.payload.gameName}")
}
}
commitSavedExposureEvent()
}
}
/**
* Upload an Event
*/
private fun upload(event: ExposureEvent) {
storeOpThread.execute {
client.PostLog(buildLogGroup(event), LOG_STORE)
private fun commitSavedExposureEvent(force: Boolean = false) {
exposureExecutor.execute {
if (exposureSet.size < STORE_SIZE && !force || exposureSet.size == 0) return@execute
val exposureList = exposureSet.toList()
// uploadLogGroup 是一个异步方法LoghubHelper 里面实现了重传功能,所以这里交给它就好了
loghubHelper.uploadLogGroup(buildLogGroup(exposureList))
Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
exposureSet.removeAll(exposureList)
exposureDao.deleteMany(exposureList)
}
}
/**
* Upload Many Events
*/
private fun upload(eventList: List<ExposureEvent>) {
storeOpThread.execute {
client.PostLog(buildLogGroup(eventList), LOG_STORE)
}
private fun eliminateMultipleBrackets(jsonWithMultipleBracket: String): String {
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
}
/**
* Upload Events From Store, and removed them
*/
private fun checkAndUploadFromDatabase(isForceUpload: Boolean = false) {
storeOpThread.execute {
if (storeSet.size < STORE_SIZE && !isForceUpload || storeSet.size == 0) return@execute
val uploaded = storeSet.toList()
try {
client.PostLog(buildLogGroup(uploaded), LOG_STORE)
} catch (exception: LogException) {
// Return to insure no logs lost because of online commit failure
return@execute
}
storeSet.removeAll(uploaded)
db.deleteMany(uploaded)
}
private fun buildLogGroup(eventList: List<ExposureEvent>): LogGroup {
val logGroup = LogGroup("sls android", "no ip")
eventList.forEach { logGroup.PutLog(buildLog(it)) }
return logGroup
}
private fun buildLog(event: ExposureEvent): LGLOG {
val log = LGLOG()
private fun buildLog(event: ExposureEvent): LgLOG {
val log = LgLOG(TimeUtil.currentTime())
log.PutContent("id", event.id)
log.PutContent("payload", gson.toJson(event.payload))
@ -158,30 +137,6 @@ object ExposureManager {
return log
}
private fun eliminateMultipleBrackets(jsonWithMultipleBracket: String): String {
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
}
private fun buildLogGroup(event: ExposureEvent): LogGroup {
val logGroup = LogGroup("sls android", "no ip")
logGroup.PutLog(buildLog(event))
return logGroup
}
private fun buildLogGroup(eventList: List<ExposureEvent>): LogGroup {
val logGroup = LogGroup("sls android", "no ip")
eventList.forEach { event ->
logGroup.PutLog(buildLog(event))
}
return logGroup
}
internal class FixedSizeLinkedHashSet<T>(var maxSize: Int) : LinkedHashSet<T>() {
override fun add(element: T): Boolean {
if (size == maxSize) {

View File

@ -1,15 +1,16 @@
package com.gh.common.exposure
import com.gh.common.util.fromObject
import com.gh.gamecenter.entity.GameEntity
import com.google.gson.Gson
import java.util.*
object ExposureUtils {
val gson = Gson()
@JvmStatic
fun logADownloadExposureEvent(entity: GameEntity, platform: String?, traceEvent: ExposureEvent?, downloadType: DownloadType): ExposureEvent {
fun logADownloadExposureEvent(entity: GameEntity,
platform: String?,
traceEvent: ExposureEvent?,
downloadType: DownloadType): ExposureEvent {
val gameEntity = entity.clone()
gameEntity.platform = platform
gameEntity.downloadType = downloadType.toString()
@ -17,21 +18,24 @@ object ExposureUtils {
source = traceEvent?.source ?: ArrayList(),
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
event = ExposureType.DOWNLOAD)
ExposureManager.log(exposureEvent, false)
ExposureManager.log(exposureEvent)
return exposureEvent
}
@JvmStatic
fun logADownloadCompleteExposureEvent(entity: GameEntity, platform: String?, trace: String?, downloadType: DownloadType) {
fun logADownloadCompleteExposureEvent(entity: GameEntity,
platform: String?,
trace: String?,
downloadType: DownloadType) {
val gameEntity = entity.clone()
gameEntity.platform = platform
gameEntity.downloadCompleteType = downloadType.toString()
val traceEvent = gson.fromJson(trace, ExposureEvent::class.java)
val traceEvent = trace?.fromObject<ExposureEvent>()
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
source = traceEvent?.source ?: ArrayList(),
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
event = ExposureType.DOWNLOAD_COMPLETE)
ExposureManager.log(exposureEvent, false)
ExposureManager.log(exposureEvent)
}
enum class DownloadType {

View File

@ -1,7 +1,11 @@
package com.gh.common.exposure
/**
* 统计曝光的列表的 adapter 需要实现这个接口
*/
interface IExposable {
fun getEventByPosition(pos: Int): ExposureEvent?
// 部分列表的 item 内嵌套了 recyclerview 这里获取这个 item 所携带的所有事件
fun getEventListByPosition(pos: Int): List<ExposureEvent>?
}

View File

@ -1,42 +0,0 @@
package com.gh.common.exposure.aliyun;
import com.aliyun.sls.android.sdk.model.Log;
import com.gh.common.exposure.time.TimeUtil;
import java.util.HashMap;
import java.util.Map;
/**
* Extend to change __time__ field in mContent to use the correct time from TimeUtil
*/
public class LGLOG extends Log {
private Map<String, Object> mContent = new HashMap<String, Object>();
public LGLOG() {
mContent.put("__time__", TimeUtil.INSTANCE.currentTime());
}
@Override
public void PutTime(int time) {
mContent.put("__time__", time);
}
@Override
public void PutContent(String key, String value) {
if (key == null || key.isEmpty()) {
return;
}
if (value == null) {
mContent.put(key, "");
} else {
mContent.put(key, value);
}
}
@Override
public Map<String, Object> GetContent() {
return mContent;
}
}

View File

@ -1,67 +0,0 @@
package com.gh.common.exposure.aliyun;
import com.aliyun.sls.android.sdk.LOGClient;
import com.aliyun.sls.android.sdk.LogException;
import com.gh.common.exposure.time.TimeUtil;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
/**
* Extend to override GetHttpHeadersFrom, so we can change "Date" header attribute using
* correct time from TimeUtil.
* And accordingly, the value of "Authorization" attribute should also be re-calculate
* since the sign became different as before.
*/
public class LGLOGClient extends LOGClient {
private String mAccessKeyID;
private String mAccessKeySecret;
private String mAccessToken;
public LGLOGClient(String endPoint, String accessKeyID, String accessKeySecret, String projectName) {
super(endPoint, accessKeyID, accessKeySecret, projectName);
this.mAccessKeyID = accessKeyID;
this.mAccessKeySecret = accessKeySecret;
this.mAccessToken = "";
}
@Override
public Map<String, String> GetHttpHeadersFrom(String logStoreName, byte[] body, byte[] bodyZipped) throws LogException {
Map<String, String> headers = super.GetHttpHeadersFrom(logStoreName, body, bodyZipped);
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // 设置时区为GMT
String str = sdf.format(new Date(TimeUtil.INSTANCE.currentTimeMillis()));
headers.put("Date", str);
StringBuilder signStringBuf = new StringBuilder("POST" + "\n").
append(headers.get("Content-MD5") + "\n").
append(headers.get("Content-Type") + "\n").
append(headers.get("Date") + "\n");
String token = mAccessToken;
if (token != null && token != "") {
headers.put("x-acs-security-token", token);
signStringBuf.append("x-acs-security-token:" + headers.get("x-acs-security-token") + "\n");
}
signStringBuf.append("x-log-apiversion:0.6.0\n").
append("x-log-bodyrawsize:" + headers.get("x-log-bodyrawsize") + "\n").
append("x-log-compresstype:deflate\n").
append("x-log-signaturemethod:hmac-sha1\n").
append("/logstores/" + logStoreName + "/shards/lb");
String signString = signStringBuf.toString();
try {
String sign = hmac_sha1(signString, mAccessKeySecret);
headers.put("Authorization", "LOG " + mAccessKeyID + ":" + sign);
} catch (Exception e) {
throw new LogException("LogClientError", "fail to get encode signature", e, "");
}
return headers;
}
}

View File

@ -15,8 +15,8 @@ data class Meta(
val android_sdk: Int? = -1,
val android_version: String? = "",
val network: String? = "",
val ip: String? = "",
val os: String? = "",
val gid: String? = "",
val channel: String? = "",
val appVersion: String? = "",
val userId: String? = "",

View File

@ -12,23 +12,32 @@ import android.telephony.TelephonyManager
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.manager.UserManager
import com.halo.assistant.HaloApp
import com.leon.channel.helper.ChannelReaderUtil
import java.io.File
object MetaUtil {
private lateinit var application: Application
private val application: Application = HaloApp.getInstance().application
private var channel = ""
private var m: Meta? = null
fun init(application: Application) {
MetaUtil.application = application
}
fun refreshMeta() {
m = Meta(getMac(), getIMEI(), getModel(), getManufacturer(), getAndroidId(), getAndroidSDK(),
getAndroidVersion(), getNetwork(), getIP(), getOS(), getChannel(), BuildConfig.VERSION_NAME, UserManager.getInstance().userId, BuildConfig.EXPOSURE_VERSION)
m = Meta(mac = getMac(),
imei = getIMEI(),
model = getModel(),
manufacturer = getManufacturer(),
android_id = getAndroidId(),
android_sdk = getAndroidSDK(),
android_version = getAndroidVersion(),
network = getNetwork(),
os = getOS(),
gid = HaloApp.getInstance().gid,
channel = getChannel(),
appVersion = BuildConfig.VERSION_NAME,
userId = UserManager.getInstance().userId,
exposureVersion = BuildConfig.EXPOSURE_VERSION)
}
fun getMeta(): Meta {
@ -140,16 +149,16 @@ object MetaUtil {
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
if (telephonyManager.simState != TelephonyManager.SIM_STATE_READY) return "unknown"
when (telephonyManager.networkType) {
// Unknown
// Unknown
TelephonyManager.NETWORK_TYPE_UNKNOWN -> "Cellular - Unknown"
// Cellular Data2G
// Cellular Data2G
TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_CDMA,
TelephonyManager.NETWORK_TYPE_IDEN, TelephonyManager.NETWORK_TYPE_1xRTT -> "Cellular - 2G"
// Cellular Data3G
// Cellular Data3G
TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSPA,
TelephonyManager.NETWORK_TYPE_HSPAP, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_EVDO_0,
TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_EVDO_B -> "Cellular - 3G"
// Cellular Data4G
// Cellular Data4G
TelephonyManager.NETWORK_TYPE_LTE -> "Cellular - 4G"
else -> "Cellular - Unknown Generation"
}
@ -160,10 +169,6 @@ object MetaUtil {
}
fun getIP(): String {
return "unknown"
}
fun getOS(): String {
return "android"
}

View File

@ -1,5 +1,7 @@
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
@ -17,11 +19,12 @@ class Corrector {
fixedRateTimer("TimeUtil-Corrector-Checker", initialDelay = 0, period = TIME_CORRECTOR_ADJUST_PERIOD) {
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
.subscribeOn(Schedulers.io())
.subscribe({
val serverTime = java.lang.Long.parseLong(it.string())
delta = serverTime * 1000 - System.currentTimeMillis()
}, Throwable::printStackTrace)
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let { delta = it * 1000 - System.currentTimeMillis() }
}
})
}
}
}

View File

@ -4,19 +4,20 @@ object TimeUtil {
private lateinit var corrector: Corrector
fun init() {
corrector = Corrector()
}
fun currentTimeMillis(): Long {
return corrector.delta + System.currentTimeMillis()
}
fun currentTime(): Int {
return ( ( corrector.delta + System.currentTimeMillis() ) / 1000 ).toInt()
}
/**
* Must be called early then real use (for example in Application)
*/
fun init() {
corrector = Corrector()
return if (::corrector.isInitialized) {
((corrector.delta + System.currentTimeMillis()) / 1000).toInt()
} else {
(System.currentTimeMillis() / 1000).toInt()
}
}
}

View File

@ -11,10 +11,12 @@ import com.gh.gamecenter.SuggestSelectActivity
import com.gh.gamecenter.manager.UserManager
import com.halo.assistant.HaloApp
import com.m7.imkfsdk.KfStartHelper
import com.m7.imkfsdk.utils.Utils
import com.moor.imkf.ChatListener
import com.moor.imkf.IMChat
import com.moor.imkf.IMChatManager
import com.moor.imkf.IMMessage
import com.moor.imkf.utils.MoorUtils
object ImManager {
@ -29,6 +31,8 @@ object ImManager {
fun attachIm() {
try {
if (UserManager.getInstance().userInfoEntity != null) {
MoorUtils.init(HaloApp.getInstance().application)
Utils.init(HaloApp.getInstance().application)
IMChatManager.getInstance().init(
HaloApp.getInstance().application,
ImReceiver.UNIQUE_BROADCAST_ACTION,

View File

@ -12,8 +12,8 @@ import android.support.v4.app.NotificationCompat
import com.gh.base.CurrentActivityHolder
import com.gh.gamecenter.R
import com.m7.imkfsdk.chat.ChatActivity
import com.m7.imkfsdk.utils.Utils
import com.moor.imkf.IMChatManager
import com.moor.imkf.utils.Utils
class ImReceiver : BroadcastReceiver() {

View File

@ -32,7 +32,7 @@ class Notifier private constructor() {
@JvmStatic
fun tagNotifierAsShowed(content: String) {
val viewedNotifierCollection = SPUtils.getString(SP_VIEWED_NOTIFIER)
if (viewedNotifierCollection.length > 1000) {
if (viewedNotifierCollection.length > 3000) {
SPUtils.setString(SP_VIEWED_NOTIFIER, content)
} else {
SPUtils.setString(SP_VIEWED_NOTIFIER, viewedNotifierCollection + content)

View File

@ -201,12 +201,16 @@ class NotifierView @JvmOverloads constructor(context: Context, attrs: AttributeS
showAnimatorSet.cancel()
hideAnimatorSet.cancel()
removeAllListeners(expandAnimator,
shrinkAnimator,
translateUpAnimator,
translateDownAnimator,
translateToLeftAnimator,
translateToRightAnimator)
try {
removeAllListeners(expandAnimator,
shrinkAnimator,
translateUpAnimator,
translateDownAnimator,
translateToLeftAnimator,
translateToRightAnimator)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun removeAllListeners(vararg ts: Animator) {
@ -227,7 +231,7 @@ class NotifierView @JvmOverloads constructor(context: Context, attrs: AttributeS
postDelayed({ shrink() }, duration)
}
fun shrink() {
private fun shrink() {
shrinkAnimator.doOnEnd { hide() }
shrinkAnimator.start()
}

View File

@ -0,0 +1,43 @@
package com.gh.common.observer
import android.content.Context
import android.database.ContentObserver
import android.media.AudioManager
import android.os.Handler
class VolumeObserver(var context: Context, handler: Handler, var callback: MuteCallback? = null)
: ContentObserver(handler) {
var previousVolume: Int = 0
init {
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
}
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC)
val delta = previousVolume - currentVolume
if (delta != 0) {
if (currentVolume == 0) {
callback?.onMute(true)
} else {
callback?.onMute(false)
}
}
if (delta > 0) {
previousVolume = currentVolume
} else if (delta < 0) {
previousVolume = currentVolume
}
}
}
interface MuteCallback {
fun onMute(isMute: Boolean)
}

View File

@ -0,0 +1,54 @@
package com.gh.common.repository
import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.RandomUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import io.reactivex.Observable
// 热门卡牌的仓库
object RemenkapaiRepository {
var remenkapaiList = arrayListOf<GameEntity>()
@JvmStatic
fun getRemenkapai(size: Int): Observable<List<GameEntity>> {
return if (remenkapaiList.isEmpty()) {
RetrofitManager.getInstance(getApplication()).api.remenkapai
.map { gameList -> filterEntityWithoutApk(gameList) }
.map { pickRandomSizeEntity(size) }
.map(ApkActiveUtils.filterMapperList)
} else {
Observable.create { emitter -> emitter.onNext(pickRandomSizeEntity(size)) }
}
}
/**
* 选择随机数量的热门卡牌
*/
private fun pickRandomSizeEntity(size: Int): List<GameEntity> {
val randomGameList = arrayListOf<GameEntity>()
val randomArray = RandomUtils.getRandomArray(size, remenkapaiList.size)
for (i in randomArray) {
randomGameList.add(remenkapaiList[i])
}
return randomGameList
}
/**
* 过滤没有 Apk 的实体
*/
private fun filterEntityWithoutApk(gameList: List<GameEntity>): List<GameEntity> {
val realGameList = arrayListOf<GameEntity>()
for (gameEntity in gameList) {
val apk = gameEntity.getApk()
if (apk.size != 0) {
realGameList.add(gameEntity)
}
}
remenkapaiList = realGameList
return remenkapaiList
}
}

View File

@ -0,0 +1,37 @@
package com.gh.common.util
import com.gh.common.constant.Config
import com.gh.gamecenter.entity.SettingsEntity
object AdHelper {
// 搜索为空/求版本/意见反馈-功能收录/发现
const val LOCATION_SEARCH_EMPTY = "search_empty"
const val LOCATION_GAME_REQUEST_VERSION = "game_request_version"
const val LOCATION_SUGGESTION_FUNCTION = "suggestion_function"
const val LOCATION_DISCOVER = "discover"
fun getAd(location: String): SettingsEntity.AD? {
val adList = Config.getSettings()?.adList ?: return null
for (ad in adList) {
if (ad.location == location) return ad
}
return null
}
fun getDiscoverAds(): List<SettingsEntity.AD> {
val adList = Config.getSettings()?.adList ?: return listOf()
val discoverAdList = arrayListOf<SettingsEntity.AD>()
for (ad in adList) {
if (ad.location == LOCATION_DISCOVER) {
discoverAdList.add(ad)
}
}
return discoverAdList
}
}

View File

@ -1,31 +1,52 @@
package com.gh.common.util;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.utils.Utils;
import java.util.List;
import io.reactivex.functions.Function;
/**
* Created by khy on 10/05/17.
*/
public class ApkActiveUtils {
// 过滤隐藏apk包
public static void filterHideApk(GameEntity gameEntity) {
if (gameEntity == null || gameEntity.getApk() == null
|| gameEntity.getApk().size() == 0) return;
List<ApkEntity> apkList = gameEntity.getApk();
for (int i = 0; i < apkList.size(); i++) {
ApkEntity apkEntity = apkList.get(i);
String packageName = apkEntity.getPackageName();
String id = gameEntity.getId();
if (!apkEntity.isActive() && !PackageManager.INSTANCE.isCanPluggable(id, packageName)) {
apkList.remove(i);
i--;
try {
if (gameEntity == null || gameEntity.getOriginalApk().size() == 0) return;
List<ApkEntity> apkList = gameEntity.getOriginalApk();
for (int i = 0; i < apkList.size(); i++) {
ApkEntity apkEntity = apkList.get(i);
String packageName = apkEntity.getPackageName();
String id = gameEntity.getId();
if (!apkEntity.isActive() && !PackagesManager.INSTANCE.isCanPluggable(id, packageName)) {
apkList.remove(i);
i--;
}
}
} catch (Exception e) {
if (BuildConfig.DEBUG) {
Utils.log("filter hide game apk throws exception:" + e.toString());
}
}
}
// 过滤隐藏apk包
public static Function<List<GameEntity>, List<GameEntity>> filterMapperList = list -> {
for (GameEntity gameEntity : list) {
ApkActiveUtils.filterHideApk(gameEntity);
}
return list;
};
// 过滤隐藏apk包
public static Function<GameEntity, GameEntity> filterMapper = list -> {
ApkActiveUtils.filterHideApk(list);
return list;
};
}

View File

@ -18,73 +18,76 @@ public class AskErrorResponseUtils {
if (e == null) return;
int code = e.code();
try {
if (code == 403) {
if (code == 403 || code == 401) {
JSONObject object = new JSONObject(e.response().errorBody().string());
int errorCode = object.getInt("code");
switch (errorCode) {
case 403001:
Utils.toast(context, "标签名称太长了");
break;
case 403002:
Utils.toast(context, "已经被邀请了");
break;
case 403003:
Utils.toast(context, "每天最多只能邀请10次");
break;
case 403004:
Utils.toast(context, "客户端提供的ID无效空/无效ID");
break;
case 403005:
Utils.toast(context, "已经回答过了(限制频率)");
break;
case 403006:
Utils.toast(context, "图片数量达到限制点");
break;
case 403007:
Utils.toast(context, "不合法的用户");
break;
case 403008:
Utils.toast(context, "已投票");
break;
case 403009:
Utils.toast(context, "已经收藏过了");
break;
case 403010:
Utils.toast(context, "无效的标签栏");
break;
case 403011:
Utils.toast(context, "标题内容过长");
break;
case 403012:
Utils.toast(context, "描述内容过长");
break;
case 403013:
Utils.toast(context, "无效的标签");
break;
case 403014:
Utils.toast(context, "标签数量太多了");
break;
case 403015:
Utils.toast(context, "已经关注过了");
break;
default:
Utils.toast(context, "网络错误");
break;
}
} else if (code == 401) {
JSONObject object = new JSONObject(e.response().errorBody().string());
int errorCode = object.getInt("code");
if (errorCode == 404001) {
Utils.toast(context, "请求的资源不存在");
}
errorResponseControl(context, object);
} else {
Utils.toast(context, "网络错误");
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
public static void errorResponseControl(Context context, JSONObject jsonObject) {
int errorCode = 0;
try {
errorCode = jsonObject.getInt("code");
switch (errorCode) {
case 403001:
Utils.toast(context, "标签名称太长了");
break;
case 403002:
Utils.toast(context, "已经被邀请了");
break;
case 403003:
Utils.toast(context, "每天最多可以邀请10次");
break;
case 403004:
Utils.toast(context, "客户端提供的ID无效空/无效ID");
break;
case 403005:
Utils.toast(context, "已经回答过了(限制频率)");
break;
case 403006:
Utils.toast(context, "图片数量达到限制点");
break;
case 403007:
Utils.toast(context, "不合法的用户");
break;
case 403008:
Utils.toast(context, "已投票");
break;
case 403009:
Utils.toast(context, "已经收藏过了");
break;
case 403010:
Utils.toast(context, "无效的标签栏");
break;
case 403011:
Utils.toast(context, "标题内容过长");
break;
case 403012:
Utils.toast(context, "描述内容过长");
break;
case 403013:
Utils.toast(context, "无效的标签");
break;
case 403014:
Utils.toast(context, "标签数量太多了");
break;
case 403015:
Utils.toast(context, "已经关注过了");
break;
case 404001:
Utils.toast(context, "请求的资源不存在");
break;
default:
Utils.toast(context, "网络错误");
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -14,15 +14,17 @@ import com.lightgame.utils.Utils;
public class CheckLoginUtils {
public static void checkLogin(final Context context, OnLoginListener listener) {
if (TextUtils.isEmpty(UserManager.getInstance().getToken())) {
Utils.toast(context, "需要登录");
LogUtils.login(context, "dialog", null);
LogUtils.login(context, "activity", null);
Intent intent = LoginActivity.getIntent(context);
public static void checkLogin(final Context context, String entrance, OnLoginListener listener) {
if (!isLogin()) {
if (listener != null) Utils.toast(context, "需要登录");
LogUtils.login("dialog", null, entrance);
LogUtils.login("activity", null, entrance);
Intent intent = LoginActivity.getIntent(context, entrance);
context.startActivity(intent);
} else {
listener.onLogin();
if (listener != null) {
listener.onLogin();
}
}
}

View File

@ -19,7 +19,7 @@ import retrofit2.HttpException
object CollectionUtils {
enum class CollectionType {
toolkit, article, answer
toolkit, article, answer, communityArticle
}
fun postCollection(context: Context, content: String, type: CollectionType, listener: OnCollectionListener) {
@ -28,6 +28,7 @@ object CollectionUtils {
CollectionType.article -> RetrofitManager.getInstance(context).getApi().postCollectionArticle(UserManager.getInstance().userId, content)
CollectionType.toolkit -> RetrofitManager.getInstance(context).getApi().postCollectionTools(UserManager.getInstance().userId, content)
CollectionType.answer -> RetrofitManager.getInstance(context).getApi().postCollectionAnswer(UserManager.getInstance().userId, content)
else -> return
}
postCollection
.subscribeOn(Schedulers.io())
@ -36,7 +37,6 @@ object CollectionUtils {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
listener.onSuccess()
if(type != CollectionType.answer)
EventBus.getDefault().post(EBCollectionChanged(content, true, type))
}
@ -66,6 +66,7 @@ object CollectionUtils {
CollectionType.article -> postCollection = RetrofitManager.getInstance(context).getApi().deletaCollectionArticle(UserManager.getInstance().userId, id)
CollectionType.toolkit -> postCollection = RetrofitManager.getInstance(context).getApi().deleteCollectionTools(UserManager.getInstance().userId, id)
CollectionType.answer -> postCollection = RetrofitManager.getInstance(context).getApi().deleteCollectionAnswer(UserManager.getInstance().userId, id)
else -> return
}
postCollection
.subscribeOn(Schedulers.io())
@ -74,7 +75,6 @@ object CollectionUtils {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
listener.onSuccess()
if(type != CollectionType.answer)
EventBus.getDefault().post(EBCollectionChanged(id, false, type))
}

View File

@ -0,0 +1,297 @@
package com.gh.common.util
import android.content.Context
import android.text.TextUtils
import com.gh.common.util.CommentUtils.copyText
import com.gh.gamecenter.CommentDetailActivity
import com.gh.gamecenter.MessageDetailActivity
import com.gh.gamecenter.adapter.OnCommentCallBackListener
import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.entity.MeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import com.tencent.bugly.beta.tinker.TinkerManager.getApplication
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONException
import org.json.JSONObject
import retrofit2.HttpException
object CommentHelper {
// TODO 合并这两个方法的共同部分
@JvmStatic
fun showCommunityArticleCommentOptions(
context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
articleId: String,
communityId: String,
listener: OnCommentCallBackListener?) {
val dialogOptions = ArrayList<String>()
if (commentEntity.me == null || !commentEntity.me?.isAnswerCommented!!) {
dialogOptions.add("回复")
}
dialogOptions.add("复制")
dialogOptions.add("举报")
if (commentEntity.parentUser != null && showConversation) {
dialogOptions.add("查看对话")
}
DialogUtils.showListDialog(context, dialogOptions, null) {
when (it) {
"回复" -> {
context.ifLogin("社区文章详情-评论-回复") {
if (listener != null) {
listener.onCommentCallback(commentEntity)
} else if (!TextUtils.isEmpty(commentEntity.id)) {
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, commentEntity.id))
} else {
Utils.toast(context, "缺少关键属性")
}
}
}
"复制" -> copyText(commentEntity.content, context)
"举报" -> context.ifLogin("社区文章详情-评论-举报") {
showReportTypeDialog(context) { reportType ->
PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType,
object : PostCommentUtils.PostCommentListener {
override fun postSuccess(response: JSONObject?) {
Utils.toast(context, "感谢您的举报")
}
override fun postFailed(error: Throwable?) {
if (error == null) {
Utils.toast(context, "举报失败,请稍后重试")
} else {
Utils.toast(context, "举报失败,${error.message}")
}
}
})
}
}
"查看对话" -> {
context.startActivity(CommentDetailActivity
.getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null))
}
}
}
}
@JvmStatic
fun showAnswerCommentOptions(
context: Context,
commentEntity: CommentEntity,
showConversation: Boolean,
answerId: String,
listener: OnCommentCallBackListener?) {
val dialogOptions = ArrayList<String>()
if (commentEntity.me == null || !commentEntity.me?.isAnswerCommented!!) {
dialogOptions.add("回复")
}
dialogOptions.add("复制")
dialogOptions.add("举报")
commentEntity.me?.let {
if (it.isModerator && (
it.moderatorPermissions.contains(MeEntity.HIDE_ANSWER_COMMENT)
|| it.moderatorPermissions.contains(MeEntity.TOP_ANSWER_COMMENT))) {
dialogOptions.add("管理")
}
}
if (commentEntity.parentUser != null && showConversation) {
dialogOptions.add("查看对话")
}
DialogUtils.showListDialog(context, dialogOptions, null) {
when (it) {
"管理" -> showControlDialog(context, answerId, commentEntity, commentEntity.me!!)
"回复" -> {
context.ifLogin("回答详情-评论-回复") {
if (listener != null) {
listener.onCommentCallback(commentEntity)
} else if (!TextUtils.isEmpty(commentEntity.id)) {
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, commentEntity.id))
} else {
Utils.toast(context, "缺少关键属性")
}
}
}
"复制" -> copyText(commentEntity.content, context)
"举报" -> context.ifLogin("回答详情-评论-举报") {
showReportTypeDialog(context) { reportType ->
PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType,
object : PostCommentUtils.PostCommentListener {
override fun postSuccess(response: JSONObject?) {
Utils.toast(context, "感谢您的举报")
}
override fun postFailed(error: Throwable?) {
if (error == null) {
Utils.toast(context, "举报失败,请稍后重试")
} else {
Utils.toast(context, "举报失败,${error.message}")
}
}
})
}
}
"查看对话" -> {
context.startActivity(CommentDetailActivity
.getAnswerCommentIntent(context, commentEntity.id, answerId, null))
}
}
}
}
private fun showControlDialog(context: Context, answerId: String, comment: CommentEntity, me: MeEntity) {
val dialogOptions = arrayListOf<String>()
val highlight = "置顶评论"
val hide = "隐藏评论"
if (me.moderatorPermissions.contains(MeEntity.TOP_ANSWER_COMMENT)) {
dialogOptions.add(highlight)
}
if (me.moderatorPermissions.contains(MeEntity.HIDE_ANSWER_COMMENT)) {
dialogOptions.add(hide)
}
val content = if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
"你的操作将提交给小编审核,确定提交吗?"
} else {
"你的操作将立即生效,确定提交吗?(你的管理权限为:高级)"
}
val disabledOptions = arrayListOf<String>()
if (comment.priority != 0) {
disabledOptions.add(highlight)
}
comment.me?.let {
if (it.isAnswerCommented) {
disabledOptions.add(highlight)
}
}
DialogUtils.showListDialog(context, dialogOptions, disabledOptions) {
when (it) {
highlight -> {
if (comment.priority != 0) {
Utils.toast(context, "评论已经置顶")
return@showListDialog
}
comment.me?.let { me ->
if (me.isAnswerCommented) {
Utils.toast(context, "不能置顶自己的评论")
return@showListDialog
}
}
DialogUtils.showAlertDialog(context, highlight, content,
"确定", "取消",
{
RetrofitManager.getInstance(context).api
.highlightAnswerComment(answerId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
Utils.toast(context, "提交成功")
} else {
Utils.toast(context, "置顶成功,请刷新列表")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.let { httpException ->
if (httpException.code() == 403) {
val string = e.response().errorBody()?.string()
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
}
}
}
}
})
}, null)
}
hide -> {
DialogUtils.showAlertDialog(context, hide, content,
"确定", "取消",
{
RetrofitManager.getInstance(context).api
.hideAnswerComment(answerId, comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
if (me.moderatorLevel == MeEntity.MODERATOR_LEVEL_PRIMARY) {
Utils.toast(context, "提交成功")
} else {
Utils.toast(context, "隐藏成功,请刷新列表")
}
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.let { httpException ->
if (httpException.code() == 403) {
val string = e.response().errorBody()?.string()
val errorJson = JSONObject(string)
val errorCode = errorJson.getInt("code")
if (errorCode == 403059) {
Utils.toast(getApplication(), "权限错误,请刷新后重试")
return
} else {
Utils.toast(getApplication(), e.message())
}
}
}
}
})
}, null)
}
}
}
}
private fun showReportTypeDialog(context: Context, reportCallback: (reportType: String) -> Unit) {
val reportTypes = arrayListOf("垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它")
DialogUtils.showListDialog(context, reportTypes, null) { text ->
val jsonObject = JSONObject()
try {
jsonObject.put("reason", text)
reportCallback.invoke(jsonObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
}
}
}

View File

@ -4,6 +4,7 @@ import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.view.View;
@ -19,8 +20,11 @@ import com.gh.gamecenter.adapter.OnCommentCallBackListener;
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.entity.MeEntity;
import com.gh.gamecenter.entity.RatingComment;
import com.gh.gamecenter.entity.UserInfoEntity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import org.json.JSONException;
@ -33,6 +37,11 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
/**
@ -71,8 +80,10 @@ public class CommentUtils {
}
}
public static void showReportDialog(final CommentEntity commentEntity, final Context context, final boolean showConversation,
final OnCommentCallBackListener listener, final String newsId) {
public static void showGameCommentOptions(final Context context,
final RatingComment comment,
final String gameId,
final String entrance) {
final Dialog dialog = new Dialog(context);
@ -83,6 +94,113 @@ public class CommentUtils {
List<String> dialogType = new ArrayList<>();
dialogType.add("复制");
dialogType.add("举报");
for (String s : dialogType) {
final TextView reportTv = new TextView(context);
reportTv.setText(s);
reportTv.setTextSize(17);
reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
0, DisplayUtils.dip2px(context, 12));
container.addView(reportTv);
reportTv.setOnClickListener(v -> {
dialog.cancel();
switch (reportTv.getText().toString()) {
case "复制":
copyText(comment.getContent(), context);
break;
case "举报":
CheckLoginUtils.checkLogin(context, entrance, () -> showGameCommentReportDialog(gameId, comment, context));
break;
}
});
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(container);
dialog.show();
}
private static void showGameCommentReportDialog(final String gameId, final RatingComment comment, final Context context) {
final String[] arrReportType = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息",
"违法有害信息", "其它"};
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
final Dialog reportTypeDialog = new Dialog(context);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
container.setBackgroundColor(Color.WHITE);
for (final String s : arrReportType) {
TextView reportTypeTv = new TextView(context);
reportTypeTv.setText(s);
reportTypeTv.setTextSize(17);
reportTypeTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTypeTv.setBackgroundResource(R.drawable.textview_white_style);
reportTypeTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTypeTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
0, DisplayUtils.dip2px(context, 12));
container.addView(reportTypeTv);
reportTypeTv.setOnClickListener(v -> {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("reason", s);
} catch (JSONException e) {
e.printStackTrace();
}
RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString());
RetrofitManager.getInstance(context).getApi()
.reportGameComment(gameId, comment.getId(), body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(@Nullable ResponseBody response) {
Utils.toast(context, "感谢您的举报");
}
@Override
public void onFailure(@Nullable HttpException e) {
Utils.toast(context, "举报失败,请先检查网络设置");
}
});
reportTypeDialog.cancel();
});
}
reportTypeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
reportTypeDialog.setContentView(container);
reportTypeDialog.show();
}
public static void showReportDialog(final CommentEntity commentEntity,
final Context context,
final boolean showConversation,
final OnCommentCallBackListener listener,
final String newsId,
final String patch) {
final Dialog dialog = new Dialog(context);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
List<String> dialogType = new ArrayList<>();
if (commentEntity.getMe() == null || !commentEntity.getMe().isCommentOwn()) {
dialogType.add("回复");
}
@ -113,7 +231,7 @@ public class CommentUtils {
dialog.cancel();
switch (reportTv.getText().toString()) {
case "回复":
CheckLoginUtils.checkLogin(context, () -> {
CheckLoginUtils.checkLogin(context, patch + "-回复", () -> {
if (listener != null) {
listener.onCommentCallback(commentEntity);
} else if (!TextUtils.isEmpty(newsId)) {
@ -127,7 +245,8 @@ public class CommentUtils {
copyText(commentEntity.getContent(), context);
break;
case "举报":
CheckLoginUtils.checkLogin(context, () -> showReportTypeDialog(commentEntity, context));
CheckLoginUtils.checkLogin(context, patch + "-举报",
() -> showReportTypeDialog(commentEntity, context));
break;
case "查看对话":
@ -144,125 +263,134 @@ public class CommentUtils {
}
public static void showAnswerCommentOptions(final CommentEntity commentEntity, final Context context,
final OnCommentCallBackListener listener, final String id, boolean showConversation, String answerId) {
// public static void showAnswerCommentOptions(final CommentEntity commentEntity, final Context context,
// final OnCommentCallBackListener listener, final String id,
// boolean showConversation, String answerId, String articleId, String articleCommunityId) {
//
// final Dialog dialog = new Dialog(context);
//
// LinearLayout container = new LinearLayout(context);
// container.setOrientation(LinearLayout.VERTICAL);
// container.setBackgroundColor(Color.WHITE);
// container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
//
// List<String> dialogType = new ArrayList<>();
//
// if (commentEntity.getMe() == null || !commentEntity.getMe().isAnswerCommented()) {
// dialogType.add("回复");
// }
//
// dialogType.add("复制");
// dialogType.add("举报");
//
// if (commentEntity.getParentUser() != null && showConversation) {
// dialogType.add("查看对话");
// }
//
// for (String s : dialogType) {
// final TextView reportTv = new TextView(context);
// reportTv.setText(s);
// reportTv.setTextSize(17);
// reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
// reportTv.setBackgroundResource(R.drawable.textview_white_style);
// int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
// reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
// LinearLayout.LayoutParams.WRAP_CONTENT));
// reportTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
// 0, DisplayUtils.dip2px(context, 12));
// container.addView(reportTv);
//
// reportTv.setOnClickListener(v -> {
// dialog.cancel();
// switch (reportTv.getText().toString()) {
// case "回复":
// CheckLoginUtils.checkLogin(context, () -> {
// if (listener != null) {
// listener.onCommentCallback(commentEntity);
// } else if (!TextUtils.isEmpty(id)) {
// context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, id));
// } else {
// Utils.toast(context, "缺少关键属性");
// }
// });
// break;
// case "复制":
// copyText(commentEntity.getContent(), context);
// break;
// case "举报":
// CheckLoginUtils.checkLogin(context, () -> showAnswerReportDialog(answerId, commentEntity, context));
// break;
// case "查看对话":
// if (TextUtils.isEmpty(articleId)) {
// context.startActivity(CommentDetailActivity.getAnswerCommentIntent(context, commentEntity.getId(), answerId, null));
// } else {
// context.startActivity(CommentDetailActivity.getCommunityArticleCommentIntent(context, articleId, commentEntity.getId(), articleCommunityId, null));
// }
// break;
// }
// });
// }
//
// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
// dialog.setContentView(container);
// dialog.show();
// }
final Dialog dialog = new Dialog(context);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
List<String> dialogType = new ArrayList<>();
if (commentEntity.getMe() == null || !commentEntity.getMe().isAnswerCommented()) {
dialogType.add("回复");
}
dialogType.add("复制");
dialogType.add("举报");
if (commentEntity.getParentUser() != null && showConversation) {
dialogType.add("查看对话");
}
for (String s : dialogType) {
final TextView reportTv = new TextView(context);
reportTv.setText(s);
reportTv.setTextSize(17);
reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
0, DisplayUtils.dip2px(context, 12));
container.addView(reportTv);
reportTv.setOnClickListener(v -> {
dialog.cancel();
switch (reportTv.getText().toString()) {
case "回复":
CheckLoginUtils.checkLogin(context, () -> {
if (listener != null) {
listener.onCommentCallback(commentEntity);
} else if (!TextUtils.isEmpty(id)) {
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, id));
} else {
Utils.toast(context, "缺少关键属性");
}
});
break;
case "复制":
copyText(commentEntity.getContent(), context);
break;
case "举报":
CheckLoginUtils.checkLogin(context, () -> showAnswerReportDialog(answerId, commentEntity, context));
break;
case "查看对话":
context.startActivity(CommentDetailActivity.getAnswerCommentIntent(context, commentEntity.getId(), answerId));
break;
}
});
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(container);
dialog.show();
}
private static void showAnswerReportDialog(final String answerId, final CommentEntity commentEntity, final Context context) {
final String[] arrReportType = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息",
"违法有害信息", "其它"};
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
final Dialog reportTypeDialog = new Dialog(context);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
container.setBackgroundColor(Color.WHITE);
for (final String s : arrReportType) {
TextView reportTypeTv = new TextView(context);
reportTypeTv.setText(s);
reportTypeTv.setTextSize(17);
reportTypeTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTypeTv.setBackgroundResource(R.drawable.textview_white_style);
reportTypeTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTypeTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
0, DisplayUtils.dip2px(context, 12));
container.addView(reportTypeTv);
reportTypeTv.setOnClickListener(v -> {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("reason", s);
} catch (JSONException e) {
e.printStackTrace();
}
PostCommentUtils.postAnswerReportData(context, commentEntity.getId(), answerId, jsonObject.toString(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
Utils.toast(context, "感谢您的举报");
}
@Override
public void postFailed(Throwable error) {
Utils.toast(context, error.toString());
}
});
reportTypeDialog.cancel();
});
}
reportTypeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
reportTypeDialog.setContentView(container);
reportTypeDialog.show();
}
// private static void showAnswerReportDialog(final String answerId, final CommentEntity commentEntity, final Context context) {
// final String[] arrReportType = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息",
// "违法有害信息", "其它"};
// int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
//
// final Dialog reportTypeDialog = new Dialog(context);
// LinearLayout container = new LinearLayout(context);
// container.setOrientation(LinearLayout.VERTICAL);
// container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
// container.setBackgroundColor(Color.WHITE);
//
// for (final String s : arrReportType) {
// TextView reportTypeTv = new TextView(context);
// reportTypeTv.setText(s);
// reportTypeTv.setTextSize(17);
// reportTypeTv.setTextColor(ContextCompat.getColor(context, R.color.title));
// reportTypeTv.setBackgroundResource(R.drawable.textview_white_style);
// reportTypeTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
// LinearLayout.LayoutParams.WRAP_CONTENT));
// reportTypeTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12),
// 0, DisplayUtils.dip2px(context, 12));
// container.addView(reportTypeTv);
//
// reportTypeTv.setOnClickListener(v -> {
// JSONObject jsonObject = new JSONObject();
// try {
// jsonObject.put("reason", s);
// } catch (JSONException e) {
// e.printStackTrace();
// }
//
// PostCommentUtils.postAnswerReportData(context, commentEntity.getId(), answerId, jsonObject.toString(),
// new PostCommentUtils.PostCommentListener() {
// @Override
// public void postSuccess(JSONObject response) {
// Utils.toast(context, "感谢您的举报");
// }
//
// @Override
// public void postFailed(Throwable error) {
// if (error != null) {
// Utils.toast(context, "举报失败" + error.getMessage());
// } else {
// Utils.toast(context, "举报失败,请稍候重试");
// }
// }
// });
// reportTypeDialog.cancel();
// });
// }
//
// reportTypeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
// reportTypeDialog.setContentView(container);
// reportTypeDialog.show();
// }
private static void showReportTypeDialog(final CommentEntity commentEntity, final Context context) {
final String[] arrReportType = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息",
@ -321,74 +449,79 @@ public class CommentUtils {
}
public static void postVote(final Context context, final CommentEntity commentEntity,
final TextView commentLikeCountTv, final ImageView commentLikeIv, final OnVoteListener listener) {
CheckLoginUtils.checkLogin(context, () -> {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
Utils.toast(context, "已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.ic_like_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
final TextView commentLikeCountTv, final ImageView commentLikeIv,
final OnVoteListener listener) {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
Utils.toast(context, "已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.vote_icon_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
PostCommentUtils.addCommentVoto(context, commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
if (listener != null) {
listener.onVote();
}
PostCommentUtils.addCommentVote(context, commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
if (listener != null) {
listener.onVote();
}
}
@Override
public void postFailed(Throwable e) {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {
commentLikeCountTv.setVisibility(View.VISIBLE);
}
@Override
public void postFailed(Throwable e) {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.ic_like_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
} else {
commentLikeCountTv.setVisibility(View.VISIBLE);
}
if (e instanceof HttpException) {
HttpException exception = (HttpException) e;
if (exception.code() == 403) {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if ("voted".equals(detail)) {
Utils.toast(context, "已经点过赞啦!");
}
} catch (Exception ex) {
ex.printStackTrace();
if (e instanceof HttpException) {
HttpException exception = (HttpException) e;
if (exception.code() == 403) {
try {
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
if ("voted".equals(detail)) {
Utils.toast(context, "已经点过赞啦!");
}
return;
} catch (Exception ex) {
ex.printStackTrace();
}
return;
}
Utils.toast(context, "网络异常,点赞失败");
}
});
});
Utils.toast(context, "网络异常,点赞失败");
}
});
}
public static void postVoteToAnswerComment(final Context context, String answerId, final CommentEntity commentEntity,
public static void postVoteToAnswerComment(final Context context, String answerId, String articleId,
String articleCommunityId, final CommentEntity commentEntity,
final TextView commentLikeCountTv, final ImageView commentLikeIv, final OnVoteListener listener) {
CheckLoginUtils.checkLogin(context, () -> {
String entrance = "回答详情-评论-点赞";
if (TextUtils.isEmpty(articleId)) {
entrance = "社区文章详情-评论-点赞";
}
CheckLoginUtils.checkLogin(context, entrance, () -> {
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
Utils.toast(context, "已经点过赞啦!");
return;
}
commentEntity.setVote(commentEntity.getVote() + 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
commentLikeIv.setImageResource(R.drawable.ic_like_select);
commentLikeIv.setImageResource(R.drawable.vote_icon_select);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
PostCommentUtils.voteAnswerComment(context, answerId, commentEntity.getId(),
PostCommentUtils.voteAnswerComment(context, answerId, articleId, articleCommunityId, commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
@ -402,7 +535,7 @@ public class CommentUtils {
commentEntity.setVote(commentEntity.getVote() - 1);
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
commentLikeIv.setImageResource(R.drawable.ic_like_unselect);
commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
commentLikeCountTv.setText(String.valueOf(commentEntity.getVote()));
if (commentEntity.getVote() == 0) {
commentLikeCountTv.setVisibility(View.GONE);
@ -435,14 +568,14 @@ public class CommentUtils {
public static void setCommentUserView(Context mContext, CommentViewHolder holder, CommentEntity entity) {
MeEntity userDataEntity = entity.getMe();
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.hint));
holder.commentLikeIv.setImageResource(R.drawable.ic_like_unselect);
holder.commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
if (entity.getVote() == 0) {
holder.commentLikeCountTv.setVisibility(View.GONE);
} else { // 检查是否已点赞
if (userDataEntity != null && (userDataEntity.isCommentVoted() || userDataEntity.isAnswerCommentVoted())) {
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
holder.commentLikeIv.setImageResource(R.drawable.ic_like_select);
holder.commentLikeIv.setImageResource(R.drawable.vote_icon_select);
}
holder.commentLikeCountTv.setVisibility(View.VISIBLE);
holder.commentLikeCountTv.setText(NumberUtils.transSimpleCount(entity.getVote()));

View File

@ -0,0 +1,45 @@
package com.gh.common.util
import com.gh.gamecenter.qa.entity.AskGameSelectEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
/**
* 用于判断社区跳转前社区是否可用
*/
object CommunityHelper {
private var availableCommunityList = listOf<AskGameSelectEntity>()
@JvmStatic
fun getAvailableCommunityList() {
RetrofitManager.getInstance(HaloApp.getInstance().application).api
.getAskGameSelect(HaloApp.getInstance().channel
, UrlFilterUtils.getFilterQuery("status", "opened"), 1, 100)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<List<AskGameSelectEntity>>() {
override fun onResponse(response: List<AskGameSelectEntity>?) {
if (response != null && response.isNotEmpty()) {
availableCommunityList = response
}
}
})
}
@JvmStatic
fun isCommunityAvailable(communityId: String?): Boolean {
communityId?.let {
if (availableCommunityList.isEmpty()) return true
for (entity in availableCommunityList) {
if (communityId == entity.id) {
return true
}
}
}
return false
}
}

View File

@ -142,12 +142,11 @@ object CompressImageUtils {
}
fun getImageSetting(): SettingsEntity.Image {
var settings = Config.getSettings()
val settings = Config.getSettings()
if (settings == null && settings?.image != null) {
return settings.image
return settings.image!!
}
settings = SettingsEntity()
val image = settings.Image()
val image = SettingsEntity.Image()
image.processLimitSize = compressLimitSize
image.size = defaultCompressBorder
image.ratio = defaultRatio

View File

@ -1,6 +1,7 @@
package com.gh.common.util
import android.content.Context
import android.text.TextUtils
import com.gh.gamecenter.eventbus.EBConcernChanged
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.Response
@ -20,12 +21,14 @@ import retrofit2.HttpException
*/
object ConcernUtils {
fun postConcernGameId(context: Context, gameId: String, listener: onConcernListener?) {
// val params = JSONArray()
// params.put(gameId)
// val body = RequestBody.create(MediaType.parse("application/json"), params.toString())
RetrofitManager.getInstance(context).getApi()
.postConcern(UserManager.getInstance().userId, gameId)
fun postConcernGameId(context: Context, gameId: String, listener: onConcernListener?, autoConcern: Boolean = false) {
val mode = if (autoConcern) "auto" else "manual"
val userId = UserManager.getInstance().userId
if (TextUtils.isEmpty(userId)) return
RetrofitManager.getInstance(context).api
.postConcern(UserManager.getInstance().userId, gameId, mode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
@ -43,7 +46,7 @@ object ConcernUtils {
}
fun deleteConcernData(context: Context, gameId: String, listener: onConcernListener?) {
RetrofitManager.getInstance(context).getApi()
RetrofitManager.getInstance(context).api
.deleteConcern(UserManager.getInstance().userId, gameId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -64,7 +67,7 @@ object ConcernUtils {
fun updateConcernData(context: Context, data: JSONArray) {
val body = RequestBody.create(MediaType.parse("application/json"),
data.toString())
RetrofitManager.getInstance(context).getApi()
RetrofitManager.getInstance(context).api
.putConcern(UserManager.getInstance().userId, body)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
@ -76,7 +79,7 @@ object ConcernUtils {
}
fun deleteConcernQuestions(context: Context, questionsId: String, listener: onConcernListener?) {
RetrofitManager.getInstance(context).getApi()
RetrofitManager.getInstance(context).api
.deleteConcernQuestions(UserManager.getInstance().userId, questionsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -95,7 +98,7 @@ object ConcernUtils {
}
fun postConcernQuestions(context: Context, questionsId: String, listener: onConcernListener?) {
RetrofitManager.getInstance(context).getApi()
RetrofitManager.getInstance(context).api
.postConcernQuestions(UserManager.getInstance().userId, questionsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -6,7 +6,7 @@ import android.os.Build;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.NewsDetailEntity;
import com.gh.gamecenter.manager.DataCollectionManager;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import org.json.JSONArray;
@ -118,7 +118,7 @@ public class DataCollectionUtils {
Map<String, Object> map = new HashMap<>();
map.put("type", Build.MODEL);
map.put("system", Build.VERSION.SDK_INT + "=" + Build.VERSION.RELEASE);
map.put("install", PackageManager.INSTANCE.getInstalledList());
map.put("install", PackagesManager.INSTANCE.getInstalledList());
DataCollectionManager.upsert(context, "user", map);
}

View File

@ -38,7 +38,7 @@ public class DataLogUtils {
// 上传日志
public static void uploadLog(Context context, String topic, Map<String, Object> map) {
String version = PackageUtils.getPatchVersionName();
String version = PackageUtils.getVersionName();
String user = Installation.getUUID(context);
String channel = HaloApp.getInstance().getChannel();
map.put("version", version);

View File

@ -82,12 +82,11 @@ public class DataUtils {
StatConfig.init(context);
StatConfig.setInstallChannel(channel);
StatConfig.setAntoActivityLifecycleStat(true);
StatConfig.setAppVersion(PackageUtils.getPatchVersionName());
StatConfig.setAppVersion(PackageUtils.getVersionName());
// 开启收集服务
StatService.startStatService(context, Config.MTA_APPKEY, com.tencent.stat.common.StatConstants.VERSION);
StatService.registerActivityLifecycleCallbacks(context);
} catch (MtaSDkException e) {
e.printStackTrace();
}
@ -100,7 +99,7 @@ public class DataUtils {
strategy.setEnableANRCrashMonitor(false);
strategy.setEnableNativeCrashMonitor(false);
strategy.setAppChannel(channel);
strategy.setAppVersion(PackageUtils.getPatchVersionName());
strategy.setAppVersion(PackageUtils.getVersionName());
CrashReport.initCrashReport(context, Config.BUGLY_APPID, false, strategy);
@ -115,17 +114,7 @@ public class DataUtils {
// if (CommonDebug.IS_DEBUG && (kv == null || kv.length % 2 != 0)) {
// throw new IllegalStateException("onEvent kv 必须不为空且数量为偶数");
// }
Properties prop = new Properties();
for (int i = 0; i < kv.length; i++) {
if (i % 2 != 0 && i != 0) {
String key = kv[i - 1];
String value = kv[i];
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value);
}
}
}
StatService.trackCustomKVEvent(context, eventId, prop);
MtaHelper.onEvent(eventId, kv);
}
public static void onEvent(Context var0, String var1, String var2) {
@ -199,11 +188,19 @@ public class DataUtils {
onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("版本", platform);
kv2.put("状态", status);
kv2.put("位置", entrance);
kv2.put("游戏分平台", gameName + "-" + platform);
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
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

@ -8,7 +8,8 @@ import com.gh.common.view.DownloadProgressBar;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.DetailViewHolder;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
/**
@ -33,15 +34,13 @@ public class DetailDownloadUtils {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.downloadOffText) ? "暂无下载" : viewHolder.downloadOffText);
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NONE);
} else {
String status = GameUtils.getDownloadBtnText(viewHolder.context, viewHolder.gameEntity);
String status = GameUtils.getDownloadBtnText(viewHolder.context, viewHolder.gameEntity, PluginLocation.only_game);
switch (status) {
case "插件化":
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN);
break;
case "打开":
if (viewHolder.gameEntity.getApk().size() == 1) {
status = "启动";
}
case "启动":
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
break;
default:
@ -73,11 +72,19 @@ public class DetailDownloadUtils {
switch (downloadEntity.getStatus()) {
case downloading:
case pause:
viewHolder.mDownloadPb.setText(R.string.downloading);
if (downloadEntity.isPluggable() && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
}
break;
case timeout:
case neterror:
case waiting:
viewHolder.mDownloadPb.setText(R.string.downloading);
if (downloadEntity.isPluggable() && PackageManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
case subscribe:
viewHolder.mDownloadPb.setText(R.string.waiting);
if (downloadEntity.isPluggable() && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
@ -86,7 +93,7 @@ public class DetailDownloadUtils {
case done:
viewHolder.mDownloadPb.setText(R.string.install);
if (downloadEntity.isPluggable()
&& PackageManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN);
} else {
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);

View File

@ -4,8 +4,9 @@ import android.content.Context
import android.os.Environment
import android.preference.PreferenceManager
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.StringResponse
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Phone_State
import com.lightgame.utils.Utils
@ -13,7 +14,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.File
object DeviceTokenUtils {
const val DEVICE_ID = "uuid"
@ -26,18 +26,13 @@ object DeviceTokenUtils {
RetrofitManager.getInstance(context).api.time
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : StringResponse() {
override fun onResponse(response: String) {
if (response.matches("^[0-9]{10}$".toRegex())) {
try {
val editor = sp.edit()
editor.putLong("server_time", java.lang.Long.parseLong(response))
editor.putLong("client_time", System.currentTimeMillis() / 1000)
editor.apply()
} catch (e: NumberFormatException) {
e.printStackTrace()
}
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val editor = sp.edit()
response?.time?.let {
editor.putLong("server_time", it)
editor.putLong("client_time", System.currentTimeMillis() / 1000)
editor.apply()
}
}
})
@ -51,18 +46,18 @@ object DeviceTokenUtils {
if (values.isNotEmpty()) {
for (value in values) {
if (value.key.contains("isNewFirstLaunchV")) {
lunchType = LunchType.update
lunchType = LunchType.UPDATE
break
}
}
}
// 再次重装
if (lunchType == null && !getDeviceId().isNullOrEmpty()) {
lunchType = LunchType.again
lunchType = LunchType.AGAIN
}
// 首次安装
if (lunchType == null) {
lunchType = LunchType.first
lunchType = LunchType.FIRST
}
// 保存deviceId
var deviceId = Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
@ -133,7 +128,7 @@ object DeviceTokenUtils {
}
enum class LunchType {
first,
update,
again
FIRST,
UPDATE,
AGAIN
}

View File

@ -128,6 +128,20 @@ public class DeviceUtils {
return builder.toString();
}
public static String getUserAgent() {
String userAgent = "";
userAgent = System.getProperty("http.agent");
StringBuffer sb = new StringBuffer();
for (int i = 0, length = userAgent.length(); i < length; i++) {
char c = userAgent.charAt(i);
if (c <= '\u001f' || c >= '\u007f') {
sb.append(String.format("\\u%04x", (int) c));
} else {
sb.append(c);
}
}
return sb.toString();
}
public static String getIPAddress(Context context) {
NetworkInfo info = ((ConnectivityManager) context
@ -201,7 +215,7 @@ public class DeviceUtils {
}
}
return null;
return "无网络";
}

View File

@ -7,12 +7,14 @@ import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -24,10 +26,12 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.gh.gamecenter.AboutActivity;
import com.gh.gamecenter.KcSelectGameActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.kuaichuan.WifiMgr;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import java.io.File;
import java.text.DecimalFormat;
@ -325,7 +329,6 @@ public class DialogUtils {
}
public static void showWarningDialog(Context context, String title, CharSequence msg, final ConfirmListener listener) {
//TODO fix this
if (!(context instanceof Activity)) {
return;
}
@ -350,10 +353,61 @@ public class DialogUtils {
}, null);
}
public static void showDownloadDialog(Context context, ConfirmListener listener, CancelListener cancelListener) {
showWarningDialog(context, "下载提示", "您当前使用的网络为2G/3G/4G开始下载将会消耗移动流量确定下载", "取消", "确定", listener, cancelListener);
public static void checkDownload(Context context, String size, CheckDownloadCallBack callBack) {
if (!NetworkUtils.isNetworkConnected(context)) {
showNoConnectionDownloadDialog(context, null,
() -> callBack.onResponse(true));
} else if (NetworkUtils.isWifiConnected(context) || filter4GorSize(context, size)) {
callBack.onResponse(false);
} else {
showDownloadDialog(context,
() -> callBack.onResponse(false),
() -> callBack.onResponse(true));
}
}
private static boolean filter4GorSize(Context context, String size) {
try {
if (TextUtils.isEmpty(size)) {
return false;
}
String mb = size.toUpperCase().replaceAll("MB", "").trim();
Float i = Float.valueOf(mb);
if (NetworkUtils.isWifiOr4GConnected(context) && i <= 50) {
Utils.toast(context, "当前使用移动流量下载");
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static void checkResumeDownload(Context context, CheckDownloadCallBack callBack) {
if (NetworkUtils.isWifiConnected(context)) {
callBack.onResponse(false);
} else {
showResumeDownloadDialog(context, () -> {
callBack.onResponse(false);
}, () -> {
callBack.onResponse(true);
});
}
}
public static void showNoConnectionDownloadDialog(Context context, ConfirmListener listener, CancelListener cancelListener) {
showWarningDialog(context, "下载提示", "网络异常,请检查手机网络状态", "连上WiFi后自动下载", "关闭", listener, cancelListener);
}
public static void showDownloadDialog(Context context, ConfirmListener listener, CancelListener cancelListener) {
showWarningDialog(context, "下载提示", "当前正在使用移动网络,立即下载会消耗手机流量", "连上WiFi后自动下载", "立即下载", listener, cancelListener);
}
public static void showResumeDownloadDialog(Context context, ConfirmListener listener, CancelListener cancelListener) {
showWarningDialog(context, "下载提示", "当前正在使用移动网络,继续下载会消耗手机流量", "连上WiFi后自动下载", "继续下载", listener, cancelListener);
}
public static void showDownloadDialog(Context context, ConfirmListener listener) {
showWarningDialog(context, "下载提示", "您当前使用的网络为2G/3G/4G开始下载将会消耗移动流量确定下载", listener);
}
@ -701,6 +755,88 @@ public class DialogUtils {
dialog.show();
}
public static void showLowVersionDialog(Context context) {
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_alert, null);
TextView contentTv = contentView.findViewById(R.id.dialog_content);
TextView titleTv = contentView.findViewById(R.id.dialog_title);
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
TextView positiveTv = contentView.findViewById(R.id.dialog_positive);
contentTv.setText("链接超出范围,请检查升级至最新版本的光环助手");
titleTv.setText("提示");
negativeTv.setText("关闭");
positiveTv.setText("检查升级");
negativeTv.setOnClickListener(view -> dialog.dismiss());
positiveTv.setOnClickListener(view -> {
context.startActivity(AboutActivity.getIntent(context, true));
dialog.dismiss();
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(contentView);
dialog.show();
}
public static void showListDialog(Context context,
List<String> selectionList,
DialogInterface.OnClickListener onClickListener) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
String[] selectionArray = new String[selectionList.size()];
selectionArray = selectionList.toArray(selectionArray);
builder.setItems(selectionArray, onClickListener);
AlertDialog dialog = builder.create();
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.show();
}
/**
* @param options 供以显示的选项
* @param disabledOptions 显示为灰色的选项(是 options 的子集)
*/
public static void showListDialog(Context context,
List<String> options,
List<String> disabledOptions,
OptionCallback callback) {
Dialog dialog = new Dialog(context);
LinearLayout container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setBackgroundColor(Color.WHITE);
container.setPadding(0, DisplayUtils.dip2px(context, 12f), 0, DisplayUtils.dip2px(context, 12f));
for (String option : options) {
TextView reportTv = new TextView(context);
reportTv.setText(option);
reportTv.setTextSize(17f);
if (disabledOptions != null && disabledOptions.contains(option)) {
reportTv.setTextColor(ContextCompat.getColor(context, R.color.btn_gray));
} else {
reportTv.setTextColor(ContextCompat.getColor(context, R.color.title));
reportTv.setBackgroundResource(R.drawable.textview_white_style);
}
int widthPixels = context.getResources().getDisplayMetrics().widthPixels;
reportTv.setLayoutParams(new LinearLayout.LayoutParams(widthPixels * 9 / 10,
LinearLayout.LayoutParams.WRAP_CONTENT));
reportTv.setPadding(DisplayUtils.dip2px(context, 20f), DisplayUtils.dip2px(context, 12f),
0, DisplayUtils.dip2px(context, 12f));
container.addView(reportTv);
reportTv.setOnClickListener(v -> {
dialog.cancel();
callback.onClicked(reportTv.getText().toString());
});
}
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(container);
dialog.show();
}
public interface ConfirmListener {
void onConfirm();
}
@ -709,4 +845,12 @@ public class DialogUtils {
void onCancel();
}
public interface OptionCallback {
void onClicked(String text);
}
public interface CheckDownloadCallBack {
void onResponse(boolean isSubscribe);
}
}

View File

@ -6,18 +6,23 @@ import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import com.gh.base.fragment.BaseFragment_TabLayout
import com.gh.common.AppExecutor
import com.gh.common.util.EntranceUtils.*
import com.gh.gamecenter.*
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.LinkEntity
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.eventbus.EBSkip
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.AskFragment
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.column.detail.AskColumnDetailActivity
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity
import com.gh.gamecenter.subject.refactor.SubjectActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.suggest.SuggestType
import com.lightgame.utils.Util_System_ClipboardManager
import com.lightgame.utils.Utils
@ -58,6 +63,41 @@ object DirectUtils {
}
}
/**
* 跳转到特定页面,只支持App内部跳转
*/
@JvmStatic
fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String) {
when (linkEntity.type) {
"article", "news" -> {
NewsUtils.statNewsViews(context, linkEntity.link) // 统计阅读量
context.startActivity(NewsDetailActivity.getIntentById(context, linkEntity.link, entrance))
}
"game" -> GameDetailActivity.startGameDetailActivity(context, linkEntity.link, entrance)
"column" -> SubjectActivity.startSubjectActivity(context, linkEntity.link, linkEntity.text, false, entrance)
"question" -> context.startActivity(QuestionsDetailActivity.getIntent(context, linkEntity.link, entrance, path))
"answer" -> context.startActivity(AnswerDetailActivity.getIntent(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_column" -> context.startActivity(CommunitySubjectActivity.getIntent(context, linkEntity.community!!, linkEntity.link, entrance))
"community_special_column" -> context.startActivity(AskColumnDetailActivity.getIntentByColumnId(context, linkEntity.link, linkEntity.community!!, entrance, path))
"web" -> directToWebView(context, url = linkEntity.link!!, entrance = entrance)
"qq" -> directToQqConversation(context, linkEntity.link)
else -> DialogUtils.showLowVersionDialog(context)
}
}
/**
* 跳转到文章详情
*/
@ -137,7 +177,6 @@ object DirectUtils {
bundle.putString(KEY_GAMEID, gameId)
bundle.putString(KEY_PACKAGENAME, packageName)
bundle.putInt(BaseFragment_TabLayout.PAGE_INDEX, INDEX_UPDATE)
bundle.putBoolean(KEY_AUTO_UPDATE, true)
EntranceUtils.jumpActivity(context, bundle)
}
@ -242,7 +281,21 @@ object DirectUtils {
context.startActivity(intent)
}
UserManager.getInstance().setCommunityData(community)
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_GAMEFRAGMENT, 1))
EventBus.getDefault().post(EBReuse(AskFragment.EB_RETRY_PAGE))
// 这里换个线程操作是为了做一点延时
AppExecutor.ioExecutor.execute {
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_GAMEFRAGMENT, 1))
EventBus.getDefault().post(EBReuse(AskFragment.EB_RETRY_PAGE))
}
}
@JvmStatic
fun directToCommunityArticle(context: Context, articleId: String?, communityId: String?, entrance: String?) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(EntranceUtils.KEY_TO, ArticleDetailActivity::class.java.name)
bundle.putString(EntranceUtils.KEY_COMMUNITY_ARTICLE_ID, articleId)
bundle.putParcelable(EntranceUtils.KEY_COMMUNITY_DATA, CommunityEntity(id = communityId!!))
EntranceUtils.jumpActivity(context, bundle)
}
}

View File

@ -21,6 +21,7 @@ object DownloadHelper {
RetrofitManager.getInstance(HaloApp.getInstance().application)
.api
.getGameDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<GameEntity>() {
override fun onResponse(response: GameEntity?) {
@ -29,13 +30,13 @@ object DownloadHelper {
for (apk in response.getApk()) {
if (packageName == apk.packageName) {
DownloadManager.createDownload(HaloApp.getInstance().application,
apk, response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", null)
apk, response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", false, null)
block.invoke()
}
}
} else if (response.getApk().size == 1) {
DownloadManager.createDownload(HaloApp.getInstance().application,
response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", null)
response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", false, null)
block.invoke()
}
}

View File

@ -21,7 +21,8 @@ import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.GameViewHolder;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
@ -68,7 +69,7 @@ public class DownloadItemUtils {
// adapter.notifyItemChanged(index);
// }
} else {
if (!queue.contains(platform)) {
if (!queue.contains(platform) && !TextUtils.isEmpty(platform)) {
queue.offer(platform);
if (AppDebugConfig.IS_DEBUG) {
AppDebugConfig.logMethodWithParams(DownloadItemUtils.class, queue.size(), gameEntity.getBrief(), downloadEntity.getPlatform(), index);
@ -95,7 +96,13 @@ public class DownloadItemUtils {
}
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder, boolean isShowPlatform) {
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform) {
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game);
}
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
boolean isShowPlatform, PluginLocation pluginLocation) {
// 控制是否显示下载按钮
if (!Config.isShowDownload(gameEntity.getId()) || context.getString(R.string.app_name).equals(gameEntity.getName())) {
@ -119,17 +126,16 @@ public class DownloadItemUtils {
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(context, R.color.button_gray));
holder.gameDownloadBtn.setClickable(false);
} else if (gameEntity.getApk().size() == 1) {
updateNormalItem(context, holder, gameEntity, isShowPlatform);
updateNormalItem(context, holder, gameEntity, isShowPlatform, pluginLocation);
} else {
// updateNormalItem(context, holder, gameEntity, isShowPlatform);
updatePluginItem(context, holder, gameEntity, isShowPlatform);
updatePluginItem(context, holder, gameEntity, isShowPlatform, pluginLocation);
}
}
// 更新正常的条目只有一个apk包
static void updateNormalItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
boolean isShowPlatform, PluginLocation pluginLocation) {
final ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
final ApkEntity apkEntity = gameEntity.getApk().get(0);
@ -143,74 +149,22 @@ 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);
holder.gameDownloadBtn.setTextColor(Color.WHITE);
final String packageName = apkEntity.getPackageName();
if (gameEntity.isPluggable()) {
holder.gameDownloadBtn.setText(R.string.pluggable);
setwhat(context, holder, apkEntity, packageName);
} else if (PackageManager.INSTANCE.isInstalled(packageName)) {
if (PackageManager.INSTANCE.isCanUpdate(gameEntity.getId(), packageName)) {
holder.gameDownloadBtn.setText(R.string.update);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
} else {
Object gh_id = PackageUtils.getMetaData(context, packageName, "gh_id");
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(context, packageName)) {
holder.gameDownloadBtn.setText(R.string.pluggable);
setwhat(context, holder, apkEntity, packageName);
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
holder.gameDownloadBtn.setText(R.string.launch);
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
holder.gameDownloadBtn.setBackgroundResource(R.drawable.detail_download_open_style);
} else {
holder.gameDownloadBtn.setText(R.string.download);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
} else {
holder.gameDownloadBtn.setText(R.string.download);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
}
}
/**
* 这个干什么鬼?
*
* @param context
* @param holder
* @param apkEntity
* @param packageName
*/
public static void setwhat(Context context, GameViewHolder holder, ApkEntity apkEntity, String packageName) {
DownloadEntity downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByPackageName(packageName);
if (downloadEntity == null || downloadEntity.getUrl().equals(apkEntity.getUrl())) {
holder.gameDownloadBtn.setClickable(true);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setClickable(false);
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_pause_up);
}
}
// 更新插件的条目有多个apk包
static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform) {
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn);
private static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
boolean isShowPlatform, PluginLocation pluginLocation) {
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
if (entryMap != null && !entryMap.isEmpty()) {
DownloadEntity downloadEntity;
LinkedBlockingQueue<String> queue = DownloadManager.getInstance(context).getQueue(gameEntity.getName());
DownloadEntity downloadEntity;
if (queue != null && !queue.isEmpty()) {
downloadEntity = entryMap.get(queue.peek());
} else {
@ -274,7 +228,8 @@ public class DownloadItemUtils {
}
} else if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.timeout)
|| status.equals(DownloadStatus.neterror)) {
|| status.equals(DownloadStatus.neterror)
|| status.equals(DownloadStatus.subscribe)) {
holder.gameProgressbar.setProgress((int) (downloadEntity.getPercent() * 10));
if (isShowPlatform && platform != null) {
holder.gameDownloadSpeed.setText(String.format("%s - 暂停", platform));
@ -284,7 +239,11 @@ public class DownloadItemUtils {
holder.gameDownloadPercentage.setText(downloadEntity.getPercent() + "%");
if (isNormal) {
holder.gameDownloadBtn.setText(R.string.downloading);
if (status.equals(DownloadStatus.pause)) {
holder.gameDownloadBtn.setText(R.string.downloading);
} else {
holder.gameDownloadBtn.setText(R.string.waiting);
}
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style);
holder.gameDownloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
}
@ -298,10 +257,10 @@ public class DownloadItemUtils {
holder.gameDownloadPercentage.setText(R.string.hundred_percent);
if (isNormal) {
holder.gameDownloadBtn.setText("安装");
holder.gameDownloadBtn.setText(R.string.install);
holder.gameDownloadBtn.setTextColor(Color.WHITE);
if (downloadEntity.isPluggable()
&& PackageManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else {
holder.gameDownloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
@ -356,51 +315,34 @@ public class DownloadItemUtils {
final String entrance,
final String location,
@Nullable final ExposureEvent traceEvent) {
String str = downloadBtn.getText().toString();
switch (str) {
case "下载":
if (NetworkUtils.isWifiConnected(context)) {
download(context, gameEntity, downloadBtn, entrance, location, traceEvent);
} else {
DialogUtils.showDownloadDialog(context, () -> download(context, gameEntity, downloadBtn, entrance, location, traceEvent));
}
break;
case "插件化":
if (entrance.contains("我的游戏")) {
DataUtils.onMtaEvent(context, "我的游戏_启动", "插件化", gameEntity.getName());
}
if (NetworkUtils.isWifiConnected(context)) {
plugin(context, gameEntity, downloadBtn, entrance, location, traceEvent);
} else {
DialogUtils.showDownloadDialog(context, () -> plugin(context, gameEntity, downloadBtn, entrance, location, traceEvent));
}
break;
case "安装":
install(context, gameEntity, position, adapter);
break;
case "启动":
if (entrance.contains("我的游戏")) {
DataUtils.onMtaEvent(context, "我的游戏_启动", "启动", gameEntity.getName());
}
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
break;
case "下载中":
context.startActivity(
DownloadManagerActivity.getDownloadMangerIntent(context, gameEntity.getApk().get(0).getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
break;
case "更新":
if (entrance.contains("我的游戏")) {
DataUtils.onMtaEvent(context, "我的游戏_启动", "更新", gameEntity.getName());
}
if (NetworkUtils.isWifiConnected(context)) {
update(context, gameEntity, entrance, location, traceEvent);
} else {
DialogUtils.showDownloadDialog(context, () -> update(context, gameEntity, entrance, location, traceEvent));
}
break;
if (str.equals(context.getString(R.string.download))) {
DialogUtils.checkDownload(context, gameEntity.getApk().get(0).getSize(),
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
} else if (str.equals(context.getString(R.string.pluggable))) {
if (entrance.contains("我的游戏")) {
DataUtils.onMtaEvent(context, "我的游戏_启动", "插件化", gameEntity.getName());
}
DialogUtils.checkDownload(context, gameEntity.getApk().get(0).getSize(),
isSubscribe -> plugin(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
} else if (str.equals(context.getString(R.string.install))) {
install(context, gameEntity, position, adapter);
} else if (str.equals(context.getString(R.string.launch))) {
if (entrance.contains("我的游戏")) {
DataUtils.onMtaEvent(context, "我的游戏_启动", "启动", gameEntity.getName());
}
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
} else if (str.equals(context.getString(R.string.waiting))
|| str.equals(context.getString(R.string.downloading))) {
context.startActivity(DownloadManagerActivity.getDownloadMangerIntent(context,
gameEntity.getApk().get(0).getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
} else if (str.equals(context.getString(R.string.update))) {
if (entrance.contains("我的游戏")) {
DataUtils.onMtaEvent(context, "我的游戏_启动", "更新", gameEntity.getName());
}
DialogUtils.checkDownload(context, gameEntity.getApk().get(0).getSize(),
isSubscribe -> update(context, gameEntity, entrance, location, isSubscribe, traceEvent));
}
}
@ -410,6 +352,7 @@ public class DownloadItemUtils {
TextView downloadBtn,
String entrance,
String location,
boolean isSubscribe,
@Nullable ExposureEvent traceEvent) {
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
if (TextUtils.isEmpty(msg)) {
@ -417,7 +360,7 @@ public class DownloadItemUtils {
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, downloadExposureEvent);
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, isSubscribe, downloadExposureEvent);
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
downloadBtn.setText(R.string.downloading);
@ -432,14 +375,14 @@ public class DownloadItemUtils {
//插件化
private static void plugin(Context context, GameEntity gameEntity, TextView downloadBtn, String entrance,
String location, @Nullable ExposureEvent traceEvent) {
String location, boolean isSubscribe, @Nullable ExposureEvent traceEvent) {
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "插件化");
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.PLUGIN_DOWNLOAD);
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, downloadExposureEvent);
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, downloadExposureEvent);
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
downloadBtn.setText(R.string.downloading);
@ -473,10 +416,11 @@ public class DownloadItemUtils {
}
//更新
private static void update(Context context, GameEntity gameEntity, String entrance, String location, @Nullable ExposureEvent traceEvent) {
private static void update(Context context, GameEntity gameEntity, String entrance, String location,
boolean isSubscribe, @Nullable ExposureEvent traceEvent) {
DataUtils.onGameUpdateEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), "下载开始");
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.UPDATE);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, downloadExposureEvent);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, downloadExposureEvent);
}
}

View File

@ -25,6 +25,7 @@ public class EntranceUtils {
public static final String KEY_URL = "url";
public static final String KEY_GAMENAME = "gameName";
public static final String HOST_ARTICLE = "article";
public static final String HOST_COMMUNITY_ARTICLE = "community.article";
public static final String HOST_GAME = "game";
public static final String HOST_GAME_DOWNLOAD = "game_download";
public static final String HOST_COLUMN = "column";
@ -40,6 +41,7 @@ public class EntranceUtils {
public static final String KEY_DATA = "data";
public static final String KEY_MESSAGE = "message";
public static final String KEY_TYPE = "type";
public static final String KEY_LINK = "link";
public static final String KEY_NAME = "name";
public static final String KEY_ENTRANCE = "entrance";
public static final String KEY_TARGET = "target";
@ -60,6 +62,7 @@ public class EntranceUtils {
public static final String KEY_CURRENTITEM = "currentItem";
public static final String KEY_COMMENTID = "commentId";
public static final String KEY_PATH = "path";
public static final String KEY_OUTER_INFO = "outerInfo";
public static final String KEY_OLDERUSER = "isOldUser";
public static final String KEY_SEARCHKEY = "searchKey";
public static final String KEY_HINT = "hint";
@ -79,7 +82,7 @@ public class EntranceUtils {
public static final String KEY_MESSAGE_TYPE = "messageType";
public static final String KEY_QUESTIONS_SEARCH_KEY = "questionsSearchKey";
public static final String KEY_SHOW_ANSWER_COMMENT = "showAnswerComment";
public static final String KEY_RECOMMENDS_ANSWER = "isRecommendsAnswer";
public static final String KEY_RECOMMENDS_CONTENTS = "isRecommendsContents";
public static final String KEY_VERSION_UPDATE = "versionUpdate";
public static final String KEY_CHECK_QUESTION_CONCERN = "check_question_concern";
public static final String KEY_DRAFT_ID = "draft_id";
@ -100,8 +103,14 @@ public class EntranceUtils {
public static final String KEY_QUESTION_TAG = "question_tag";
public static final String KEY_COLUMN_ID = "column_id";
public static final String KEY_AUTO_DOWNLOAD = "auto_download";
public static final String KEY_AUTO_UPDATE = "auto_update";
public static final String KEY_SEARCH_SUGGEST_HINT = "search_suggest_hint";
public static final String KEY_HIDE_SUGGEST_HINT = "hide_suggest_hint";
public static final String KEY_COMMUNITY_ARTICLE_ID = "communityArticleId";
public static final String KEY_ARTICLE_COMMENT_ID = "articleCommentId";
public static final String KEY_DEVICE_NAME = "deviceName";
public static final String KEY_SHOW_ARTICLE_COMMENT = "showArticleComment";
public static final String KEY_RATING_STAR_COUNT = "ratingStarCount";
public static final String KEY_QUESTION_MODERATOR_PATCH = "questionModeratorPatch";
public static final String KEY_SKIP_GAME_COMMENT = "skipGameComment";
public static void jumpActivity(Context context, Bundle bundle) {

View File

@ -0,0 +1,103 @@
package com.gh.common.util
import android.content.Context
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.ErrorEntity
import com.lightgame.utils.Utils
/**
* 这个类用来管理一些错误像弹窗、TOAST 什么的
*/
object ErrorHelper {
/***
* 禁言错误,
*403050 评论回答
*403051 评论资讯文章
*403055 评论社区文章
*403048 发表回答
*403053 发表社区文章
*403049 发布问题
*403046 编辑回答
*403045 编辑答案
*403057 游戏评论
*403054 更新社区文章
*403047 回答点赞
*/
/**
* [important] 用来标识有同样错误码可以触发两种处理时,为 true 时选择重要的
*/
fun handleError(context: Context, errorString: String?, important: Boolean = false) {
val errorEntity = errorString?.fromObject<ErrorEntity>()
if (errorEntity == null) {
Utils.toast(context, R.string.post_failure_hint)
return
}
if (!errorEntity.toast.isNullOrEmpty()) {
Utils.toast(context, errorEntity.toast)
return
}
when (errorEntity.code) {
403050,
403051,
403055,
403048,
403053,
403049,
403046,
403045,
403057,
403054,
403047 -> handleErrorWithBannedDialog(context, errorEntity)
403001 -> Utils.toast(context, "标签名称太长了")
403002 -> Utils.toast(context, "已经被邀请了")
403003 -> Utils.toast(context, "每天最多可以邀请10次")
403004 -> Utils.toast(context, "客户端提供的ID无效空/无效ID")
403005 -> Utils.toast(context, "已经回答过了(限制频率)")
403006 -> Utils.toast(context, "图片数量达到限制点")
403007 -> Utils.toast(context, "不合法的用户")
403008 -> Utils.toast(context, "已投票")
403009 -> Utils.toast(context, "已经收藏过了")
403010 -> Utils.toast(context, "无效的标签栏")
403011 -> Utils.toast(context, "标题内容过长")
403012 -> Utils.toast(context, "描述内容过长")
403013 -> Utils.toast(context, "无效的标签")
403014 -> Utils.toast(context, "标签数量太多了")
403015 -> Utils.toast(context, "已经关注过了")
404001 -> Utils.toast(context, "请求的资源不存在")
403018 -> Utils.toast(context, R.string.comment_failed_unable)
403020 -> if (important!!) {
DialogUtils.showAlertDialog(context,
"限制提醒",
"提问过于频繁,请先休息一下哦",
"知道了", null, null, null)
} else {
Utils.toast(context, R.string.comment_failed_toofrequent)
}
403021 -> Utils.toast(context, R.string.comment_failed_illegal)
else -> Utils.toast(context, R.string.post_failure_hint)
}
}
private fun handleErrorWithBannedDialog(context: Context, errorEntity: ErrorEntity) {
val bannedType = if (errorEntity.data?.alwaysBlock!!) {
""
} else {
"(非永久)"
}
DialogUtils.showAlertDialog(context,
"提示",
"你因违反《问答版块规则》,已被禁言$bannedType如有疑问请联系客服QQ3467475980",
"关闭", null, null, null)
}
}

View File

@ -0,0 +1,100 @@
package com.gh.common.util
import android.arch.lifecycle.*
import android.content.Context
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.view.ViewPager
import android.view.View
/**
* 创建以 activity 为观察者上下文的 viewModel
*/
inline fun <reified VM : ViewModel> FragmentActivity.viewModelProvider(
provider: ViewModelProvider.Factory
) =
ViewModelProviders.of(this, provider).get(VM::class.java)
/**
* 创建以 fragment 为观察者上下文的 viewModel
*/
inline fun <reified VM : ViewModel> Fragment.viewModelProvider(
provider: ViewModelProvider.Factory
) =
ViewModelProviders.of(this, provider).get(VM::class.java)
/**
*
* ViewPager Extensions
*
*/
fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = addOnPageChangeListener(onSelected = action)
fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = null) {
val listener = object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
// Do nothing.
}
override fun onPageSelected(position: Int) {
onSelected?.invoke(position)
}
override fun onPageScrollStateChanged(state: Int) {
// Do nothing.
}
}
addOnPageChangeListener(listener)
}
/**
* LiveData Extensions
*/
fun <T> LiveData<T?>.observeNonNull(owner: LifecycleOwner, callback: (T) -> Unit) {
observe(owner, Observer { value ->
if (value != null) {
callback(value)
}
})
}
/**
* Login related extensions
*/
fun Fragment.ifLogin(entrance: String, action: (() -> Unit)? = null) {
requireContext().ifLogin(entrance, action)
}
fun Context.ifLogin(entrance: String, action: (() -> Unit)? = null) {
CheckLoginUtils.checkLogin(this, entrance, action)
}
/**
* Gson related extensions.
*/
inline fun <reified T : Any> String.fromObject(): T? {
return try {
GsonUtils.getInstance().mGson.fromJson(this, T::class.java)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
inline fun <reified T : Any> T.toJson(): String {
return GsonUtils.getInstance().mGson.toJson(this)
}
/**
* 快速点击两下
*/
fun fastDoubleClickAction(id: Int, interval: Long = 300, action: (() -> Unit)? = null) {
if (ClickUtils.isFastDoubleClick(id, interval)) {
action?.invoke()
}
}
fun View.fastDoubleClickAction(interval: Long, action: (() -> Unit)? = null) {
fastDoubleClickAction(id, interval, action)
}

View File

@ -6,13 +6,15 @@ import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.widget.TextView;
import com.gh.common.constant.Config;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameCollectionEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
@ -46,13 +48,13 @@ public class GameUtils {
/**
* 设置下载按钮状态
*/
public static void setDownloadBtnStatus(Context context, GameEntity gameEntity, TextView downloadBtn) {
String status = getDownloadBtnText(context, gameEntity);
public static void setDownloadBtnStatus(Context context, GameEntity gameEntity, TextView downloadBtn, PluginLocation pluginLocation) {
String status = getDownloadBtnText(context, gameEntity, pluginLocation);
downloadBtn.setTextColor(Color.WHITE);
downloadBtn.setText(status);
if ("插件化".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
} else if ("打开".equals(status)) {
} else if ("打开".equals(status) || "启动".equals(status)) {
downloadBtn.setBackgroundResource(R.drawable.detail_downloading_normal_style);
downloadBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
} else {
@ -63,22 +65,25 @@ public class GameUtils {
/**
* 获取下载按钮文案
*/
public static String getDownloadBtnText(Context context, GameEntity gameEntity) {
public static String getDownloadBtnText(Context context, GameEntity gameEntity, PluginLocation pluginLocation) {
int doneCount = 0; // 下载完成数量
int pluginCount = 0; // 可插件化数量
int updateCount = 0; // 可更新数量
int installCount = 0; // 已安装数量
DownloadEntity downloadEntity;
Object gh_id;
apkFor:
for (ApkEntity apkEntity : gameEntity.getApk()) {
// 去除下载合集判断
boolean isCollection = false;
for (GameCollectionEntity collectionEntity : gameEntity.getCollection()) {
if (collectionEntity.getPackage().contains(apkEntity.getPackageName()))
isCollection = true;
// filter by packageName
SettingsEntity settings = Config.getSettings();
if (settings != null && gameEntity.getApk().size() > 1) {
for (String pkgName : settings.getGameDownloadBlackList()) {
if (pkgName.equals(apkEntity.getPackageName())) {
continue apkFor;
}
}
}
if (isCollection) continue;
downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity != null) {
@ -90,14 +95,15 @@ public class GameUtils {
updateCount++;
}
}
if (PackageManager.INSTANCE.isCanUpdate(gameEntity.getId(), apkEntity.getPackageName())) {
if (PackagesManager.INSTANCE.isCanUpdate(gameEntity.getId(), apkEntity.getPackageName())) {
updateCount++;
}
if (PackageManager.INSTANCE.isInstalled(apkEntity.getPackageName())) {
if (PackagesManager.INSTANCE.isInstalled(apkEntity.getPackageName())) {
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignature(context, apkEntity.getPackageName())) {
&& !PackageUtils.isSignature(context, apkEntity.getPackageName())
&& apkEntity.isShowPlugin(pluginLocation)) {
pluginCount++;
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
installCount++;
@ -105,15 +111,19 @@ public class GameUtils {
}
}
if (doneCount != 0) {
return "安装";
return context.getString(R.string.install);
} else if (pluginCount != 0) {
return "插件化";
return context.getString(R.string.pluggable);
} else if (updateCount != 0) {
return "更新";
return context.getString(R.string.update);
} else if (installCount != 0) {
return "打开";
if (gameEntity.getApk().size() == 1) {
return context.getString(R.string.launch);
} else {
return context.getString(R.string.open);
}
} else {
return "下载";
return context.getString(R.string.download);
}
}
@ -135,6 +145,7 @@ public class GameUtils {
gameUpdateEntity.setPluggable(true);
gameUpdateEntity.setTag(gameEntity.getTag());
gameUpdateEntity.setBrief(gameEntity.getBrief());
gameUpdateEntity.setPlugin(apkEntity.getPlugin());
return gameUpdateEntity;
}

View File

@ -41,7 +41,7 @@ public class GameViewUtils {
if (i == size - 1) {
view = getGameTagView(context, tag.get(i), 0, tagType, tagStyle.size() > i ? tagStyle.get(i) : null);
} else {
view = getGameTagView(context, tag.get(i), DisplayUtils.dip2px(context, 6), tagType, tagStyle.size() > i ? tagStyle.get(i) : null);
view = getGameTagView(context, tag.get(i), DisplayUtils.dip2px(context, 5), tagType, tagStyle.size() > i ? tagStyle.get(i) : null);
}
if (view != null) {
labelLayout.addView(view);
@ -58,7 +58,7 @@ public class GameViewUtils {
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lparams.rightMargin = rightMargin;
TextView tag = new TextView(context);
tag.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
tag.setTextSize(TypedValue.COMPLEX_UNIT_SP, 9);
tag.setSingleLine(true);
tag.setText(tagStr);
if ("官方版".equals(tagStr) || "已关注".equals(tagStr)) {
@ -80,6 +80,7 @@ public class GameViewUtils {
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
tag.setTextColor(Color.WHITE);
}
gradientDrawable.setCornerRadius(DisplayUtils.dip2px(1.5F));
tag.setBackgroundDrawable(gradientDrawable);
} else {
colorStr = TagUtils.getInstance(context).getColor(tagStr);
@ -90,14 +91,15 @@ public class GameViewUtils {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.TRANSPARENT);
gradientDrawable.setStroke(DisplayUtils.dip2px(context, 0.6f), color);
gradientDrawable.setCornerRadius(DisplayUtils.dip2px(1.5F));
tag.setBackgroundDrawable(gradientDrawable);
tag.setTextColor(color);
}
}
tag.setLayoutParams(lparams);
tag.setPadding(DisplayUtils.dip2px(context, 3),
tag.setPadding(DisplayUtils.dip2px(context, 4),
0,
DisplayUtils.dip2px(context, 3),
DisplayUtils.dip2px(context, 4),
DisplayUtils.dip2px(context, 1));
return tag;
}

View File

@ -0,0 +1,51 @@
package com.gh.common.util
import android.app.Application
import android.text.TextUtils
import com.lightgame.utils.Utils
import com.qq.gdt.action.GDTAction
import org.json.JSONObject
/**
* 广点通辅助类 [https://gitlab.ghzhushou.com/pm/halo-app-issues/issues/403]
*/
object GdtHelper {
const val NETWORK_TYPE = "NETWORK_TYPE"
const val PAGE_TYPE = "PAGE_TYPE"
const val CONTENT_TYPE = "CONTENT_TYPE"
const val CONTENT_ID = "CONTENT_ID"
const val KEYWORD = "KEYWORD"
const val GAME_ID = "GAME_ID"
const val SCORE = "SCORE"
const val PLATFORM = "PLATFORM"
fun init(application: Application) {
GDTAction.init(application, "1107958753", "dff25cc0dcb4a3b9f881a5fd7eec7e8a")
}
fun logAction(type: String) {
GDTAction.logAction(type)
Utils.log("GDT", type)
}
fun logAction(type: String, vararg kv: String?) {
try {
val actionParam = JSONObject()
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
actionParam.put(key, value)
}
}
}
Utils.log("GDT", "$type + [${kv.joinToString(" , ")}]")
GDTAction.logAction(type, actionParam)
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@ -33,13 +33,4 @@ class GsonUtils private constructor() {
fun toJson(any: Any): String {
return mGson.toJson(any)
}
}
// Use Kotlin Extension to do the same trick.
inline fun <reified T : Any> String.fromObject(): T {
return GsonUtils.getInstance().mGson.fromJson(this, T::class.java)
}
inline fun <reified T : Any> T.toJson(): String {
return GsonUtils.getInstance().mGson.toJson(this)
}

View File

@ -231,12 +231,23 @@ object ImageUtils {
*/
@JvmStatic
fun display(view: SimpleDraweeView?, url: String?) {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(getTransformLimitUrl(url, width, view.context))
} else {
view?.post {
view.setImageURI(getTransformLimitUrl(url, view.width, view.context))
url?.let {
// 图片是以 gif 结尾的就
if (it.endsWith(".gif")) {
val controller = Fresco.newDraweeControllerBuilder()
.setUri(url)
.setAutoPlayAnimations(true)
.build()
view?.controller = controller
} else {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(getTransformLimitUrl(url, width, view.context))
} else {
view?.post {
view.setImageURI(getTransformLimitUrl(url, view.width, view.context))
}
}
}
}
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of Siebe Projects samples.
*
* Siebe Projects samples is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Siebe Projects samples is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with Siebe Projects samples. If not, see <http://www.gnu.org/licenses/>.
*/
package com.gh.common.util;
/**
* The observer that will be notified when the height of
* the keyboard has changed
*/
public interface KeyboardHeightObserver {
/**
* Called when the keyboard height has changed, 0 means keyboard is closed,
* >= 1 means keyboard is opened.
*
* @param height The height of the keyboard in pixels
* @param orientation The orientation either: Configuration.ORIENTATION_PORTRAIT or
* Configuration.ORIENTATION_LANDSCAPE
*/
void onKeyboardHeightChanged(int height, int orientation);
}

View File

@ -0,0 +1,170 @@
/*
* This file is part of Siebe Projects samples.
*
* Siebe Projects samples is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Siebe Projects samples is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with Siebe Projects samples. If not, see <http://www.gnu.org/licenses/>.
*/
package com.gh.common.util;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.widget.PopupWindow;
import com.gh.gamecenter.R;
/**
* The keyboard height provider, this class uses a PopupWindow
* to calculate the window height when the floating keyboard is opened and closed.
*/
public class KeyboardHeightProvider extends PopupWindow {
/** The tag for logging purposes */
private final static String TAG = "sample_KeyboardHeightProvider";
/** The keyboard height observer */
private KeyboardHeightObserver observer;
/** The cached landscape height of the keyboard */
private int keyboardLandscapeHeight;
/** The cached portrait height of the keyboard */
private int keyboardPortraitHeight;
/** The view that is used to calculate the keyboard height */
private View popupView;
/** The parent view */
private View parentView;
/** The root activity that uses this KeyboardHeightProvider */
private Activity activity;
/**
* Construct a new KeyboardHeightProvider
*
* @param activity The parent activity
*/
public KeyboardHeightProvider(Activity activity) {
super(activity);
this.activity = activity;
LayoutInflater inflator = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
this.popupView = inflator.inflate(R.layout.popupwindow, null, false);
setContentView(popupView);
setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_RESIZE | LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
parentView = activity.findViewById(android.R.id.content);
setWidth(0);
setHeight(LayoutParams.MATCH_PARENT);
popupView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
if (popupView != null) {
handleOnGlobalLayout();
}
});
}
/**
* Start the KeyboardHeightProvider, this must be called after the onResume of the Activity.
* PopupWindows are not allowed to be registered before the onResume has finished
* of the Activity.
*/
public void start() {
if (!isShowing() && parentView.getWindowToken() != null) {
setBackgroundDrawable(new ColorDrawable(0));
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
}
}
/**
* Close the keyboard height provider,
* this provider will not be used anymore.
*/
public void close() {
this.observer = null;
dismiss();
}
/**
* Set the keyboard height observer to this provider. The
* observer will be notified when the keyboard height has changed.
* For example when the keyboard is opened or closed.
*
* @param observer The observer to be added to this provider.
*/
public void setKeyboardHeightObserver(KeyboardHeightObserver observer) {
this.observer = observer;
}
/**
* Get the screen orientation
*
* @return the screen orientation
*/
private int getScreenOrientation() {
return activity.getResources().getConfiguration().orientation;
}
/**
* Popup window itself is as big as the window of the Activity.
* The keyboard can then be calculated by extracting the popup view bottom
* from the activity window height.
*/
private void handleOnGlobalLayout() {
Point screenSize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(screenSize);
Rect rect = new Rect();
popupView.getWindowVisibleDisplayFrame(rect);
// REMIND, you may like to change this using the fullscreen size of the phone
// and also using the status bar and navigation bar heights of the phone to calculate
// the keyboard height. But this worked fine on a Nexus.
int orientation = getScreenOrientation();
int keyboardHeight = screenSize.y - rect.bottom;
if (keyboardHeight == 0) {
notifyKeyboardHeightChanged(0, orientation);
}
else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
this.keyboardPortraitHeight = keyboardHeight;
notifyKeyboardHeightChanged(keyboardPortraitHeight, orientation);
}
else {
this.keyboardLandscapeHeight = keyboardHeight;
notifyKeyboardHeightChanged(keyboardLandscapeHeight, orientation);
}
}
/**
*
*/
private void notifyKeyboardHeightChanged(int height, int orientation) {
if (observer != null) {
observer.onKeyboardHeightChanged(height, orientation);
}
}
}

View File

@ -3,7 +3,6 @@ package com.gh.common.util;
import android.app.Dialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
@ -11,20 +10,18 @@ import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.LibaoDetailActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
import com.gh.gamecenter.entity.MeEntity;
import com.gh.gamecenter.entity.UserDataLibaoEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.eventbus.EBUISwitch;
import com.gh.gamecenter.geetest.GeetestListener;
import com.gh.gamecenter.geetest.GeetestUtils;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.retrofit.JSONObjectResponse;
@ -36,6 +33,7 @@ import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
@ -216,6 +214,10 @@ public class LibaoUtils {
libaoBtn.setText(R.string.libao_unshelve);
libaoBtn.setTextColor(context.getResources().getColor(R.color.button_gray));
break;
case "check":
libaoBtn.setText(R.string.libao_check);
libaoBtn.setBackgroundResource(R.drawable.button_normal_style);
break;
default:
libaoBtn.setBackgroundResource(R.drawable.button_border_gray);
libaoBtn.setText("异常");
@ -229,77 +231,166 @@ public class LibaoUtils {
String status = libaoEntity.getStatus();
setLiBaoBtnStatus(libaoBtn, status, context);
libaoBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CheckLoginUtils.checkLogin(context, () -> {
// 领取限制
if ("领取".equals(libaoBtn.getText().toString()) || "淘号".equals(libaoBtn.getText().toString())) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context)
.getPlatformName(libaoEntity.getPlatform()) + "";
}
libaoBtn.setOnClickListener(v -> {
String btnStatus = libaoBtn.getText().toString();
CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> {
// 领取限制
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), "关闭", "立即安装"
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
adapter.openDownload();
}
}, null);
if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) {
if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) {
String platform;
if (TextUtils.isEmpty(libaoEntity.getPlatform())) {
platform = "";
} else {
platform = PlatformUtils.getInstance(context)
.getPlatformName(libaoEntity.getPlatform());
}
boolean isExistPlatform = false;
ArrayList<ApkEntity> apk = adapter.getGameEntity().getApk();
for (ApkEntity apkEntity : apk) {
if (TextUtils.isEmpty(libaoEntity.getPlatform())) break;
if (libaoEntity.getPlatform().equals(apkEntity.getPlatform())) {
isExistPlatform = true;
break;
}
}
String dialogContent = context.getString(R.string.ling_rules_dialog, libaoEntity.getGame().getName(), platform);
boolean finalIsExistPlatform = isExistPlatform;
DialogUtils.showWarningDialog(context, "条件不符",
Html.fromHtml(dialogContent), isExistPlatform ? "关闭" : null,
isExistPlatform ? "立即安装" : "关闭",
() -> {
if (finalIsExistPlatform) {
adapter.openDownload(libaoEntity.getPlatform());
}
}, null);
return;
}
}
switch (btnStatus) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
if (!TextUtils.isEmpty(libaoEntity.getDes())) {
DialogUtils.showAlertDialog(v.getContext(), "使用说明",
Html.fromHtml(libaoEntity.getDes()), "关闭", null, null, null);
}
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucced(Object response) {
switch (libaoBtn.getText().toString()) {
case "未开始":
Utils.toast(context, "还没到开始领取时间");
break;
case "查看":
Intent intent = LibaoDetailActivity.getIntent(context, libaoEntity, entrance);
context.startActivity(intent);
break;
case "再领一个":
case "领取":
if ("repeatLing".equals(status)) {
DialogUtils.showWarningDialog(context, "礼包刷新提醒"
, "礼包每天0点刷新换新区或者换新角色需要继续领取礼包的童鞋请于明天0点之后回来即可[再领一个]"
, null, "知道了", null, null);
} else {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance);
}
break;
case "再淘一个":
case "淘号":
if ("repeatTao".equals(status)) {
Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新");
return;
}
final Dialog loadingDialog = DialogUtils.showWaitDialog(context, "淘号中...");
postLibaoTao(context, libaoEntity.getId(), new PostLibaoListener() {
@Override
public void postSucced(Object response) {
if (loadingDialog != null) loadingDialog.dismiss();
if (loadingDialog != null) loadingDialog.dismiss();
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
try {
libaoCode = responseBody.getString("code");
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject responseBody = (JSONObject) response;
String libaoCode = null;
if (TextUtils.isEmpty(libaoCode)) {
try {
libaoCode = responseBody.getString("code");
String detail = responseBody.getString("detail");
switch (detail) {
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
if (TextUtils.isEmpty(libaoCode)) {
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
String detail = responseBody.getString("detail");
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
@ -307,108 +398,25 @@ public class LibaoUtils {
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "淘号异常");
Utils.toast(context, "操作失败");
break;
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
Utils.toast(context, "淘号成功");
libaoEntity.setStatus("taoed");
EventBus.getDefault().post(new EBReuse("libaoChanged"));
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context)));
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "淘号成功"
, Html.fromHtml(context.getString(R.string.taoed_dialog, libaoCode))
, "关闭", " 复制礼包码"
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(new Runnable() {
@Override
public void run() {
Spanned msg = Html.fromHtml(
context.getString(R.string.taoed_copy_dialog
, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}
}, 300);
}
}
}, null);
}
@Override
public void postFailed(Throwable error) {
Utils.log("---" + error.toString());
if (loadingDialog != null) loadingDialog.dismiss();
if (error instanceof HttpException) {
HttpException exception = (HttpException) error;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
String detail = errorJson.getString("detail");
// Utils.toast(context, "返回::" + detail);
switch (detail) {
case "coming":
Utils.toast(context, "礼包领取时间未开始");
break;
case "finish":
Utils.toast(context, "礼包领取时间已结束");
break;
case "fetched":
Utils.toast(context, "你今天已领过这个礼包了, 不能再淘号");
libaoBtn.setText("已淘号");
libaoBtn.setBackgroundResource(R.drawable.libao_taoed_style);
libaoBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.libao_taoed_selector));
libaoEntity.setStatus("taoed");
break;
case "try tao":
case "used up":
DialogUtils.showHintDialog(context, "礼包已领光"
, "手速不够快,礼包已经被抢光了,十分抱歉", "知道了");
break;
case "maintaining":
Utils.toast(context, "网络状态异常,请稍后再试");
break;
case "fail to compete":
Utils.toast(context, "淘号失败,稍后重试");
break;
default:
Utils.toast(context, "操作失败");
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "礼包处理异常" + ex.toString());
}
return;
} else if (exception.code() == 401) {
return;
}
}
Utils.toast(context, "发生异常");
}
});
break;
}
});
}
Utils.toast(context, "发生异常");
}
});
break;
}
});
});
}
@ -450,20 +458,14 @@ public class LibaoUtils {
final String finalLibaoCode = libaoCode;
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, libaoCode))
, "关闭", " 复制礼包码"
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(new Runnable() {
@Override
public void run() {
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}
}, 300);
}
, () -> {
copyLink(finalLibaoCode, context);
if (isInstallRequired) {
libaoBtn.postDelayed(() -> {
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
lunningAppDialog(context
, msg, libaoEntity);
}, 300);
}
}, null);
}
@ -524,12 +526,8 @@ public class LibaoUtils {
return;
} else if (exception.code() == 412) {
// 需要验证
GeetestUtils.getInstance().showDialog(context, new GeetestListener() {
@Override
public void onVerified(String captcha) {
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, captcha, entrance);
}
});
GeetestUtils.getInstance().showDialog(context, captcha ->
libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, captcha, entrance));
return;
} else if (exception.code() == 401) {
return;
@ -557,17 +555,14 @@ public class LibaoUtils {
public static void lunningAppDialog(final Context context, Spanned msg, final LibaoEntity libaoEntity) {
DialogUtils.showWarningDialog(context, "复制成功", msg
, "关闭", "启动游戏"
, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
if (LibaoUtils.isAppInstalled(context, libaoEntity.getPackageName())) {
PackageUtils.launchApplicationByPackageName(context, libaoEntity.getPackageName());
} else {
Utils.toast(context, "请安装游戏:" + libaoEntity.getGame().getName()
+ PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform()) + "");
}
, () -> {
if (LibaoUtils.isAppInstalled(context, libaoEntity.getPackageName())) {
PackageUtils.launchApplicationByPackageName(context, libaoEntity.getPackageName());
} else {
Utils.toast(context, "请安装游戏:" + libaoEntity.getGame().getName()
+ PlatformUtils.getInstance(context).getPlatformName(libaoEntity.getPlatform()) + "");
}
}, null);
}

View File

@ -2,9 +2,12 @@ package com.gh.common.util;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.CommunityEntity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.qa.entity.Questions;
import com.gh.loghub.LogHubUtils;
@ -20,6 +23,24 @@ import org.json.JSONObject;
*/
public class LogUtils {
public static void uploadCommunityArticle(String tracers, String articleId, String articleTitle,
int readTime, CommunityEntity community) {
JSONObject object = new JSONObject();
try {
object.put("subject", "community_article");
object.put("community_id", community.getId());
object.put("community_name", community.getName());
object.put("article_id", articleId);
object.put("article_name", articleTitle);
object.put("tracers", tracers);
object.put("read", readTime);
} catch (JSONException e) {
e.printStackTrace();
}
upload(object);
}
public static void uploadDevice(LunchType launchType) {
JSONObject object = new JSONObject();
Application application = HaloApp.getInstance().getApplication();
@ -27,14 +48,12 @@ public class LogUtils {
object.put("subject", "halo_device");
object.put("launch_time", Utils.getTime(application));
object.put("launch_type", launchType.name());
object.put("network", DeviceUtils.getNetwork(application));
object.put("device_model", android.os.Build.MODEL);
object.put("device_system", android.os.Build.VERSION.RELEASE);
object.put("manufacture", Build.MANUFACTURER);
} catch (JSONException e) {
e.printStackTrace();
}
upload(application, object);
upload(object);
}
public static void uploadAnswerReadTime(String tracers, int readTime, String answerId, Questions questions) {
@ -52,7 +71,7 @@ public class LogUtils {
e.printStackTrace();
}
upload(HaloApp.getInstance().getApplication(), object);
upload(object);
}
public static void uploadQuestionReadTime(String tracers, int readTime, Questions questions) {
@ -69,47 +88,11 @@ public class LogUtils {
e.printStackTrace();
}
upload(HaloApp.getInstance().getApplication(), object);
upload(object);
}
public static void uploadQuestions(Context context, String tracers, Questions questions) {
if (context == null) return;
JSONObject object = new JSONObject();
try {
object.put("community_id", UserManager.getInstance().getCommunity().getId());
object.put("community_name", UserManager.getInstance().getCommunity().getName());
object.put("question_id", questions.getId());
object.put("question_name", questions.getTitle());
object.put("subject", "question");
object.put("tracers", tracers);
} catch (JSONException e) {
e.printStackTrace();
}
upload(context, object);
}
public static void uploadAnswers(Context context, String tracers, Questions questions, String answerId) {
if (context == null) return;
JSONObject object = new JSONObject();
try {
object.put("community_id", UserManager.getInstance().getCommunity().getId());
object.put("community_name", UserManager.getInstance().getCommunity().getName());
object.put("question_id", questions.getId());
object.put("question_name", questions.getTitle());
object.put("subject", "answer");
object.put("tracers", tracers);
object.put("answer_id", answerId);
} catch (JSONException e) {
e.printStackTrace();
}
upload(context, object);
}
public static void uploadSearch(Context context, String searchKey) {
if (TextUtils.isEmpty(searchKey) || context == null) return;
public static void uploadSearch(String searchKey) {
if (TextUtils.isEmpty(searchKey)) return;
JSONObject object = new JSONObject();
try {
@ -121,12 +104,11 @@ public class LogUtils {
e.printStackTrace();
}
upload(context, object);
upload(object);
}
public static void communityRefresh(Context context, int dataCount, boolean manualRefresh) {
if (context == null) return;
public static void communityRefresh(int dataCount, boolean manualRefresh) {
JSONObject object = new JSONObject();
try {
object.put("subject", "community_refresh");
@ -134,50 +116,49 @@ public class LogUtils {
object.put("refresh_type", "recommend");
object.put("refresh_way", manualRefresh ? "manual" : "auto");
object.put("data_count", dataCount);
object.put("user_id", UserManager.getInstance().getUserId());
object.put("network", DeviceUtils.getNetwork(context));
object.put("version", PackageUtils.getPatchVersionName());
object.put("channel", HaloApp.getInstance().getChannel());
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("imei", Util_System_Phone_State.getDeviceId(context));
object.put("device_system", android.os.Build.VERSION.RELEASE);
object.put("device_model", android.os.Build.MODEL);
object.put("time", Utils.getTime(context));
} catch (JSONException e) {
e.printStackTrace();
}
upload(context, object);
upload(object);
}
public static void login(Context context, String loginStep, String loginType) {
if (context == null) return;
public static void login(String loginStep, String loginType, String entrance) {
JSONObject object = new JSONObject();
try {
object.put("entrance", entrance);
object.put("subject", "login");
object.put("step", loginStep);
object.put("login_type", loginType);
object.put("network", DeviceUtils.getNetwork(context));
} catch (JSONException e) {
e.printStackTrace();
}
upload(context, object);
upload(object);
}
private static void upload(Context context, JSONObject object) {
if (context == null) return;
private static void upload(JSONObject object) {
if (BuildConfig.DEBUG) {
Utils.log("LogUtils->" + object.toString());
}
Context context = HaloApp.getInstance().getApplication();
try {
object.put("version", PackageUtils.getPatchVersionName());
object.put("version", PackageUtils.getVersionName());
object.put("channel", HaloApp.getInstance().getChannel());
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
object.put("imei", Util_System_Phone_State.getDeviceId(context));
object.put("time", Utils.getTime(context));
object.put("network", DeviceUtils.getNetwork(context));
object.put("user_id", UserManager.getInstance().getUserId());
object.put("device_system", android.os.Build.VERSION.RELEASE);
object.put("device_model", android.os.Build.MODEL);
object.put("imei", Util_System_Phone_State.getImei(HaloApp.getInstance().getApplication()));
object.put("G_ID", UserManager.getInstance().getDeviceId());
} catch (JSONException e) {
e.printStackTrace();
}
LogHubUtils.uploadLog(DeviceUtils.getIPAddress(context), object);
// 暂时除了曝光外的数据都是扔到 community 这个库的,要是不是这个这个库的话这里要改一下
LogHubUtils.uploadLog(DeviceUtils.getIPAddress(context), object, "community");
}
}

View File

@ -12,6 +12,8 @@ import com.lightgame.utils.Utils;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Iterator;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
@ -104,20 +106,39 @@ public class LoginUtils {
});
}
/**
* 请用 ErrorHelper.handleError 替代本方法
*/
@Deprecated
public static void userPostErrorToast(String errorString, Context context, boolean isQuestion) {
if (TextUtils.isEmpty(errorString)) {
Utils.toast(context, R.string.post_failure_hint);
return;
}
try {
JSONObject errorJson = new JSONObject(errorString);
Iterator<String> iterator = errorJson.keys();
while (iterator.hasNext()) {
String key = iterator.next();
if ("toast".equals(key)) {
Utils.toast(context, errorJson.get(key).toString());
return;
}
}
int errorCode = errorJson.getInt("code");
switch (errorCode) {
case 403018:
Utils.toast(context, R.string.comment_failed_unable);
case 403050:
case 403053:
case 403048:
case 403049:
case 403057:
case 403045:
case 403046:
case 403054:
Utils.toast(context, R.string.comment_failed_userbanned);
break;
case 403051:
@ -135,12 +156,6 @@ public class LoginUtils {
case 403021:
Utils.toast(context, R.string.comment_failed_illegal);
break;
case 403045:
Utils.toast(context, R.string.deny_edit_question);
break;
case 403046:
Utils.toast(context, R.string.deny_edit_answer);
break;
case 403047:
Utils.toast(context, R.string.deny_vote_answer);
break;
@ -148,7 +163,7 @@ public class LoginUtils {
Utils.toast(context, R.string.post_failure_hint);
break;
}
} catch (JSONException e) {
} catch (Exception e) {
Utils.toast(context, R.string.post_failure_hint);
e.printStackTrace();
}
@ -300,7 +315,8 @@ public class LoginUtils {
Utils.toast(context, "403202");
break;
case 400213:
Utils.toast(context, "昵称违规");
case 403016:
Utils.toast(context, "内容违规,请修改后再保存");
break;
case 403801:
Utils.toast(context, "获取验证码太频繁,请稍后再试");

View File

@ -255,6 +255,11 @@ public class MessageShareUtils {
private void wechatSahre() {
Utils.toast(mContext, "分享跳转中...");
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
Utils.toast(mContext, "没安装微信,分享失败");
return;
}
//官方分享
// WXImageObject imgObj = new WXImageObject();
// imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
@ -286,6 +291,11 @@ public class MessageShareUtils {
private void wechatMomentsSahre() {
Utils.toast(mContext, "分享跳转中...");
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
Utils.toast(mContext, "没安装微信,分享失败");
return;
}
WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(mContext.getExternalCacheDir().getPath() + "/ShareImg/" + picName);
WXMediaMessage msg = new WXMediaMessage();

View File

@ -0,0 +1,85 @@
package com.gh.common.util
import android.os.Build
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Phone_State
import com.lightgame.utils.Utils
import com.tencent.stat.StatService
import java.util.*
object MtaHelper {
@JvmStatic
fun onEvent(eventId: String, vararg kv: String?) {
val prop = Properties()
if (kv.size == 1) {
prop.setProperty(kv[0], "")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
@JvmStatic
fun onEventWithTime(eventId: String, time: Int, vararg kv: String?) {
val prop = Properties()
for (i in kv.indices) {
if (i % 2 != 0 || i != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
if (prop.size == 0) return
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}] + last $time seconds")
StatService.trackCustomKVTimeIntervalEvent(HaloApp.getInstance().application, time, eventId, prop)
}
/**
* 这个方法除了记录传进来的入参还会附带一些基本的设备信息
*/
@JvmStatic
fun onEventWithBasicDeviceInfo(eventId: String, vararg kv: String) {
val prop = Properties()
for (i in kv.indices) {
if (i % 2 != 0) {
val key = kv[i - 1]
val value = kv[i]
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
prop.setProperty(key, value)
}
}
}
prop.setProperty("光环版本", BuildConfig.VERSION_NAME)
prop.setProperty("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
prop.setProperty("IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application))
prop.setProperty("机型", Build.MODEL)
prop.setProperty("厂商", Build.MANUFACTURER)
prop.setProperty("Android版本", Build.VERSION.RELEASE)
if (!TextUtils.isEmpty(HaloApp.getInstance().gid)) {
prop.setProperty("GID", HaloApp.getInstance().gid)
}
Utils.log("MTA","$eventId + [${kv.joinToString(" , ")}]")
StatService.trackCustomKVEvent(HaloApp.getInstance().application, eventId, prop)
}
}

View File

@ -52,6 +52,12 @@ public class NetworkUtils {
return false;
}
public static boolean isWifiOr4GOr3GConnected(Context context) {
String network = DeviceUtils.getNetwork(context);
return "WIFI".equals(network) || "4G".equals(network) || "3G".equals(network);
}
/**
* 判断MOBILE网络是否可用
*

View File

@ -0,0 +1,56 @@
package com.gh.common.util
import android.content.Context
import android.content.pm.ApplicationInfo
import com.gh.common.constant.Config
import com.halo.assistant.HaloApp
object PackageHelper {
// 黑名单包名,用于区分像 Xposed Installer 那些工具的包名
var excludePackageNameList = arrayListOf<String>()
var localPackageNameSet = hashSetOf<String>()
get() {
return if (field.isEmpty()) {
field = getAllPackageName(HaloApp.getInstance().application)
field
} else {
field
}
}
@JvmStatic
fun refreshLocalPackageList() {
localPackageNameSet = getAllPackageName(HaloApp.getInstance().application)
}
@JvmStatic
fun initExcludePackageName() {
Config.getSettings()?.gameCommentBlackList?.let {
excludePackageNameList = ArrayList(it)
}
}
/*
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
private fun getAllPackageName(context: Context): HashSet<String> {
val set = HashSet<String>()
return try {
val packageInfos = context.applicationContext.packageManager.getInstalledPackages(0)
for (packageInfo in packageInfos) {
if (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
if (context.packageName != packageInfo.packageName) {
set.add(packageInfo.packageName)
}
}
}
set
} catch (e: Exception) {
e.printStackTrace()
set
}
}
}

View File

@ -11,9 +11,11 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import com.gh.common.constant.Config;
import com.g00fy2.versioncompare.Version;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
@ -42,12 +44,18 @@ public class PackageUtils {
List<GameUpdateEntity> updateList = new ArrayList<>();
boolean isAPluginGame = false;
for (ApkEntity apkEntity : gameEntity.getApk()) {
// 判断是否gh_version是否存在
String gh_version = (String) PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_version");
if (gh_version != null && apkEntity.getGhVersion() != null) {
Object gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
if (gh_version != null && apkEntity.getGhVersion() != null && gh_id != null) {
// 确定这是一个插件游戏
if (!isAPluginGame) isAPluginGame = true;
gh_version = gh_version.substring(2);
if (Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity.getForce()) {
if (Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity.getForce()
&& gh_id.equals(gameEntity.getId())) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
@ -66,6 +74,41 @@ public class PackageUtils {
}
}
// 不是插件游戏
if (!isAPluginGame) {
for (ApkEntity apkEntity : gameEntity.getApkNormal()) {
String versionFromRequest = apkEntity.getVersion();
String versionFromInstalledApp = getVersionByPackage(context, apkEntity.getPackageName());
// 是否需要显示更新
boolean shouldShouldUpdate = apkEntity.getForce();
if (shouldShouldUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
// 根据版本判断是否需要更新
shouldShouldUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
if (shouldShouldUpdate) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTag(gameEntity.getTag());
updateList.add(updateEntity);
}
}
}
}
return updateList;
}
@ -108,6 +151,17 @@ public class PackageUtils {
return null;
}
public static boolean compareSignatureBetweenInstalledAppWithApk(Context context, String packageName, String apkFilePath) {
try {
Signature sig = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0];
Signature releaseSig = context.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_SIGNATURES).signatures[0];
return sig.hashCode() == releaseSig.hashCode();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/*
* 解析签名
*/
@ -128,15 +182,15 @@ public class PackageUtils {
* 启动安装应用程序
*/
public static void launchSetup(final Context context, final String path) {
if (isCanLaunchSetup(context, path)) {
context.startActivity(PackageUtils.getInstallIntent(context, path));
} else {
DialogUtils.showPluginDialog(context, new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
context.startActivity(PackageUtils.getUninstallIntent(context, path));
}
});
try {
if (isCanLaunchSetup(context, path)) {
context.startActivity(PackageUtils.getInstallIntent(context, path));
} else {
DialogUtils.showPluginDialog(context,
() -> context.startActivity(PackageUtils.getUninstallIntent(context, path)));
}
} catch (Exception e) {
Utils.toast(context, e.getMessage());
}
}
@ -149,7 +203,7 @@ public class PackageUtils {
if (TextUtils.isEmpty(packageName)) {
return true;
}
boolean isContain = com.gh.gamecenter.manager.PackageManager.INSTANCE.isInstalled(packageName);
boolean isContain = com.gh.gamecenter.manager.PackagesManager.INSTANCE.isInstalled(packageName);
if (!isContain) {
return true;
}
@ -159,6 +213,11 @@ public class PackageUtils {
return true;
}
// 由于新增了非插件的也能更新的功能,倘若两个签名一样的话就不走下面的光环签名判断了
if (compareSignatureBetweenInstalledAppWithApk(context, packageName, path)) {
return true;
}
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
@ -172,7 +231,15 @@ public class PackageUtils {
if ("smartisan".equals(Build.MANUFACTURER)) {
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, new File(path));
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
}
InstallUtils.getInstance(context).addInstall(getPackageNameByPath(context, path));
return installIntent;
}
@ -226,42 +293,18 @@ public class PackageUtils {
return 0;
}
/**
* 数据统计或反馈用PatchVersionName
* 判断助手是否是第一次启动或版本更新提交的版本号用AppVersionName{@link PackageUtils#getVersionName(Context)}
*
* @return 补丁包版本号
*/
public static String getPatchVersionName() {
return Config.PATCH_VERSION_NAME;
}
/*
* 返回光环助手的版本信息
*/
public static String getVersionName(Context context) {
try {
PackageInfo pkgInfo = context.getApplicationContext().getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return pkgInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
public static String getVersionName() {
return BuildConfig.VERSION_NAME;
}
/*
* 返回光环助手的版本code
*/
public static String getVersionCode(Context context) {
try {
PackageInfo pkgInfo = context.getApplicationContext().getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return String.valueOf(pkgInfo.versionCode);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
public static int getVersionCode() {
return BuildConfig.VERSION_CODE;
}
/*

View File

@ -1,6 +1,7 @@
package com.gh.common.util;
import android.content.Context;
import android.text.TextUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.CommentEntity;
@ -57,27 +58,33 @@ public class PostCommentUtils {
});
}
public static void addAnswerComment(final Context context, final String answerId, final String content,
public static void addAnswerComment(final Context context, final String answerId, final String articleId,
final String articleCommunityId, final String content,
final CommentEntity commentEntity,
final PostCommentListener listener) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content);
Observable<ResponseBody> observable;
if (commentEntity != null) {
observable = RetrofitManager.getInstance(context).getApi().postReplyToAnswerComment(answerId, commentEntity.getId(), body);
if (!TextUtils.isEmpty(articleId)) {
if (commentEntity != null) {
observable = RetrofitManager.getInstance(context).getApi().postReplyToCommunityArticleComment(articleCommunityId,
articleId, commentEntity.getId(), body);
} else {
observable = RetrofitManager.getInstance(context).getApi().postCommentToCommunityArticle(articleCommunityId, articleId, body);
}
} else {
observable = RetrofitManager.getInstance(context).getApi().postNewCommentToAnswer(answerId, body);
if (commentEntity != null) {
observable = RetrofitManager.getInstance(context).getApi().postReplyToAnswerComment(answerId, commentEntity.getId(), body);
} else {
observable = RetrofitManager.getInstance(context).getApi().postNewCommentToAnswer(answerId, body);
}
}
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new JSONObjectResponse() {
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(JSONObject response) {
if (response.length() != 0) {
if (listener != null) {
listener.postSuccess(response);
}
} else {
Utils.toast(context, R.string.post_failure_hint);
public void onResponse(ResponseBody response) {
if (listener != null) {
listener.postSuccess(new JSONObject());// 不需要返回
}
}
@ -90,10 +97,18 @@ public class PostCommentUtils {
});
}
public static void voteAnswerComment(final Context context,final String answerId, final String commentId,
final PostCommentListener listener) {
RetrofitManager.getInstance(context).getApi()
.postVoteAnswerComment(answerId,commentId)
public static void voteAnswerComment(final Context context, final String answerId, String articleId, String articleCommunityId,
final String commentId, final PostCommentListener listener) {
Observable<ResponseBody> observable;
if (!TextUtils.isEmpty(answerId)) {
observable = RetrofitManager.getInstance(context).getApi().postVoteAnswerComment(answerId, commentId);
} else {
observable = RetrofitManager.getInstance(context).getApi().postVoteCommunityArticleComment(articleCommunityId, articleId, commentId);
}
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@ -113,7 +128,7 @@ public class PostCommentUtils {
});
}
public static void addCommentVoto(final Context context, final String commentId,
public static void addCommentVote(final Context context, final String commentId,
final PostCommentListener listener) {
RetrofitManager.getInstance(context).getApi()
.postCommentVote(commentId)
@ -157,7 +172,7 @@ public class PostCommentUtils {
}
public static void postAnswerReportData(final Context context, final String commentId, final String answerId, final String reportData,
final PostCommentListener listener) {
final PostCommentListener listener) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"), reportData);
RetrofitManager.getInstance(context).getApi()
.postReportOfAnswerComment(answerId, commentId, body)
@ -176,6 +191,30 @@ public class PostCommentUtils {
});
}
public static void reportCommunityArticleComment(final Context context,
final String communityId,
final String articleId,
final String commentId,
final String reportData,
final PostCommentListener listener) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"), reportData);
RetrofitManager.getInstance(context).getApi()
.postCommunityArticleCommentReport(communityId, articleId, commentId, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response<ResponseBody>() {
@Override
public void onResponse(ResponseBody response) {
listener.postSuccess(null);
}
@Override
public void onFailure(HttpException e) {
listener.postFailed(e);
}
});
}
public interface PostCommentListener {
void postSuccess(JSONObject response);

View File

@ -0,0 +1,20 @@
package com.gh.common.util
import android.app.ActivityManager
import android.content.Context
object ServiceUtils {
fun isServiceRunningInForeground(context: Context, serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
if (service.foreground) {
return true
}
}
}
return false
}
}

View File

@ -85,7 +85,8 @@ public class ShareUtils {
tools,
askInvite,
askNormal, // 问答问题/答案
shareGh
shareGh,
communityArticle
}
private String[] arrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "新浪微博", "短信", "复制链接", "取消"};
@ -228,6 +229,7 @@ public class ShareUtils {
mSummary += "(光环加速版)";
break;
case askNormal:
case communityArticle:
mTitle += " - 光环助手";
break;
}
@ -249,6 +251,12 @@ public class ShareUtils {
//微信好友分享
private void wechatShare() {
Utils.toast(mContext, R.string.share_skip);
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
Utils.toast(mContext, "没安装微信,分享失败");
return;
}
WXWebpageObject webpage = new WXWebpageObject();
WXMediaMessage msg = new WXMediaMessage(webpage);
webpage.webpageUrl = shareUrl;
@ -258,13 +266,14 @@ public class ShareUtils {
mSummary += "(光环加速版)";
break;
case askNormal:
case communityArticle:
mTitle += " - 光环助手";
break;
}
msg.title = mTitle;
msg.description = mSummary;
msg.description = !TextUtils.isEmpty(mSummary) && mSummary.length() > 1024 ? mSummary.substring(0, 1024) : mSummary;
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("webpage");
@ -358,6 +367,7 @@ public class ShareUtils {
mSummary += "(光环加速版)";
break;
case askNormal:
case communityArticle:
mTitle += " - 光环助手";
break;
}
@ -383,6 +393,12 @@ public class ShareUtils {
//微信朋友圈分享
private void wechatMomentsShare() {
Utils.toast(mContext, R.string.share_skip);
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
Utils.toast(mContext, "没安装微信,分享失败");
return;
}
WXWebpageObject webpage = new WXWebpageObject();
WXMediaMessage msg = new WXMediaMessage(webpage);
@ -396,6 +412,7 @@ public class ShareUtils {
msg.title = mSummary;
break;
case askNormal:
case communityArticle:
msg.title = mTitle + " - 光环助手";
break;
default:
@ -446,6 +463,7 @@ public class ShareUtils {
break;
case askInvite:
case askNormal:
case communityArticle:
smsBody = mTitle + " - 光环助手" + shareUrl;
break;
default:

View File

@ -54,4 +54,17 @@ object SPUtils {
fun getBoolean(key: String): Boolean {
return sp.getBoolean(key, false)
}
@JvmStatic
fun setString(sp: SharedPreferences, key: String, value: String? = null) {
try {
val commitStatus = sp.edit().putString(key, value).commit()
if (!commitStatus) {
sp.edit().putString(key, value).apply()
}
} catch (e: Exception) {
e.printStackTrace()
sp.edit().putString(key, value).apply()
}
}
}

View File

@ -47,6 +47,14 @@ public class StringUtils {
return displayName + "(" + description + ")";
}
public static String eliminateHtmlContent(String s) {
if (TextUtils.isEmpty(s)) return "";
s = Html.fromHtml(s).toString();
s = s.replace("\n", "");
return s;
}
/**
* 截取字符串部分长度,超出的以 "..." 代替
*

View File

@ -0,0 +1,39 @@
package com.gh.common.util
import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import com.gh.gamecenter.R
object TextHelper {
@JvmStatic
fun limitTheLengthOfEditText(editText: EditText, length: Int, exceedCallback: ExceedTextLengthLimitCallback? = null) {
editText.addTextChangedListener(object :TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val tvCount = editText.text.toString().length
if (tvCount > length) {
val str = editText.text.toString().substring(0, length)
editText.setText(str)
editText.setSelection(str.length)
if (!ClickUtils.isFastDoubleClick(R.id.userinfo_nickname_et, 2000)) {
exceedCallback?.onExceed()
}
}
}
})
}
interface ExceedTextLengthLimitCallback {
fun onExceed()
}
}

View File

@ -0,0 +1,20 @@
package com.gh.common.util
/**
* 第三方安装包(即安装包里没有 gh-id的辅助类
*/
object ThirdPartyPackageHelper {
private const val PREFIX = "third_party_package"
@JvmStatic
fun saveGameId(packageName: String, gameId: String) {
SPUtils.setString(PREFIX + packageName, gameId)
}
@JvmStatic
fun getGameId(packageName: String): String {
return SPUtils.getString(PREFIX + packageName, "")!!
}
}

View File

@ -0,0 +1,35 @@
package com.gh.common.view;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.TextView;
public class CustomLinkMovementMethod extends LinkMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
boolean b = super.onTouchEvent(widget, buffer, event);
//解决点击事件冲突问题
if (!b && event.getAction() == MotionEvent.ACTION_UP) {
ViewParent parent = widget.getParent();//处理widget的父控件点击事件
if (parent instanceof ViewGroup) {
return ((ViewGroup) parent).performClick();
}
}
return b;
}
public static CustomLinkMovementMethod getInstance() {
if (sInstance == null)
sInstance = new CustomLinkMovementMethod();
return sInstance;
}
private static CustomLinkMovementMethod sInstance;
}

View File

@ -4,10 +4,10 @@ import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -24,12 +24,13 @@ import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.OnCollectionCallBackListener;
import com.gh.gamecenter.adapter.PlatformPagerAdapter;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.ApkLink;
import com.gh.gamecenter.entity.GameCollectionEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBPackage;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.manager.PackageManager;
import com.gh.gamecenter.manager.PackagesManager;
import com.lightgame.download.DataWatcher;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
@ -87,6 +88,7 @@ public class DownloadDialog implements OnCollectionCallBackListener {
private String entrance;
private String location;
private ExposureEvent traceEvent;
private String mAutoDownloadPlatform;
private final int row = 3;
private final int column = 3;
private boolean isLoadPlatform;
@ -103,12 +105,19 @@ public class DownloadDialog implements OnCollectionCallBackListener {
return instance;
}
// 自动下载并翻到相应页面
public void showPopupWindowAutoDownload(View view, GameEntity gameEntity, String autoDownloadPlatform,
String entrance, String location, ExposureEvent traceEvent) {
mAutoDownloadPlatform = autoDownloadPlatform;
showPopupWindow(view, gameEntity, entrance, location, traceEvent);
}
public void showPopupWindow(View view, GameEntity gameEntity, String entrance, String location) {
showPopupWindow(view, gameEntity, entrance, location, null);
}
public void showPopupWindow(View view, GameEntity gameEntity, String entrance, String location, @Nullable ExposureEvent traceEvent) {
public void showPopupWindow(View view, GameEntity gameEntity, String entrance, String location,
@Nullable ExposureEvent traceEvent) {
if (isShow && (popupWindow == null || !popupWindow.isShowing())) {
isShow = false;
}
@ -122,23 +131,28 @@ public class DownloadDialog implements OnCollectionCallBackListener {
this.location = location;
this.traceEvent = traceEvent;
gameApk = sortApk(new ArrayList<>(gameEntity.getApk()));
gameApk = gameEntity.getApk();
if (gameEntity.getCollection() != null) {
mergeApkCollection(gameEntity);
}
if (gameEntity.getApkLink() != null) {
mergeApkLink(gameEntity);
}
sortApk();
// 一个自定义的布局,作为显示的内容
View contentView = View.inflate(mContext, R.layout.game_download_dialog, null);
TextView title = (TextView) contentView.findViewById(R.id.dialog_title);
TextView title = contentView.findViewById(R.id.dialog_title);
title.setText(gameEntity.getName());
viewPager = (ViewPager) contentView.findViewById(R.id.dialog_viewPager);
dialog_ll_hint = (LinearLayout) contentView.findViewById(R.id.dialog_ll_hint);
dialog_ll_collection = (LinearLayout) contentView.findViewById(R.id.dialog_ll_collection);
dialog_ll_collection_hint = (LinearLayout) contentView.findViewById(R.id.dialog_ll_collection_hint);
collectionViewPager = (ViewPager) contentView.findViewById(R.id.dialog_collection_viewPager);
viewPager = contentView.findViewById(R.id.dialog_viewPager);
dialog_ll_hint = contentView.findViewById(R.id.dialog_ll_hint);
dialog_ll_collection = contentView.findViewById(R.id.dialog_ll_collection);
dialog_ll_collection_hint = contentView.findViewById(R.id.dialog_ll_collection_hint);
collectionViewPager = contentView.findViewById(R.id.dialog_collection_viewPager);
isLoadPlatform = false;
@ -149,32 +163,21 @@ public class DownloadDialog implements OnCollectionCallBackListener {
popupWindow = new PopupWindow(contentView, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, true);
contentView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
contentView.setOnClickListener(v -> popupWindow.dismiss());
contentView.setFocusable(true);
contentView.setFocusableInTouchMode(true);
contentView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0
&& popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
}
return false;
contentView.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0
&& popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
}
return false;
});
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
isShow = false;
EventBus.getDefault().unregister(DownloadDialog.this);
DownloadManager.getInstance(mContext).removeObserver(dataWatcher);
}
popupWindow.setOnDismissListener(() -> {
isShow = false;
EventBus.getDefault().unregister(DownloadDialog.this);
DownloadManager.getInstance(mContext).removeObserver(dataWatcher);
});
popupWindow.setTouchable(true);
@ -193,79 +196,121 @@ public class DownloadDialog implements OnCollectionCallBackListener {
DownloadManager.getInstance(mContext).addObserver(dataWatcher);
}
private ArrayList<ApkEntity> sortApk(ArrayList<ApkEntity> apkList) {
private void sortApk() {
for (ApkEntity apkEntity : gameApk) {
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (apkCollection != null) {
List<ApkEntity> saveApkEntity = apkCollection.getSaveApkEntity();
if (saveApkEntity != null) {
for (ApkEntity entity : saveApkEntity) {
int sortValue = getSortValue(entity);
if (apkEntity.getOrder() < sortValue) {
apkEntity.setOrder(sortValue);
}
}
}
continue;
}
apkEntity.setOrder(getSortValue(apkEntity));
}
Comparator<ApkEntity> comparator = (lhs, rhs) -> rhs.getOrder() - lhs.getOrder();
Collections.sort(gameApk, comparator);
}
private int getSortValue(ApkEntity apkEntity) {
/*
* 安装插件 10
* 插件化下载中 9
* 插件化 8
* 安装更新 7
* 更新下载中 6
* 更新 5
* 安装 4
* 下载中 3
* 启动 2
* 默认有图片1
* 默认无图片0
*/
* 插件化下载中 9
* 插件化 8
* 安装更新 7
* 更新下载中 6
* 更新 5
* 安装 4
* 下载中 3
* 启动 2
* 默认有图片1
* 默认无图片0
*/
DownloadEntity downloadEntity;
String packageName;
Object gh_id;
for (ApkEntity apkEntity : apkList) {
downloadEntity = DownloadManager.getInstance(mContext).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity == null) {
packageName = apkEntity.getPackageName();
if (PackageManager.INSTANCE.isInstalled(packageName)) {
gh_id = PackageUtils.getMetaData(mContext, packageName, "gh_id");
if (gh_id == null || gh_id.equals(gameEntity.getId())) {
if (!PackageUtils.isSignature(mContext, packageName)) {
apkEntity.setOrder(8);
} else if (PackageManager.INSTANCE.isCanUpdate(gameEntity.getId(), packageName)) {
apkEntity.setOrder(5);
} else {
apkEntity.setOrder(2);
}
continue;
String packageName = apkEntity.getPackageName();
DownloadEntity downloadEntity = DownloadManager.getInstance(mContext).getDownloadEntityByUrl(apkEntity.getUrl());
if (downloadEntity == null) {
if (!TextUtils.isEmpty(packageName) && PackagesManager.INSTANCE.isInstalled(packageName)) {
gh_id = PackageUtils.getMetaData(mContext, packageName, "gh_id");
if (gh_id == null || gh_id.equals(gameEntity.getId())) {
if (!PackageUtils.isSignature(mContext, packageName)) {
return 8;
} else if (PackagesManager.INSTANCE.isCanUpdate(gameEntity.getId(), packageName)) {
return 5;
} else {
return 2;
}
}
apkEntity.setOrder(1);
}
if (apkEntity.getOrder() < 1) apkEntity.setOrder(1);
String platform = apkEntity.getPlatform();
int id = PlatformUtils.getInstance(mContext).getPlatformPic(platform);
if (id == 0) {
String path = PlatformUtils.getInstance(mContext).getPlatformPicUrl(platform);
if (path == null) {
apkEntity.setOrder(0);
}
String platform = apkEntity.getPlatform();
int id = PlatformUtils.getInstance(mContext).getPlatformPic(platform);
if (id == 0) {
String path = PlatformUtils.getInstance(mContext).getPlatformPicUrl(platform);
if (path == null) {
return 0;
}
}
} else {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
if (downloadEntity.isPluggable()) {
return 10;
} else if (downloadEntity.isUpdate()) {
return 7;
} else {
return 4;
}
} else {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
if (downloadEntity.isPluggable()) {
apkEntity.setOrder(10);
} else if (downloadEntity.isUpdate()) {
apkEntity.setOrder(7);
} else {
apkEntity.setOrder(4);
}
if (downloadEntity.isPluggable()) {
return 9;
} else if (downloadEntity.isUpdate()) {
return 6;
} else {
if (downloadEntity.isPluggable()) {
apkEntity.setOrder(9);
} else if (downloadEntity.isUpdate()) {
apkEntity.setOrder(6);
} else {
apkEntity.setOrder(3);
}
return 3;
}
}
}
Comparator<ApkEntity> comparator = new Comparator<ApkEntity>() {
@Override
public int compare(ApkEntity lhs, ApkEntity rhs) {
return rhs.getOrder() - lhs.getOrder();
return 0;
}
// 合并ApkLink
private void mergeApkLink(GameEntity gameEntity) {
for (ApkLink apkLink : gameEntity.getApkLink()) {
if (!TextUtils.isEmpty(apkLink.getCollection())) {
for (int i = 0; i < gameApk.size(); i++) {
ApkEntity apkEntity = gameApk.get(i);
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (apkCollection != null && apkCollection.getSaveApkEntity() != null) {
List<ApkEntity> saveApkEntity = apkCollection.getSaveApkEntity();
if (apkLink.getCollection().equals(apkCollection.getId())) {
ApkEntity element = new ApkEntity();
element.setApkLink(apkLink);
if (saveApkEntity.size() > apkLink.getSort()) {
saveApkEntity.add(apkLink.getSort(), element);
} else {
saveApkEntity.add(element);
}
}
}
}
} else {
ApkEntity element = new ApkEntity();
element.setApkLink(apkLink);
if (gameApk.size() > apkLink.getSort()) {
gameApk.add(apkLink.getSort(), element);
} else {
gameApk.add(element);
}
}
};
Collections.sort(apkList, comparator);
return apkList;
}
}
// 合并ApkCollection
@ -289,6 +334,7 @@ public class DownloadDialog implements OnCollectionCallBackListener {
List<ApkEntity> saveApkList = new ArrayList<>();
saveApkList.add(apkEntity);
collectionEntity.setSaveApkEntity(saveApkList);
collectionEntity.setId(gameCollectionEntity.getId());
collectionEntity.setName(gameCollectionEntity.getName());
collectionEntity.setIcon(gameCollectionEntity.getIcon());
collectionEntity.setColor(gameCollectionEntity.getColor());
@ -347,10 +393,34 @@ public class DownloadDialog implements OnCollectionCallBackListener {
if (viewPager != null) {
currentItem = viewPager.getCurrentItem();
}
if (!TextUtils.isEmpty(mAutoDownloadPlatform)) {
for (int i = 0; i < apkList.size(); i++) {
ApkEntity apkEntity = apkList.get(i);
if (mAutoDownloadPlatform.equals(apkEntity.getPlatform())) {
currentItem = (i / 9);
break;
}
GameCollectionEntity apkCollection = apkEntity.getApkCollection();
if (apkCollection != null) {
List<ApkEntity> saveApkEntity = apkCollection.getSaveApkEntity();
if (saveApkEntity != null) {
for (ApkEntity entity : saveApkEntity) {
if (mAutoDownloadPlatform.equals(entity.getPlatform())) {
currentItem = (i / 9);
break;
}
}
}
}
}
}
Utils.log("currentItem = " + currentItem);
adapter = new PlatformPagerAdapter(mContext, this, gameEntity, apkList, entrance, location, traceEvent);
adapter = new PlatformPagerAdapter(mContext, this,
gameEntity, apkList, mAutoDownloadPlatform, entrance, location, traceEvent);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(currentItem);
if (currentItem != 0) setDownloadOvalHint(dialog_ll_hint, currentItem);
}
private void addHintPoint(LinearLayout linearLayout, int size) {
@ -363,7 +433,7 @@ public class DownloadDialog implements OnCollectionCallBackListener {
DisplayUtils.dip2px(mContext, 6), DisplayUtils.dip2px(mContext, 6));
if (i == 0) {
lparams.leftMargin = 0;
imageView.setImageResource(R.drawable.oval_hint_up);
imageView.setImageResource(R.drawable.download_oval_hint_up);
} else {
lparams.leftMargin = DisplayUtils.dip2px(mContext, 9);
imageView.setImageResource(R.drawable.oval_hint_gray_bg);
@ -417,7 +487,8 @@ public class DownloadDialog implements OnCollectionCallBackListener {
public void showCollection(GameCollectionEntity gameCollectionEntity) {
dialog_ll_collection.setVisibility(View.VISIBLE);
int count = gameCollectionEntity.getSaveApkEntity().size();
List<ApkEntity> saveApkList = gameCollectionEntity.getSaveApkEntity();
int count = saveApkList.size();
int vpHeight;
if (count <= 3) {
vpHeight = 82;
@ -432,14 +503,31 @@ public class DownloadDialog implements OnCollectionCallBackListener {
collectionViewPager.setLayoutParams(layoutParams);
dialog_ll_collection_hint.removeAllViews();
int size = (int) Math.ceil(gameCollectionEntity.getSaveApkEntity().size() / (double) (row * column));
int size = (int) Math.ceil(count / (double) (row * column));
addHintPoint(dialog_ll_collection_hint, size);
collectionAdapter = new PlatformPagerAdapter(
mContext, null, gameEntity, gameCollectionEntity.getSaveApkEntity(), entrance, location, traceEvent);
mContext, null, gameEntity, saveApkList,
mAutoDownloadPlatform, entrance, location, traceEvent);
collectionViewPager.setAdapter(collectionAdapter);
collectionViewPager.addOnPageChangeListener(new MyPageChangeListener(dialog_ll_collection_hint));
int currentItem = 0;
if (!TextUtils.isEmpty(mAutoDownloadPlatform)) {
for (int i = 0; i < saveApkList.size(); i++) {
ApkEntity apkEntity = saveApkList.get(i);
if (mAutoDownloadPlatform.equals(apkEntity.getPlatform())) {
currentItem = (i / 9);
break;
}
}
}
if (currentItem != 0) {
collectionViewPager.setCurrentItem(currentItem);
setDownloadOvalHint(dialog_ll_collection_hint, currentItem);
}
mAutoDownloadPlatform = null;
}
// 隐藏合集
@ -464,15 +552,7 @@ public class DownloadDialog implements OnCollectionCallBackListener {
@Override
public void onPageSelected(int position) {
for (int i = 0, size = linearLayout.getChildCount(); i < size; i++) {
if (i == position % size) {
((ImageView) linearLayout.getChildAt(i))
.setImageResource(R.drawable.oval_hint_up);
} else {
((ImageView) linearLayout.getChildAt(i))
.setImageResource(R.drawable.oval_hint_gray_bg);
}
}
setDownloadOvalHint(linearLayout, position);
}
@Override
@ -481,4 +561,16 @@ public class DownloadDialog implements OnCollectionCallBackListener {
}
}
private void setDownloadOvalHint(LinearLayout linearLayout, int position) {
for (int i = 0, size = linearLayout.getChildCount(); i < size; i++) {
if (i == position % size) {
((ImageView) linearLayout.getChildAt(i))
.setImageResource(R.drawable.download_oval_hint_up);
} else {
((ImageView) linearLayout.getChildAt(i))
.setImageResource(R.drawable.oval_hint_gray_bg);
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.gh.common.view
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import com.gh.common.util.DisplayUtils
object DrawableView {
@JvmStatic
fun getServerDrawable(colorCode: String): Drawable {
return getServerDrawable(Color.parseColor(colorCode))
}
@JvmStatic
fun getServerDrawable(colorCode: Int): Drawable {
val drawable = GradientDrawable()
drawable.setColor(colorCode)
drawable.cornerRadius = DisplayUtils.dip2px(2F).toFloat()
return drawable
}
}

View File

@ -7,7 +7,6 @@ import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
@ -26,16 +25,14 @@ public class ExpendTextView extends android.support.v7.widget.AppCompatTextView
private boolean mInitLayout = false;
private boolean mOpenLayout = false;
private ExpandCallback mExpandCallback;
public ExpendTextView(Context context) {
super(context);
}
public ExpendTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpendTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mMaxLines = getMaxLines();
}
@ -55,6 +52,10 @@ public class ExpendTextView extends android.support.v7.widget.AppCompatTextView
this.mExpendText = text;
}
public void setExpandCallback(ExpandCallback callback) {
this.mExpandCallback = callback;
}
@Override
public void setText(CharSequence text, BufferType type) {
mInitLayout = true;
@ -103,11 +104,18 @@ public class ExpendTextView extends android.support.v7.widget.AppCompatTextView
setMaxLines(Integer.MAX_VALUE);
setText(mSnapshotText);
if (mExpandCallback != null) {
mExpandCallback.onExpand();
}
}
}, length - mExpendText.length(), length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(msp);
setMovementMethod(LinkMovementMethod.getInstance());
setMovementMethod(CustomLinkMovementMethod.getInstance());
}
public interface ExpandCallback {
void onExpand();
}
}

View File

@ -0,0 +1,136 @@
package com.gh.common.view;
import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import com.gh.gamecenter.R;
import java.util.ArrayList;
import java.util.List;
public class MessageSpannableTextView extends android.support.v7.widget.AppCompatTextView {
private OnSpannableClickListener mSpannableClickListener;
private final String mStartMarkKey = "{{";
private final String mEndMarkKey = "}}";
private List<MarkData> mMarkList;
public MessageSpannableTextView(Context context) {
super(context);
}
public MessageSpannableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mMarkList = new ArrayList<>();
}
@Override
public void setText(CharSequence text, BufferType type) {
if (TextUtils.isEmpty(text) ||
!text.toString().contains(mStartMarkKey) && !text.toString().contains(mEndMarkKey)) {
super.setText(text, type);
return;
}
mMarkList.clear();
String sText = text.toString();
String[] split = sText.split("\\}\\}");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < split.length; i++) {
String s = split[i];
int p = s.lastIndexOf(mStartMarkKey);
if (p != -1) {
MarkData markData = new MarkData();
String substring = s.substring(p);
String content = s.replace(substring, "");
builder.append(content);
markData.setStart(builder.length() + 1);
String key = substring.replace(mStartMarkKey, " ") + " ";
builder.append(key);
markData.setEnd(builder.length() - 1);
markData.setKey(key);
mMarkList.add(markData);
System.out.println(substring);
System.out.println(s);
} else {
builder.append(s);
if (i != split.length - 1 || sText.substring(sText.length() - 2, sText.length()).equals("}}")) {
builder.append("}}");
}
}
}
SpannableStringBuilder msp = new SpannableStringBuilder(builder);
for (MarkData markData : mMarkList) {
msp.setSpan(new ClickableSpan() {
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(getContext().getResources().getColor(R.color.tag_orange));
ds.setUnderlineText(true);
}
@Override
public void onClick(View widget) {
if (mSpannableClickListener != null) {
mSpannableClickListener.onClick(markData.getKey().trim());
}
}
}, markData.getStart(), markData.getEnd(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
setMovementMethod(CustomLinkMovementMethod.getInstance());
super.setText(msp, type);
}
public void setOnSpannableClickListener(OnSpannableClickListener spannableClickListener) {
this.mSpannableClickListener = spannableClickListener;
}
public interface OnSpannableClickListener {
void onClick(String spannableText);
}
class MarkData {
private int start;
private int end;
private String key;
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
}

View File

@ -0,0 +1,298 @@
package com.gh.common.view
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
import android.media.AudioManager
import android.os.Build
import android.os.Handler
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import cn.jzvd.JZDataSource
import cn.jzvd.JZUtils
import cn.jzvd.Jzvd
import cn.jzvd.JzvdStd
import com.gh.common.observer.MuteCallback
import com.gh.common.observer.VolumeObserver
import com.gh.common.util.DialogUtils
import com.gh.common.util.MtaHelper
import com.gh.common.util.NetworkUtils
import com.gh.gamecenter.R
import com.halo.assistant.HaloApp
import java.util.*
class PlayerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : JzvdStd(context, attrs) {
var showAlertDialogForTheFistTime: Boolean = true
var gameName: String = ""
lateinit var muteIv: ImageView
lateinit var rotateIv: ImageView
val muteCallback = object : MuteCallback {
override fun onMute(isMute: Boolean) {
if (isMute) {
muteIv.setImageResource(R.drawable.ic_volume_off)
} else {
muteIv.setImageResource(R.drawable.ic_volume_on)
}
}
}
var volumeObserver = VolumeObserver(context, Handler(), muteCallback)
override fun init(context: Context?) {
super.init(context)
muteIv = findViewById(R.id.mute)
rotateIv = findViewById(R.id.rotate)
muteIv.setOnClickListener(this)
rotateIv.setOnClickListener(this)
Jzvd.WIFI_TIP_DIALOG_SHOWED = true
}
override fun onClick(v: View) {
if (v.id == R.id.start || v.id == R.id.thumb) {
if (Jzvd.CURRENT_STATE_PLAYING != currentState) {
if ((currentScreen == SCREEN_WINDOW_NORMAL || currentScreen == SCREEN_WINDOW_LIST)) {
MtaHelper.onEvent("游戏详情_新", "视频_点击播放", gameName)
} else {
MtaHelper.onEvent("游戏详情_新", "视频全屏_点击播放", gameName)
}
} else {
MtaHelper.onEvent("游戏详情_新", "视频_点击暂停", gameName)
}
if (showAlertDialogForTheFistTime
&& !NetworkUtils.isWifiConnected(context)
&& currentState != Jzvd.CURRENT_STATE_PLAYING) {
showNetworkAlertDialog()
} else {
super.onClick(v)
}
} else {
super.onClick(v)
when (v.id) {
R.id.rotate -> {
if (Jzvd.FULLSCREEN_ORIENTATION != SCREEN_ORIENTATION_LANDSCAPE) {
Jzvd.FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
JZUtils.setRequestedOrientation(context, Jzvd.FULLSCREEN_ORIENTATION)
} else {
Jzvd.FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
JZUtils.setRequestedOrientation(context, Jzvd.FULLSCREEN_ORIENTATION)
}
MtaHelper.onEvent("游戏详情_新", "视频全屏_点击旋转", gameName)
}
R.id.mute -> {
toggleMute()
}
}
}
}
override fun getLayoutId(): Int {
return R.layout.player_view
}
private fun toggleMute() {
HaloApp.getInstance().isMute = !HaloApp.getInstance().isMute
if (HaloApp.getInstance().isMute) {
mute()
} else {
unmute()
}
}
private fun showNetworkAlertDialog() {
DialogUtils.showAlertDialog(context,
"播放视频",
"您当前使用的网络为2G/3G/4G播放视频将会消耗移动流量确定播放",
"确定",
"取消",
DialogUtils.ConfirmListener {
showAlertDialogForTheFistTime = false
startButton.performClick()
},
null
).show()
}
private fun mute() {
muteIv.setImageResource(R.drawable.ic_volume_off)
// 安卓 6.0 以上 toggle 静音接口,以下将声音置为 0% 或 60%
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE, 0)
} else {
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0)
}
MtaHelper.onEvent("游戏详情_新", "视频_点击静音", gameName)
}
private fun unmute() {
muteIv.setImageResource(R.drawable.ic_volume_on)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_UNMUTE, 0)
} else {
mAudioManager.setStreamVolume(
AudioManager.STREAM_MUSIC,
60 * mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
0)
}
MtaHelper.onEvent("游戏详情_新", "视频_解除静音", gameName)
}
override fun onStatePlaying() {
super.onStatePlaying()
// 默认加载完显示播放信息
if (currentScreen != Jzvd.SCREEN_WINDOW_FULLSCREEN) {
changeUiToPlayingShow()
}
}
override fun onClickUiToggle() {
// 仅在全屏状态下才会 toggle 播放信息
if (currentScreen == Jzvd.SCREEN_WINDOW_FULLSCREEN) {
if (bottomContainer.visibility != View.VISIBLE) {
setSystemTimeAndBattery()
clarity.text = jzDataSource.currentKey.toString()
}
if (currentState == Jzvd.CURRENT_STATE_PREPARING) {
changeUiToPreparing()
if (bottomContainer.visibility == View.VISIBLE) {
} else {
setSystemTimeAndBattery()
}
} else if (currentState == Jzvd.CURRENT_STATE_PLAYING) {
if (bottomContainer.visibility == View.VISIBLE) {
changeUiToPlayingClear()
} else {
changeUiToPlayingShow()
}
} else if (currentState == Jzvd.CURRENT_STATE_PAUSE) {
if (bottomContainer.visibility == View.VISIBLE) {
changeUiToPauseClear()
} else {
changeUiToPauseShow()
}
}
} else {
// 小界面播放中或者准备中的时候点击直接进入全屏
when (currentState) {
Jzvd.CURRENT_STATE_PLAYING,
Jzvd.CURRENT_STATE_PREPARING -> {
startWindowFullscreen()
}
}
}
}
override fun setUp(jzDataSource: JZDataSource?, screen: Int) {
super.setUp(jzDataSource, screen)
batteryTimeLayout.visibility = View.INVISIBLE
// 初始化隐藏和置换一些原有资源
if (currentScreen == SCREEN_WINDOW_NORMAL || currentScreen == SCREEN_WINDOW_LIST) {
progressBar.visibility = View.INVISIBLE
totalTimeTextView.visibility = View.INVISIBLE
muteIv.visibility = View.VISIBLE
rotateIv.visibility = View.GONE
// 将右下角的按钮变成静音与否
if (HaloApp.getInstance().isMute) {
mute()
} else {
unmute()
}
} else {
progressBar.visibility = View.VISIBLE
totalTimeTextView.visibility = View.VISIBLE
muteIv.visibility = View.GONE
rotateIv.visibility = View.VISIBLE
}
}
override fun updateStartImage() {
when (currentState) {
Jzvd.CURRENT_STATE_PLAYING -> {
if (currentScreen == SCREEN_WINDOW_NORMAL || currentScreen == SCREEN_WINDOW_LIST) {
startButton.visibility = View.INVISIBLE
} else {
startButton.visibility = View.VISIBLE
startButton.setImageResource(cn.jzvd.R.drawable.jz_click_pause_selector)
replayTextView.visibility = View.INVISIBLE
}
}
Jzvd.CURRENT_STATE_ERROR -> {
startButton.visibility = View.INVISIBLE
replayTextView.visibility = View.INVISIBLE
}
Jzvd.CURRENT_STATE_AUTO_COMPLETE -> {
startButton.visibility = View.VISIBLE
startButton.setImageResource(cn.jzvd.R.drawable.jz_click_replay_selector)
replayTextView.visibility = View.VISIBLE
}
else -> {
startButton.setImageResource(cn.jzvd.R.drawable.jz_click_play_selector)
replayTextView.visibility = View.INVISIBLE
}
}
}
override fun playOnThisJzvd() {
super.playOnThisJzvd()
if (HaloApp.getInstance().isMute) {
mute()
}
// 处理从全屏跳转回小界面
Jzvd.FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
if (currentScreen == SCREEN_WINDOW_NORMAL || currentScreen == SCREEN_WINDOW_LIST) {
progressBar.visibility = View.INVISIBLE
totalTimeTextView.visibility = View.INVISIBLE
MtaHelper.onEvent("游戏详情_新", "视频全屏_点击后退", gameName)
} else {
progressBar.visibility = View.VISIBLE
totalTimeTextView.visibility = View.VISIBLE
}
}
override fun startWindowFullscreen() {
super.startWindowFullscreen()
unmute()
MtaHelper.onEvent("游戏详情_新", "视频_点击进入全屏", gameName)
}
override fun startDismissControlViewTimer() {
// 仅在全屏是才自动隐藏播放信息
cancelDismissControlViewTimer()
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
DISMISS_CONTROL_VIEW_TIMER = Timer()
mDismissControlViewTimerTask = DismissControlViewTimerTask()
DISMISS_CONTROL_VIEW_TIMER.schedule(mDismissControlViewTimerTask, 3000)
}
}
fun observeVolume(fragment: Fragment?) {
fragment?.context?.applicationContext?.contentResolver?.registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true, volumeObserver)
fragment?.fragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentPaused(fm: FragmentManager?, f: Fragment?) {
if (f === fragment) {
fragment.context?.applicationContext?.contentResolver?.unregisterContentObserver(volumeObserver)
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
}
}
}, false)
}
}

View File

@ -95,6 +95,7 @@ public class RichEditor extends WebView {
private OnTextChangeListener mTextChangeListener;
private OnDecorationStateListener mDecorationStateListener;
private AfterInitialLoadListener mLoadListener;
private WebChromeClientListener mChromeClientListener;
public RichEditor(Context context) {
this(context, null);
@ -119,8 +120,8 @@ public class RichEditor extends WebView {
setVerticalScrollBarEnabled(false);
setHorizontalScrollBarEnabled(false);
getSettings().setJavaScriptEnabled(true);
setWebChromeClient(new WebChromeClient());
setWebViewClient(createWebviewClient());
setWebChromeClient(new WebChromeClient()); // 不要重写这个方法否则无法加载
setWebViewClient(createWebViewClient());
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
setWebContentsDebuggingEnabled(true);
}
@ -129,7 +130,7 @@ public class RichEditor extends WebView {
applyAttributes(context, attrs);
}
protected EditorWebViewClient createWebviewClient() {
protected EditorWebViewClient createWebViewClient() {
return new EditorWebViewClient();
}
@ -145,6 +146,10 @@ public class RichEditor extends WebView {
mLoadListener = listener;
}
public void setChromeClientListener(WebChromeClientListener chromeClientListener) {
mChromeClientListener = chromeClientListener;
}
private void callback(String text) {
mContents = text.replaceFirst(CALLBACK_SCHEME, "");
if (mTextChangeListener != null) {
@ -233,7 +238,7 @@ public class RichEditor extends WebView {
}
public String getHtml() {
return mContents;
return TextUtils.isEmpty(mContents) ? "" : mContents;
}
public void setEditorFontColor(int color) {
@ -393,7 +398,11 @@ public class RichEditor extends WebView {
private void load(String trigger) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
evaluateJavascript(trigger, null);
try {
evaluateJavascript(trigger, null);
} catch (IllegalStateException ignore) {
loadUrl(trigger);
}
} else {
loadUrl(trigger);
}
@ -407,6 +416,10 @@ public class RichEditor extends WebView {
if (mLoadListener != null) {
mLoadListener.onAfterInitialLoad(isReady);
}
if (mChromeClientListener != null) {
mChromeClientListener.onPageFinished(view, url);
}
}
@Override
@ -427,7 +440,18 @@ public class RichEditor extends WebView {
return true;
}
if (mChromeClientListener != null) {
return mChromeClientListener.shouldOverrideUrlLoading(view, url);
}
return super.shouldOverrideUrlLoading(view, url);
}
}
public interface WebChromeClientListener {
void onPageFinished(WebView view, String url);
boolean shouldOverrideUrlLoading(WebView view, String url);
}
}

View File

@ -1277,7 +1277,7 @@ public class SwipeLayout extends FrameLayout {
}
if (currentDragEdge == DragEdge.Left) {
// if (xvel > minVelocity) open(); //TODO 打开侧滑不受侧滑速度限制
// if (xvel > minVelocity) open(); // 打开侧滑不受侧滑速度限制
// else
if (xvel < -minVelocity) close();
else {

View File

@ -18,7 +18,7 @@ public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
private int mIntervalLR;
private boolean mIsShowIntervalTop;
public VerticalItemDecoration(Context context, int interval, boolean isShowIntervalTop) {
public VerticalItemDecoration(Context context, float interval, boolean isShowIntervalTop) {
paint = new Paint();
paint.setColor(ContextCompat.getColor(context, R.color.background));
mInterval = DisplayUtils.dip2px(context, interval);
@ -33,6 +33,14 @@ public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
mIntervalLR = DisplayUtils.dip2px(context, intervalLR);
}
// cutting
public VerticalItemDecoration(Context context, boolean isShowIntervalTop) {
paint = new Paint();
paint.setColor(ContextCompat.getColor(context, R.color.bg_ededed));
mInterval = (int) context.getResources().getDimension(R.dimen.cutting_line);
mIsShowIntervalTop = isShowIntervalTop;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
@ -45,7 +53,7 @@ public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
int bottom = top + mInterval;
if (i == 0 && mIsShowIntervalTop) {
c.drawRect(left + mIntervalLR, 0, right - mIntervalLR, bottom, paint);
c.drawRect(left + mIntervalLR, 0, right - mIntervalLR, mInterval, paint);
} else {
c.drawRect(left + mIntervalLR, top, right - mIntervalLR, bottom, paint);
}

View File

@ -10,10 +10,7 @@ import com.gh.base.fragment.BaseDialogFragment
import com.gh.common.TimeElapsedHelper
import com.gh.common.constant.Constants.SP_LAST_OPENING_ID
import com.gh.common.constant.Constants.SP_LAST_OPENING_TIME
import com.gh.common.util.DataUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.EntranceUtils
import com.gh.common.util.edit
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogWelcomeBinding
import com.gh.gamecenter.entity.CommunityEntity
@ -64,8 +61,9 @@ class WelcomeDialog : BaseDialogFragment() {
DirectUtils.directToQqConversation(context!!, mWelcomeEntity?.link!!)
}
EntranceUtils.HOST_COMMUNITY -> {
DirectUtils.directToCommunity(context!!, CommunityEntity( mWelcomeEntity?.link!!, mWelcomeEntity?.text!!))
DirectUtils.directToCommunity(context!!, CommunityEntity(mWelcomeEntity?.link!!, mWelcomeEntity?.text!!))
}
else -> DialogUtils.showLowVersionDialog(context)
}
mDismissByClickImage = true

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package com.gh.common.view.materialratingbar;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
abstract class BaseDrawable extends Drawable implements TintableDrawable {
protected int mAlpha = 0xFF;
protected ColorFilter mColorFilter;
protected ColorStateList mTintList;
protected PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_IN;
protected PorterDuffColorFilter mTintFilter;
private DummyConstantState mConstantState = new DummyConstantState();
@Override
public int getAlpha() {
return mAlpha;
}
/**
* {@inheritDoc}
*/
@Override
public void setAlpha(int alpha) {
if (mAlpha != alpha) {
mAlpha = alpha;
invalidateSelf();
}
}
/**
* {@inheritDoc}
*/
@Override
public ColorFilter getColorFilter() {
return mColorFilter;
}
/**
* {@inheritDoc}
*/
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mColorFilter = colorFilter;
invalidateSelf();
}
/**
* {@inheritDoc}
*/
@Override
public void setTint(@ColorInt int tintColor) {
setTintList(ColorStateList.valueOf(tintColor));
}
/**
* {@inheritDoc}
*/
@Override
public void setTintList(@Nullable ColorStateList tint) {
mTintList = tint;
if (updateTintFilter()) {
invalidateSelf();
}
}
/**
* {@inheritDoc}
*/
@Override
public void setTintMode(@NonNull PorterDuff.Mode tintMode) {
mTintMode = tintMode;
if (updateTintFilter()) {
invalidateSelf();
}
}
@Override
public boolean isStateful() {
return mTintList != null && mTintList.isStateful();
}
@Override
protected boolean onStateChange(int[] state) {
return updateTintFilter();
}
private boolean updateTintFilter() {
if (mTintList == null || mTintMode == null) {
boolean hadTintFilter = mTintFilter != null;
mTintFilter = null;
return hadTintFilter;
}
int tintColor = mTintList.getColorForState(getState(), Color.TRANSPARENT);
// They made PorterDuffColorFilter.setColor() and setMode() @hide.
mTintFilter = new PorterDuffColorFilter(tintColor, mTintMode);
return true;
}
/**
* {@inheritDoc}
*/
@Override
public int getOpacity() {
// Be safe.
return PixelFormat.TRANSLUCENT;
}
/**
* {@inheritDoc}
*/
@Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
if (bounds.width() == 0 || bounds.height() == 0) {
return;
}
int saveCount = canvas.save();
canvas.translate(bounds.left, bounds.top);
onDraw(canvas, bounds.width(), bounds.height());
canvas.restoreToCount(saveCount);
}
protected ColorFilter getColorFilterForDrawing() {
return mColorFilter != null ? mColorFilter : mTintFilter;
}
protected abstract void onDraw(Canvas canvas, int width, int height);
// Workaround LayerDrawable.ChildDrawable which calls getConstantState().newDrawable()
// without checking for null.
// We are never inflated from XML so the protocol of ConstantState does not apply to us. In
// order to make LayerDrawable happy, we return ourselves from DummyConstantState.newDrawable().
@Override
public ConstantState getConstantState() {
return mConstantState;
}
private class DummyConstantState extends ConstantState {
@Override
public int getChangingConfigurations() {
return 0;
}
@NonNull
@Override
public Drawable newDrawable() {
return BaseDrawable.this;
}
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package com.gh.common.view.materialratingbar;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
class ClipDrawableCompat extends ClipDrawable implements TintableDrawable {
private static final String TAG = ClipDrawableCompat.class.getSimpleName();
private Drawable mDrawable;
private DummyConstantState mConstantState = new DummyConstantState();
public ClipDrawableCompat(Drawable drawable, int gravity, int orientation) {
super(drawable, gravity, orientation);
mDrawable = drawable;
}
@Nullable
@Override
public Drawable getDrawable() {
return mDrawable;
}
@Override
public void setTint(int tintColor) {
if (mDrawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) mDrawable).setTint(tintColor);
} else {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
super.setTint(tintColor);
}
}
@Override
public void setTintList(ColorStateList tint) {
if (mDrawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) mDrawable).setTintList(tint);
} else {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
super.setTintList(tint);
}
}
@Override
public void setTintMode(PorterDuff.Mode tintMode) {
if (mDrawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) mDrawable).setTintMode(tintMode);
} else {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
super.setTintMode(tintMode);
}
}
// Workaround LayerDrawable.ChildDrawable which calls getConstantState().newDrawable()
// without checking for null.
// We are never inflated from XML so the protocol of ConstantState does not apply to us. In
// order to make LayerDrawable happy, we return ourselves from DummyConstantState.newDrawable().
@Override
public ConstantState getConstantState() {
return mConstantState;
}
private class DummyConstantState extends ConstantState {
@Override
public int getChangingConfigurations() {
return 0;
}
@NonNull
@Override
public Drawable newDrawable() {
return ClipDrawableCompat.this;
}
}
}

View File

@ -0,0 +1,662 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package com.gh.common.view.materialratingbar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v7.widget.TintTypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RatingBar;
import com.gh.common.view.materialratingbar.internal.DrawableCompat;
import com.gh.gamecenter.R;
// AppCompatRatingBar will add undesired measuring behavior.
@SuppressLint("AppCompatCustomView")
public class MaterialRatingBar extends RatingBar {
private static final String TAG = MaterialRatingBar.class.getSimpleName();
private TintInfo mProgressTintInfo = new TintInfo();
private MaterialRatingDrawable mDrawable;
private OnRatingChangeListener mOnRatingChangeListener;
private float mLastKnownRating;
public MaterialRatingBar(Context context) {
super(context);
init(null, 0);
}
public MaterialRatingBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public MaterialRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
@SuppressWarnings("RestrictedApi")
private void init(AttributeSet attrs, int defStyleAttr) {
Context context = getContext();
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.MaterialRatingBar, defStyleAttr, 0);
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressTint)) {
mProgressTintInfo.mProgressTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_progressTint);
mProgressTintInfo.mHasProgressTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressTintMode)) {
mProgressTintInfo.mProgressTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_progressTintMode, -1), null);
mProgressTintInfo.mHasProgressTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_secondaryProgressTint)) {
mProgressTintInfo.mSecondaryProgressTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_secondaryProgressTint);
mProgressTintInfo.mHasSecondaryProgressTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_secondaryProgressTintMode)) {
mProgressTintInfo.mSecondaryProgressTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_secondaryProgressTintMode, -1), null);
mProgressTintInfo.mHasSecondaryProgressTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressBackgroundTint)) {
mProgressTintInfo.mProgressBackgroundTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_progressBackgroundTint);
mProgressTintInfo.mHasProgressBackgroundTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_progressBackgroundTintMode)) {
mProgressTintInfo.mProgressBackgroundTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_progressBackgroundTintMode, -1), null);
mProgressTintInfo.mHasProgressBackgroundTintMode = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_indeterminateTint)) {
mProgressTintInfo.mIndeterminateTintList = a.getColorStateList(
R.styleable.MaterialRatingBar_mrb_indeterminateTint);
mProgressTintInfo.mHasIndeterminateTintList = true;
}
if (a.hasValue(R.styleable.MaterialRatingBar_mrb_indeterminateTintMode)) {
mProgressTintInfo.mIndeterminateTintMode = DrawableCompat.parseTintMode(a.getInt(
R.styleable.MaterialRatingBar_mrb_indeterminateTintMode, -1), null);
mProgressTintInfo.mHasIndeterminateTintMode = true;
}
boolean fillBackgroundStars = a.getBoolean(
R.styleable.MaterialRatingBar_mrb_fillBackgroundStars, isIndicator());
a.recycle();
mDrawable = new MaterialRatingDrawable(getContext(), fillBackgroundStars);
mDrawable.setStarCount(getNumStars());
setProgressDrawable(mDrawable);
}
@Override
public void setNumStars(int numStars) {
super.setNumStars(numStars);
// mDrawable can be null during super class initialization.
if (mDrawable != null) {
mDrawable.setStarCount(numStars);
}
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = getMeasuredHeight();
int width = Math.round(height * mDrawable.getTileRatio() * getNumStars());
setMeasuredDimension(View.resolveSizeAndState(width, widthMeasureSpec, 0), height);
}
@Override
public void setProgressDrawable(Drawable d) {
super.setProgressDrawable(d);
// mProgressTintInfo can be null during super class initialization.
if (mProgressTintInfo != null) {
applyProgressTints();
}
}
@Override
public void setIndeterminateDrawable(Drawable d) {
super.setIndeterminateDrawable(d);
// mProgressTintInfo can be null during super class initialization.
if (mProgressTintInfo != null) {
applyIndeterminateTint();
}
}
/**
* @deprecated Use {@link #getSupportProgressTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getProgressTintList() {
logRatingBarTintWarning();
return getSupportProgressTintList();
}
/**
* @deprecated Use {@link #setSupportProgressTintList(ColorStateList)} instead.
*/
@Override
public void setProgressTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportProgressTintList(tint);
}
/**
* @deprecated Use {@link #getSupportProgressTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getProgressTintMode() {
logRatingBarTintWarning();
return getSupportProgressTintMode();
}
/**
* @deprecated Use {@link #setSupportProgressTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportProgressTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportSecondaryProgressTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getSecondaryProgressTintList() {
logRatingBarTintWarning();
return getSupportSecondaryProgressTintList();
}
/**
* @deprecated Use {@link #setSupportSecondaryProgressTintList(ColorStateList)} instead.
*/
@Override
public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportSecondaryProgressTintList(tint);
}
/**
* @deprecated Use {@link #getSupportSecondaryProgressTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getSecondaryProgressTintMode() {
logRatingBarTintWarning();
return getSupportSecondaryProgressTintMode();
}
/**
* @deprecated Use {@link #setSupportSecondaryProgressTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportSecondaryProgressTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportProgressBackgroundTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getProgressBackgroundTintList() {
logRatingBarTintWarning();
return getSupportProgressBackgroundTintList();
}
/**
* @deprecated Use {@link #setSupportProgressBackgroundTintList(ColorStateList)} instead.
*/
@Override
public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportProgressBackgroundTintList(tint);
}
/**
* @deprecated Use {@link #getSupportProgressBackgroundTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getProgressBackgroundTintMode() {
logRatingBarTintWarning();
return getSupportProgressBackgroundTintMode();
}
/**
* @deprecated Use {@link #setSupportProgressBackgroundTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportProgressBackgroundTintMode(tintMode);
}
/**
* @deprecated Use {@link #getSupportIndeterminateTintList()} instead.
*/
@Nullable
@Override
public ColorStateList getIndeterminateTintList() {
logRatingBarTintWarning();
return getSupportIndeterminateTintList();
}
/**
* @deprecated Use {@link #setSupportIndeterminateTintList(ColorStateList)} instead.
*/
@Override
public void setIndeterminateTintList(@Nullable ColorStateList tint) {
logRatingBarTintWarning();
setSupportIndeterminateTintList(tint);
}
/**
* @deprecated Use {@link #getSupportIndeterminateTintMode()} instead.
*/
@Nullable
@Override
public PorterDuff.Mode getIndeterminateTintMode() {
logRatingBarTintWarning();
return getSupportIndeterminateTintMode();
}
/**
* @deprecated Use {@link #setSupportIndeterminateTintMode(PorterDuff.Mode)} instead.
*/
@Override
public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
logRatingBarTintWarning();
setSupportIndeterminateTintMode(tintMode);
}
private void logRatingBarTintWarning() {
if (getContext().getApplicationInfo().minSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
return;
}
Log.w(TAG, "Non-support version of tint method called, this is error-prone and will crash" +
" below Lollipop if you are calling it as a method of RatingBar instead of" +
" MaterialRatingBar");
}
/**
* @see RatingBar#getProgressTintList()
*/
@Nullable
public ColorStateList getSupportProgressTintList() {
return mProgressTintInfo.mProgressTintList;
}
/**
* @see RatingBar#setProgressTintList(ColorStateList)
*/
public void setSupportProgressTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mProgressTintList = tint;
mProgressTintInfo.mHasProgressTintList = true;
applyPrimaryProgressTint();
}
/**
* @see RatingBar#getProgressTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportProgressTintMode() {
return mProgressTintInfo.mProgressTintMode;
}
/**
* @see RatingBar#setProgressTintMode(PorterDuff.Mode)
*/
public void setSupportProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mProgressTintMode = tintMode;
mProgressTintInfo.mHasProgressTintMode = true;
applyPrimaryProgressTint();
}
/**
* @see RatingBar#getSecondaryProgressTintList()
*/
@Nullable
public ColorStateList getSupportSecondaryProgressTintList() {
return mProgressTintInfo.mSecondaryProgressTintList;
}
/**
* @see RatingBar#setSecondaryProgressTintList(ColorStateList)
*/
public void setSupportSecondaryProgressTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mSecondaryProgressTintList = tint;
mProgressTintInfo.mHasSecondaryProgressTintList = true;
applySecondaryProgressTint();
}
/**
* @see RatingBar#getSecondaryProgressTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportSecondaryProgressTintMode() {
return mProgressTintInfo.mSecondaryProgressTintMode;
}
/**
* @see RatingBar#setSecondaryProgressTintMode(PorterDuff.Mode)
*/
public void setSupportSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mSecondaryProgressTintMode = tintMode;
mProgressTintInfo.mHasSecondaryProgressTintMode = true;
applySecondaryProgressTint();
}
/**
* @see RatingBar#getProgressBackgroundTintList()
*/
@Nullable
public ColorStateList getSupportProgressBackgroundTintList() {
return mProgressTintInfo.mProgressBackgroundTintList;
}
/**
* @see RatingBar#setProgressBackgroundTintList(ColorStateList)
*/
public void setSupportProgressBackgroundTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mProgressBackgroundTintList = tint;
mProgressTintInfo.mHasProgressBackgroundTintList = true;
applyProgressBackgroundTint();
}
/**
* @see RatingBar#getProgressBackgroundTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportProgressBackgroundTintMode() {
return mProgressTintInfo.mProgressBackgroundTintMode;
}
/**
* @see RatingBar#setProgressBackgroundTintMode(PorterDuff.Mode)
*/
public void setSupportProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mProgressBackgroundTintMode = tintMode;
mProgressTintInfo.mHasProgressBackgroundTintMode = true;
applyProgressBackgroundTint();
}
/**
* @see RatingBar#getIndeterminateTintList()
*/
@Nullable
public ColorStateList getSupportIndeterminateTintList() {
return mProgressTintInfo.mIndeterminateTintList;
}
/**
* @see RatingBar#setIndeterminateTintList(ColorStateList)
*/
public void setSupportIndeterminateTintList(@Nullable ColorStateList tint) {
mProgressTintInfo.mIndeterminateTintList = tint;
mProgressTintInfo.mHasIndeterminateTintList = true;
applyIndeterminateTint();
}
/**
* @see RatingBar#getIndeterminateTintMode()
*/
@Nullable
public PorterDuff.Mode getSupportIndeterminateTintMode() {
return mProgressTintInfo.mIndeterminateTintMode;
}
/**
* @see RatingBar#setIndeterminateTintMode(PorterDuff.Mode)
*/
public void setSupportIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
mProgressTintInfo.mIndeterminateTintMode = tintMode;
mProgressTintInfo.mHasIndeterminateTintMode = true;
applyIndeterminateTint();
}
private void applyProgressTints() {
if (getProgressDrawable() == null) {
return;
}
applyPrimaryProgressTint();
applyProgressBackgroundTint();
applySecondaryProgressTint();
}
private void applyPrimaryProgressTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasProgressTintList || mProgressTintInfo.mHasProgressTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.progress, true);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mProgressTintList,
mProgressTintInfo.mHasProgressTintList, mProgressTintInfo.mProgressTintMode,
mProgressTintInfo.mHasProgressTintMode);
}
}
}
private void applySecondaryProgressTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasSecondaryProgressTintList
|| mProgressTintInfo.mHasSecondaryProgressTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.secondaryProgress,
false);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mSecondaryProgressTintList,
mProgressTintInfo.mHasSecondaryProgressTintList,
mProgressTintInfo.mSecondaryProgressTintMode,
mProgressTintInfo.mHasSecondaryProgressTintMode);
}
}
}
private void applyProgressBackgroundTint() {
if (getProgressDrawable() == null) {
return;
}
if (mProgressTintInfo.mHasProgressBackgroundTintList
|| mProgressTintInfo.mHasProgressBackgroundTintMode) {
Drawable target = getTintTargetFromProgressDrawable(android.R.id.background, false);
if (target != null) {
applyTintForDrawable(target, mProgressTintInfo.mProgressBackgroundTintList,
mProgressTintInfo.mHasProgressBackgroundTintList,
mProgressTintInfo.mProgressBackgroundTintMode,
mProgressTintInfo.mHasProgressBackgroundTintMode);
}
}
}
private Drawable getTintTargetFromProgressDrawable(int layerId, boolean shouldFallback) {
Drawable progressDrawable = getProgressDrawable();
if (progressDrawable == null) {
return null;
}
progressDrawable.mutate();
Drawable layerDrawable = null;
if (progressDrawable instanceof LayerDrawable) {
layerDrawable = ((LayerDrawable) progressDrawable).findDrawableByLayerId(layerId);
}
if (layerDrawable == null && shouldFallback) {
layerDrawable = progressDrawable;
}
return layerDrawable;
}
private void applyIndeterminateTint() {
Drawable indeterminateDrawable = getIndeterminateDrawable();
if (indeterminateDrawable == null) {
return;
}
if (mProgressTintInfo.mHasIndeterminateTintList
|| mProgressTintInfo.mHasIndeterminateTintMode) {
indeterminateDrawable.mutate();
applyTintForDrawable(indeterminateDrawable, mProgressTintInfo.mIndeterminateTintList,
mProgressTintInfo.mHasIndeterminateTintList,
mProgressTintInfo.mIndeterminateTintMode,
mProgressTintInfo.mHasIndeterminateTintMode);
}
}
// Progress drawables in this library has already rewritten tint related methods for
// compatibility.
@SuppressLint("NewApi")
private void applyTintForDrawable(Drawable drawable, ColorStateList tintList,
boolean hasTintList, PorterDuff.Mode tintMode,
boolean hasTintMode) {
if (hasTintList || hasTintMode) {
if (hasTintList) {
if (drawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) drawable).setTintList(tintList);
} else {
logDrawableTintWarning();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTintList(tintList);
}
}
}
if (hasTintMode) {
if (drawable instanceof TintableDrawable) {
//noinspection RedundantCast
((TintableDrawable) drawable).setTintMode(tintMode);
} else {
logDrawableTintWarning();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable.setTintMode(tintMode);
}
}
}
// The drawable (or one of its children) may not have been
// stateful before applying the tint, so let's try again.
if (drawable.isStateful()) {
drawable.setState(getDrawableState());
}
}
}
private void logDrawableTintWarning() {
Log.w(TAG, "Drawable did not implement TintableDrawable, it won't be tinted below" +
" Lollipop");
}
/**
* Get the listener that is listening for rating change events.
*
* @return The listener, may be null.
*/
public OnRatingChangeListener getOnRatingChangeListener() {
return mOnRatingChangeListener;
}
/**
* Sets the listener to be called when the rating changes.
*
* @param listener The listener.
*/
public void setOnRatingChangeListener(OnRatingChangeListener listener) {
mOnRatingChangeListener = listener;
}
@Override
public synchronized void setSecondaryProgress(int secondaryProgress) {
super.setSecondaryProgress(secondaryProgress);
// HACK: Check and call our listener here because this method is always called by
// updateSecondaryProgress() from onProgressRefresh().
float rating = getRating();
if (mOnRatingChangeListener != null && rating != mLastKnownRating) {
mOnRatingChangeListener.onRatingChanged(this, rating);
}
mLastKnownRating = rating;
}
/**
* A callback that notifies clients when the rating has been changed. This includes changes that
* were initiated by the user through a touch gesture or arrow key/trackball as well as changes
* that were initiated programmatically. This callback <strong>will</strong> be called
* continuously while the user is dragging, different from framework's
* {@link OnRatingBarChangeListener}.
*/
public interface OnRatingChangeListener {
/**
* Notification that the rating has changed. This <strong>will</strong> be called
* continuously while the user is dragging, different from framework's
* {@link OnRatingBarChangeListener}.
*
* @param ratingBar The RatingBar whose rating has changed.
* @param rating The current rating. This will be in the range 0..numStars.
*/
void onRatingChanged(MaterialRatingBar ratingBar, float rating);
}
private static class TintInfo {
public ColorStateList mProgressTintList;
public PorterDuff.Mode mProgressTintMode;
public boolean mHasProgressTintList;
public boolean mHasProgressTintMode;
public ColorStateList mSecondaryProgressTintList;
public PorterDuff.Mode mSecondaryProgressTintMode;
public boolean mHasSecondaryProgressTintList;
public boolean mHasSecondaryProgressTintMode;
public ColorStateList mProgressBackgroundTintList;
public PorterDuff.Mode mProgressBackgroundTintMode;
public boolean mHasProgressBackgroundTintList;
public boolean mHasProgressBackgroundTintMode;
public ColorStateList mIndeterminateTintList;
public PorterDuff.Mode mIndeterminateTintMode;
public boolean mHasIndeterminateTintList;
public boolean mHasIndeterminateTintMode;
}
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package com.gh.common.view.materialratingbar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.support.v7.content.res.AppCompatResources;
import android.view.Gravity;
import com.gh.common.view.materialratingbar.internal.ThemeUtils;
import com.gh.gamecenter.R;
public class MaterialRatingDrawable extends LayerDrawable {
public MaterialRatingDrawable(Context context, boolean fillBackgroundStars) {
super(new Drawable[]{
createLayerDrawableWithTintAttrRes(fillBackgroundStars ?
R.drawable.ic_star
: R.drawable.ic_star_border, fillBackgroundStars ?
R.attr.colorControlHighlight : R.attr.colorControlNormal, context),
fillBackgroundStars ? createClippedLayerDrawableWithTintColor(
R.drawable.ic_star, Color.TRANSPARENT, context)
: createClippedLayerDrawableWithTintAttrRes(
R.drawable.ic_star_border, R.attr.colorControlActivated,
context),
createClippedLayerDrawableWithTintAttrRes(R.drawable.ic_star,
R.attr.colorControlActivated, context)
});
setId(0, android.R.id.background);
setId(1, android.R.id.secondaryProgress);
setId(2, android.R.id.progress);
}
private static Drawable createLayerDrawableWithTintColor(int tileRes, int tintColor,
Context context) {
TileDrawable drawable = new TileDrawable(AppCompatResources.getDrawable(context,
tileRes));
drawable.mutate();
//noinspection RedundantCast
((TintableDrawable) drawable).setTint(tintColor);
return drawable;
}
private static Drawable createLayerDrawableWithTintAttrRes(int tileRes, int tintAttrRes,
Context context) {
int tintColor = ThemeUtils.getColorFromAttrRes(tintAttrRes, context);
return createLayerDrawableWithTintColor(tileRes, tintColor, context);
}
@SuppressLint("RtlHardcoded")
private static Drawable createClippedLayerDrawableWithTintColor(int tileResId, int tintColor,
Context context) {
return new ClipDrawableCompat(createLayerDrawableWithTintColor(tileResId, tintColor,
context), Gravity.LEFT, ClipDrawableCompat.HORIZONTAL);
}
@SuppressLint("RtlHardcoded")
private static Drawable createClippedLayerDrawableWithTintAttrRes(int tileResId,
int tintAttrRes,
Context context) {
return new ClipDrawableCompat(createLayerDrawableWithTintAttrRes(tileResId, tintAttrRes,
context), Gravity.LEFT, ClipDrawableCompat.HORIZONTAL);
}
@SuppressLint("RtlHardcoded")
private static Drawable createClippedTransparentLayerDrawable() {
return new ClipDrawableCompat(new TileDrawable(new ColorDrawable(Color.TRANSPARENT)),
Gravity.LEFT, ClipDrawableCompat.HORIZONTAL);
}
public float getTileRatio() {
Drawable drawable = getTileDrawableByLayerId(android.R.id.progress).getDrawable();
return (float) drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
}
public void setStarCount(int count) {
getTileDrawableByLayerId(android.R.id.background).setTileCount(count);
getTileDrawableByLayerId(android.R.id.secondaryProgress).setTileCount(count);
getTileDrawableByLayerId(android.R.id.progress).setTileCount(count);
}
@SuppressLint("NewApi")
private TileDrawable getTileDrawableByLayerId(int id) {
Drawable layerDrawable = findDrawableByLayerId(id);
switch (id) {
case android.R.id.background:
return (TileDrawable) layerDrawable;
case android.R.id.secondaryProgress:
case android.R.id.progress: {
ClipDrawableCompat clipDrawable = (ClipDrawableCompat) layerDrawable;
return (TileDrawable) clipDrawable.getDrawable();
}
default:
// Should never reach here.
throw new RuntimeException();
}
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package com.gh.common.view.materialratingbar;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
class TileDrawable extends BaseDrawable {
private Drawable mDrawable;
private int mTileCount = -1;
public TileDrawable(Drawable drawable) {
mDrawable = drawable;
}
public Drawable getDrawable() {
return mDrawable;
}
public int getTileCount() {
return mTileCount;
}
public void setTileCount(int tileCount) {
mTileCount = tileCount;
invalidateSelf();
}
@NonNull
@Override
public Drawable mutate() {
mDrawable = mDrawable.mutate();
return this;
}
@Override
protected void onDraw(Canvas canvas, int width, int height) {
mDrawable.setAlpha(mAlpha);
ColorFilter colorFilter = getColorFilterForDrawing();
if (colorFilter != null) {
mDrawable.setColorFilter(colorFilter);
}
int tileHeight = mDrawable.getIntrinsicHeight();
float scale = (float) height / tileHeight;
canvas.scale(scale, scale);
float scaledWidth = width / scale;
if (mTileCount < 0) {
int tileWidth = mDrawable.getIntrinsicWidth();
for (int x = 0; x < scaledWidth; x += tileWidth) {
mDrawable.setBounds(x, 0, x + tileWidth, tileHeight);
mDrawable.draw(canvas);
}
} else {
float tileWidth = scaledWidth / mTileCount;
for (int i = 0; i < mTileCount; ++i) {
int drawableWidth = mDrawable.getIntrinsicWidth();
float tileCenter = tileWidth * (i + 0.5f);
float drawableWidthHalf = (float) drawableWidth / 2;
mDrawable.setBounds(Math.round(tileCenter - drawableWidthHalf), 0,
Math.round(tileCenter + drawableWidthHalf), tileHeight);
mDrawable.draw(canvas);
}
}
}
}

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