Compare commits

...

597 Commits
v3.3.1 ... v3.6

Author SHA1 Message Date
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
3cdc76b548 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-09 18:50:47 +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
b56ecfbf8f 优化开服表提示 2018-09-07 18:38:11 +08:00
42d0f3cf74 更改 targetSDK 至27和更新 MTA 库 2018-09-07 18:07:17 +08:00
27c0b4c497 还原 targetSdk 以及 MTA 更新 2018-09-07 17:57:07 +08:00
de1558d58f 提高 targetSDK 至 8.1,升级 MTA 版本 2018-09-07 14:53:37 +08:00
0197355126 Merge remote-tracking branch 'origin/dev' into dev 2018-09-07 11:07:34 +08:00
e66698d2bd 处理推送的通道问题 2018-09-07 11:07:14 +08:00
def5996c49 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-06 16:30:33 +08:00
700fd2e390 关注,粉丝增加分页 2018-09-06 16:30:24 +08:00
21a8eaafeb 去掉推送机型通道 2018-09-06 16:28:53 +08:00
4391891999 更改dexOptions 2018-09-06 10:47:00 +08:00
8302e8b5e0 修复游戏动态“推荐关注”无法出现问题 2018-09-06 10:02:15 +08:00
a8de52d5cd 修复游戏详情开服提示与开服日历底部对不齐问题,修改UmengMessageReceiver的启动方式 2018-09-05 16:05:05 +08:00
46a42c9212 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-05 09:34:15 +08:00
9ed97ea32c tinkerPatchName -> 3.4.1 2018-09-05 09:33:52 +08:00
4f087cdcc7 Merge remote-tracking branch 'origin/dev' into dev 2018-09-04 19:32:19 +08:00
4c4fcba2d2 修复推送的一些问题 2018-09-04 19:32:06 +08:00
69e9bfa7a9 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-04 16:22:52 +08:00
c3b29697bc 更改刷新Token失败处理顺序 2018-09-04 16:22:44 +08:00
f0937e8d1e 修复了点击专题大图带的路径的是游戏名字而不是专题名字的问题 2018-09-04 15:55:21 +08:00
85f713dc2d Merge remote-tracking branch 'origin/dev' into dev 2018-09-04 12:03:50 +08:00
cd146366c0 修复曝光事件统计插件升级时没有附带游戏名字的问题 2018-09-04 12:03:29 +08:00
08054ad6e5 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-04 11:34:02 +08:00
011b4b536a 修复Gif图片保存失败问题 2018-09-04 11:33:30 +08:00
d2e118180c 完善推送的内容过滤功能以及记录点击和忽略通知事件 2018-09-04 10:26:05 +08:00
93856925ba 更换个人主页问题和答案接口,修复Gif(文件名不是.gif)上传后显示成普通图片问题 2018-09-04 10:02:37 +08:00
da0a33798b Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-09-03 17:08:39 +08:00
33f4f2e60b 修复3.4闪退问题 2018-09-03 17:08:27 +08:00
5827583edc 修复一个 MTA 的统计多个参数时出现的 BUG 2018-09-03 14:28:02 +08:00
2b33d95329 修复一个 MTA 的统计 Bug 2018-09-03 09:52:27 +08:00
7f0be97170 去除无关内容 2018-08-31 01:22:18 +08:00
b6a0fa9196 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-31 01:04:33 +08:00
52c624e94b 修复游戏详情闪退 开服表UI优化 2018-08-31 01:04:22 +08:00
de847ac0d5 Merge remote-tracking branch 'origin/dev' into dev 2018-08-31 00:59:49 +08:00
2bb579fec7 修复了重复通知复用的问题 2018-08-31 00:59:38 +08:00
6a6b15fb14 修复游戏详情闪退 游戏新闻回退 2018-08-30 22:46:54 +08:00
81e6778148 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-30 21:25:18 +08:00
309a6a6425 ConnTimeout->5 2018-08-30 21:24:50 +08:00
65e5ca64a1 修复点击启动弹窗闪退的问题 2018-08-30 21:20:32 +08:00
69825d33ff 新增收到客服新信息时永远显示客服浮窗 2018-08-30 21:18:18 +08:00
ec4acd0043 修复图片无法保存问题 2018-08-30 20:30:52 +08:00
22bb168e49 合并 2018-08-30 20:17:11 +08:00
b7bea01eb1 修改okhttp超时时间,.如果数值超过10000-19999的全部统一显示为1.0W-1.9W 2018-08-30 20:16:24 +08:00
82c3591d25 部分接口增加 channel 字段 2018-08-30 20:02:58 +08:00
20d8de32ec 修复图片不能保存的问题 2018-08-30 19:54:10 +08:00
3976646f39 修复 IM 客服消息不及时的问题 2018-08-30 17:25:04 +08:00
c849d4e0b0 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-30 17:09:58 +08:00
671fab2fee 用户相关部分接口加上时间戳,修复答案编写时会上次本地图片链接问题 2018-08-30 17:09:53 +08:00
8491609da7 增加网络错误的 MTA 统计 2018-08-30 17:06:23 +08:00
67257748f9 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-30 15:52:40 +08:00
312a3fe7bb 修复搜索列表下载无法更新进度问题 2018-08-30 15:52:25 +08:00
2c16c54c96 增加 UI Executor 类 2018-08-30 15:51:30 +08:00
bbae5f0b9c 补充 MTA 统计事件 2018-08-30 14:06:23 +08:00
95022da700 修复从不同位置进入游戏详情显示不一致的问题 2018-08-30 10:00:17 +08:00
6471e95077 光环助手V3.4 RELEASE(20180828-1850)测试问题汇总(UI部分完成) 2018-08-29 20:26:14 +08:00
707e6f5d11 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-29 17:06:56 +08:00
66dfcc8064 个人主页的某些接口添加渠道号 2018-08-29 17:06:41 +08:00
0400b7d396 修复了消息弹窗标记已读造成的问题 2018-08-29 14:54:01 +08:00
96d4ca43ff Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-29 14:37:09 +08:00
d2c0699b66 UI微调 2018-08-29 14:36:35 +08:00
0e4cf2cd3a 修复 MTA 上报内容带有 HTML 元素的问题 2018-08-29 11:39:27 +08:00
8144a7e857 补充 MTA 统计需求 2018-08-29 11:03:43 +08:00
ea38698ac3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-28 18:42:36 +08:00
d00b34ebdd 光环助手V3.4 RELEASE(20180828-0950)测试问题汇总 2018-08-28 18:42:21 +08:00
a4c285df6f 增加新补充的 MTA 统计需求 2018-08-28 17:50:20 +08:00
6dfd9d5b7a Rxjava merge->mergeDelayError 2018-08-28 17:41:05 +08:00
876f7317a8 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-28 14:23:32 +08:00
430a975e98 修复礼包淘号接口 2018-08-28 14:23:22 +08:00
f277319019 统一跳转至社区的逻辑,补充部分方法描述 2018-08-28 11:13:02 +08:00
6b9fedd289 Merge remote-tracking branch 'origin/dev' into dev 2018-08-28 08:39:55 +08:00
d0ad48ada2 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-27 20:21:40 +08:00
a6b7beed75 光环助手V3.4 RELEASE(20180827-0940)测试问题汇总 2018-08-27 20:21:12 +08:00
fa257e4a04 启动弹窗在下载完图片才弹出来 2018-08-27 19:59:19 +08:00
8d827b7275 Merge remote-tracking branch 'origin/dev' into dev 2018-08-27 19:18:30 +08:00
27d73b545c 完成 MTA 事件统计需求 2018-08-27 19:18:19 +08:00
7802d961a3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-27 17:43:13 +08:00
d5d63371e3 修改退出登录逻辑 2018-08-27 17:43:05 +08:00
fcf1d38578 优化消息弹窗显示逻辑 2018-08-27 16:17:19 +08:00
fe17f817da 修复在 Mumu 模拟器上的一些 bug 2018-08-27 14:55:26 +08:00
bfa76c0fda Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-27 10:40:51 +08:00
2e1a99f905 个人动态时间格式修改 2018-08-27 10:39:47 +08:00
e7cb8e41b5 修复系统推送不能通过游戏报名进行限制的 bug 2018-08-27 09:52:40 +08:00
f88d4bde45 光环助手V3.4最后优化需求汇总(20180824) 2018-08-27 09:33:04 +08:00
b470194807 光环助手V3.4最后优化需求汇总(20180824) 2018-08-25 17:13:26 +08:00
ba5e3cb3eb 光环助手V3.4 RELEASE(20180823-1835)测试问题汇总 2018-08-25 15:30:15 +08:00
d5440b5d01 光环助手V3.4 UI优化汇总(20180823) 2018-08-25 11:00:49 +08:00
a8f3f27fb3 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-25 09:48:19 +08:00
bec06bfbf4 部分UI修改 2018-08-25 09:45:39 +08:00
9c510dc132 调整部分 UI 2018-08-24 19:05:36 +08:00
8302c99d57 增加部分 MTA 统计,修复部分 IM 的问题 2018-08-24 17:07:26 +08:00
5209e5b463 更新消息中心接口 2018-08-24 16:49:02 +08:00
663e5124fe 更新消息中心接口 2018-08-24 16:47:08 +08:00
dea2f569a1 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-23 18:18:40 +08:00
03d25eaeae 光环助手V3.4 RELEASE(20180821-1740)测试问题汇总 2018-08-23 18:18:32 +08:00
e84f56975d 修复一些客服 IM 的问题 2018-08-23 18:17:11 +08:00
a3a21efba3 避免七陌 SDK 的 emoji 在精简代码时被精简掉 2018-08-23 16:43:16 +08:00
1daa4f91b3 修复一部分社区跳转和消息通知的 bug 2018-08-23 15:45:39 +08:00
ee1ddbcdce 完成对 MTA 已有统计事件的优化,新事件待补充 http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/316 2018-08-23 09:56:59 +08:00
772549e543 解决游戏名字过长显示不全的问题 2018-08-22 17:37:01 +08:00
db537e756a 修正魅族推送的 ID 2018-08-22 15:35:27 +08:00
f9c236fd63 修复曝光统计的一些问题 2018-08-22 15:34:31 +08:00
f414ecee32 APP统计-应用数据, 数据库升级适配 2018-08-22 10:44:56 +08:00
5b1d0d5821 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
2018-08-21 17:33:26 +08:00
1c80ba56a5 光环助手V3.4 DEV(20180817-1930)测试问题汇总 2018-08-21 17:31:17 +08:00
a92044f815 去掉无用的 SO 支持,修复 IM 反馈没有内容的问题 2018-08-21 16:24:13 +08:00
00f94bf950 修复推荐入口不能跳社区的问题 2018-08-21 14:43:14 +08:00
e27f061a92 修复一些消息弹窗的问题 2018-08-21 14:29:49 +08:00
40d28948e1 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-20 18:08:59 +08:00
9b6e29d5f2 整理社区搜索相关页面 2018-08-20 18:08:47 +08:00
0ee000f08a 修复一些启动弹窗和客服 IM 的测试问题 2018-08-20 16:15:29 +08:00
6bdd021856 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-20 16:05:23 +08:00
301e14268a 光环助手V3.4 DEV(20180810)测试问题汇总 2018-08-20 16:05:11 +08:00
825ea594f4 修复社区的一些显示 bug 2018-08-20 11:37:39 +08:00
8fcb072abb 3.4数据统计需求(APP统计-应用数据 未完成) 2018-08-20 10:39:41 +08:00
f17a4e6372 完成关于问题详情和答案详情的 MTA 时间统计 2018-08-19 15:15:34 +08:00
a5b1202e5e AskLogUtils -> LogUtils 2018-08-17 15:43:52 +08:00
b5e025984c 禁言功能优化 2018-08-17 15:33:04 +08:00
33dba4e9bf Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-16 19:01:37 +08:00
92492b21ae 压缩算法优化 2018-08-16 19:01:25 +08:00
1c8ca4b8c2 补充跳转到社区的逻辑 2018-08-16 17:32:03 +08:00
466061222d UI微调 2018-08-16 17:03:24 +08:00
905e229142 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-16 16:31:09 +08:00
6906b96ef9 修复部分手机在答案编辑页面无法复制问题 2018-08-16 16:30:56 +08:00
fb748df3ce 增加退出 IM 聊天页面确认弹窗 2018-08-16 10:06:40 +08:00
844de786d0 光环助手V3.4优化需求汇总(20180814)(部分完成) 2018-08-15 18:45:19 +08:00
7dfe55014a IM 使用 Fresco 来显示图片 2018-08-15 18:24:40 +08:00
24f19e2a61 IM部分注册/反注册 位置修改 2018-08-15 15:28:47 +08:00
f947040241 IM 处理客服关闭聊天广播 2018-08-15 14:57:59 +08:00
569bb61545 简单集成七陌的客服 IM SDK,细节待完善 2018-08-15 14:33:31 +08:00
78ea8b3e73 光环助手V3.4优化需求汇总(20180814)(部分完成) 2018-08-15 11:42:12 +08:00
6b5056da41 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-14 17:43:10 +08:00
2a86546f1a 光环助手V3.4-意见反馈优化(完成) 2018-08-14 17:42:55 +08:00
d669fec902 意见反馈部分页面完成 2018-08-14 11:27:18 +08:00
3fc14b5194 修复 Webview 链接使用 HTTPS 但图片是 HTTP 时图片不加载的问题 2018-08-14 11:12:42 +08:00
4a3a039d0e 答案列表不显示Gif,优化消息中心(预防串行问题), 登录失败统计优化 2018-08-13 16:03:13 +08:00
1f43523f04 修复图片加载刷新后闪屏问题, 修复若干bug 2018-08-12 15:43:58 +08:00
26e23fa736 图片加载移动网络是先检查大图缓存再加载 2018-08-10 18:27:03 +08:00
958bce8d42 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-10 15:45:20 +08:00
8f15e52eb5 优化用户头像修改压缩上传 2018-08-10 15:44:06 +08:00
4bedede646 删掉网易七鱼相关代码 2018-08-10 14:11:32 +08:00
f66ee1721e Gif不受查看大图控制 2018-08-10 11:15:20 +08:00
138c5bb4c2 解决Fresco缓存查询异常问题 2018-08-10 10:13:05 +08:00
d1245a9a1e 去除RichEditor无用代码 2018-08-09 16:57:42 +08:00
561d6f7ea2 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-09 16:51:19 +08:00
d5992f7ed3 图片下发分类(小图:2G/3G 下发, 大图:4G/WiFi 下发) 2018-08-09 16:51:09 +08:00
d941aa0c71 基本完成启动时读取 META-INFO 里的 JSON 实现跳转的功能 2018-08-09 15:54:21 +08:00
7fa1d1e11b 【图片高清计划】前端加载图片显示规则优化 2018-08-08 18:31:53 +08:00
3edff028bf 图片详情和答案详情适配Gif 2018-08-08 15:15:43 +08:00
78d3c529c6 图片详情增加下载原图,答案详情对接新的图片显示规则 2018-08-08 09:43:11 +08:00
f0af2e280b 合并 2018-08-07 11:51:47 +08:00
34623163e6 重构图片详情, ImageUtils remove Companion 2018-08-07 11:47:51 +08:00
c90bd007c7 完善启动弹窗跳转逻辑 2018-08-07 10:28:38 +08:00
5f9637ec50 QQ 跳转适配 TIM 2018-08-07 10:23:25 +08:00
1a05e13b03 将 QQUtils 功能合并到 DirectUtils 2018-08-07 10:09:32 +08:00
c835f88695 新增启动页弹窗 2018-08-07 09:22:10 +08:00
5674fe76a2 压缩关键参数后台可以控制 2018-08-06 15:43:07 +08:00
e6933b4ded 删除无用代码 2018-08-06 09:36:03 +08:00
8a10dac03d 增加上传进度(目前只对接了:答案图片上传,问题图片上传) 2018-08-03 18:28:32 +08:00
de71ebad52 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-02 18:12:13 +08:00
310d1a2d5c 增加图片压缩工具类 2018-08-02 18:12:02 +08:00
30fcaf190b 新增存在未读消息弹出消息弹窗的功能 2018-08-02 15:44:50 +08:00
f004b15cf0 回答详情页增加认证icon 2018-08-02 10:59:43 +08:00
480c91feb5 处理推送透传信息 2018-08-02 10:16:32 +08:00
2c70b7eefc Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-08-01 18:05:53 +08:00
2be2513081 完善个人主页相关数据 2018-08-01 17:58:58 +08:00
48c0d5d2cd 去掉 8.0 设备获取 IMEI 时添加的叹号 2018-08-01 14:55:14 +08:00
3c5a6bcdec Merge remote-tracking branch 'origin/dev' into dev 2018-08-01 14:45:51 +08:00
bd2a3d529a 完成部分推送逻辑 2018-08-01 14:45:34 +08:00
6c0ac67cfa 对接社区相关搜索接口 2018-08-01 14:44:32 +08:00
cb07b8c9f4 支持从相关页面进入个人主页 2018-08-01 11:11:59 +08:00
e22be3f233 整理游戏详情动态文件 2018-07-31 17:42:28 +08:00
fd02f120c2 ... 2018-07-31 16:55:46 +08:00
6496b3dad6 合并 2018-07-31 16:50:14 +08:00
375b57cd3d 游戏详情增加答案数据 重构游戏详情动态(动态)页面 2018-07-31 16:44:13 +08:00
269265b054 基本完成推送逻辑 2018-07-31 14:52:34 +08:00
d74154080b 修复通过 URI 跳转至回答详情以及问答详情失效的问题 2018-07-31 14:21:16 +08:00
7471825a7c 用户操作历史增加跳转 2018-07-28 17:17:54 +08:00
90580316e8 个人中心增加'个性签名' 2018-07-28 16:38:41 +08:00
61e0ef2960 个人主页粉丝未读提示完成(未经过测试) 2018-07-28 15:53:34 +08:00
1125bb9b4c 个人主页对接数据 2018-07-28 14:50:28 +08:00
1e424a3791 修复由于layout id造成的打包错误 2018-07-27 16:01:18 +08:00
a901d95895 为用户头像添加认证 2018-07-27 15:41:01 +08:00
1a0a92c542 我的主页增加Ta的答案/Ta的问题 2018-07-27 15:30:15 +08:00
6ba8344292 完善社区搜索页面 2018-07-26 17:02:43 +08:00
38d2429183 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev
# Conflicts:
#	app/src/main/res/layout/personal_home_top.xml
2018-07-26 14:57:06 +08:00
36c755f781 我的光环-新增个人主页功能(完善ListActivity,相关页面的优化) 2018-07-26 14:53:43 +08:00
093c731ba7 去掉设置暗色状态栏时反射出错的日志记录 2018-07-26 11:48:02 +08:00
eae9c11d72 提取用户认证的公用部分 2018-07-26 11:46:48 +08:00
3faae4b34c Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-07-25 18:42:15 +08:00
04eef35cbd 我的光环-新增个人主页功能(页面基本完成) 2018-07-25 18:42:04 +08:00
6b08cb2159 消息通知弹窗支持滑动清除 2018-07-25 11:05:20 +08:00
0777ca90e0 处理消息通知弹窗在使用虚拟按键的设备上的位置错误问题 2018-07-24 18:00:26 +08:00
4a322d07d9 光环助手版本升为3.4 2018-07-23 14:56:06 +08:00
df49f98e46 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-07-23 14:37:28 +08:00
122e3f6aa0 社区搜索重做基本完成(还差数据接口) 2018-07-23 14:32:46 +08:00
b902837b1c 使用 Kotlin Extension 简化消息弹窗动画代码 2018-07-23 11:08:46 +08:00
62639a9c79 初步实现简陋的消息弹窗动画 2018-07-20 16:21:17 +08:00
06dc7fc566 专题改造注解 2018-07-20 11:39:31 +08:00
ece6e099ec 更新友盟 消息完成自定义处理(需要和后端协商) 2018-07-20 11:00:29 +08:00
f3ce82275a 优化专题详情断网逻辑判断 2018-07-18 18:18:07 +08:00
4000dd8383 Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-07-18 17:57:53 +08:00
d67053ce7c 专题详情重构基本完成 2018-07-18 17:33:51 +08:00
37bca1ee1c 将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中,BaseList重新整理分层结构 2018-07-18 17:32:51 +08:00
229d3e9c88 新增简单的消息弹窗 2018-07-18 15:26:03 +08:00
c5d79a014b 曝光区分 debug 和 release 包,提交到不同的库 2018-07-17 10:14:00 +08:00
7d609b9c2a 更新 README 2018-07-16 17:44:41 +08:00
97eabcc600 使用 RxJava 优化自动搜索触发机制 2018-07-16 17:37:41 +08:00
932863a73f 将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中,BaseList重新整理分层结构 2018-07-16 16:53:24 +08:00
4014fc27af Merge branch 'dev' of gitlab.ghzhushou.com:halo/assistant-android into dev 2018-07-16 15:14:22 +08:00
fdf7be4a9f 解决Retrofit + RxJava2返回null时发生异常问题(Null is not a valid element) 2018-07-16 15:13:58 +08:00
b0fd801fec 避免 kotlin 非空异常 2018-07-16 14:03:11 +08:00
34c0bbe434 修改沉浸栏(背景:白色,字体:灰色)颜色,目前只适配了MIUI和Google原生系统 2018-07-16 11:22:41 +08:00
92c5697565 图片上传增加多图上传 2018-07-13 18:20:32 +08:00
445759e511 把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题 2018-07-12 17:47:26 +08:00
a5b32cc099 完成网易七鱼基本功能的实现 2018-07-12 17:21:23 +08:00
7a5f24bfe7 图片压缩增加Gif判断(是否压缩Gif) 2018-07-12 14:42:25 +08:00
b40d58f1ae 修复下载全部开始 无法更新页面问题 2018-07-12 11:00:53 +08:00
ef28fc3616 constraintLayout 退档
整理问题编辑代码位置
2018-07-11 16:51:05 +08:00
80d2e2c488 constraintLayout 退档
整理问题编辑代码位置
2018-07-11 16:50:40 +08:00
ca07f10c9d http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/284 2018-07-11 16:15:53 +08:00
8a7fa127ba 社区精选(信息流)刷新数据统计格式更改(补锅 http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/260#note_6952) 2018-07-10 18:34:59 +08:00
8ee6039a2b 增加Retrofit FileRequestBody(进度监听) 2018-07-10 17:57:46 +08:00
aac58029f6 1.上拉加载默认文案是'上拉加载',手动拖动正式触发加载时才会显示为'加载中'
2.我的关注,如果已经有关注游戏,[热门游戏推荐] 区域改为默认是收起来;如果关注为空,则默认是展开;且展开后的高度要增加(加一行游戏的高度)
2018-07-09 18:00:52 +08:00
640a8d4e0f 合并更新依赖分支的代码 2018-07-09 14:35:02 +08:00
9f621696c1 Merge branch 'update_dependency' into dev
# Conflicts:
#	app/src/main/java/com/gh/common/util/ImageUtils.kt
#	app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt
#	app/src/main/java/com/gh/gamecenter/qa/answer/edit/AnswerEditFragment.java
#	app/src/main/java/com/gh/gamecenter/qa/ask/QuestionEditViewModel.kt
#	app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
2018-07-09 11:54:59 +08:00
a45fff7cca 使用retrofit上传图片以及引入luban图片压缩框架 2018-07-09 11:34:41 +08:00
8f37cbdfde 更新 AS 版本,优化包依赖源提高获取速度 2018-07-06 11:20:06 +08:00
3ffd6f74f1 完成 RxJava 版本的更新 2018-07-06 10:44:37 +08:00
3f9fb27642 更新一波依赖,RxJava2 的还没改完 2018-07-05 17:54:23 +08:00
1159 changed files with 54101 additions and 19126 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

@ -1,9 +1,5 @@
# 光环助手Android客户端
### sourcesets/debug/release
* https://developer.android.com/studio/build/build-variants.html#sourcesets
### APK打包配置
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
@ -51,7 +47,7 @@
* ~~Adapter ViewHolder的功能部分重写到ViewHolder类本身~~
* ~~activity 统一入口未完成(外部入口相关)去除多余activity使用统一toolbar~~
* release / debug compile不同的类库不需要再做什么开关
* ~~release / debug compile不同的类库不需要再做什么开关~~
* ~~Toolbar分离有图形按钮/没有图形按钮~~
@ -59,12 +55,15 @@
- 解决 Utils 工具类引发的内存泄漏问题
- 把原有 EventBus 的消息 Type 统一到一个文件内
- 明确 MVVM 中 Repository 及其衍生类的具体实现方式
- 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
- 将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中
- ~~将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中~~
- 依照光环助手界面功能以大模块 - 小模块的方式去修改包结构,包内文件建议以包名摘要作为前缀
- 使用 RxJava 的 Debounce 和 Map 操作优化搜索触发机制 参考资料:[1](https://proandroiddev.com/building-an-autocompleting-edittext-using-rxjava-f69c5c3f5a40),[2](https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352)
- ~~使用 RxJava 的 Debounce 和 Map 操作优化搜索触发机制 参考资料:[1](https://proandroiddev.com/building-an-autocompleting-edittext-using-rxjava-f69c5c3f5a40),[2](https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352)~~
- 把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题
- ~~把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题~~
- 上传图片改为用Retrofit上传
- ~~rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) 解决方法->com.gh.gamecenter.retrofit.Response~~
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
- 搞清楚 GameManager 的用途,看能不能去掉
- 重构一下 MainActivity

View File

@ -25,7 +25,8 @@ android {
}
dexOptions {
jumboMode = true
// jumboMode = true
javaMaxHeapSize "4g"
}
defaultConfig {
@ -67,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}\""
}
@ -88,13 +88,10 @@ android {
debuggable true
minifyEnabled false
zipAlignEnabled false
versionNameSuffix "-debug"
signingConfig signingConfigs.debug
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E2\""
}
release {
debuggable false
@ -103,10 +100,8 @@ android {
shrinkResources true
signingConfig signingConfigs.release
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
buildConfigField "String", "EXPOSURE_VERSION", "\"E2\""
}
}
@ -126,12 +121,21 @@ android {
buildConfigField "String", "MESSAGE_HOST", "\"${MESSAGE_HOST}\""
buildConfigField "String", "DATA_HOST", "\"${DATA_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
}
// internal test dev host
internal {
dimension "nonsense"
versionNameSuffix "-debug"
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "USER_HOST", "\"${DEV_USER_HOST}\""
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
@ -139,6 +143,13 @@ android {
buildConfigField "String", "MESSAGE_HOST", "\"${DEV_MESSAGE_HOST}\""
buildConfigField "String", "DATA_HOST", "\"${DEV_DATA_HOST}\""
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
buildConfigField "String", "MEIZUPUSH_APPID", "\"${DEBUG_MEIZUPUSH_APPID}\""
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${DEBUG_MEIZUPUSH_APPKEY}\""
buildConfigField "String", "BUGLY_APPID", "\"${DEBUG_BUGLY_APPID}\""
}
}
@ -166,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}"
@ -184,7 +203,6 @@ dependencies {
implementation "com.android.support:percent:${androidSupport}"
implementation "com.android.support.constraint:constraint-layout:${constraintLayout}"
implementation "com.kyleduo.switchbutton:library:${switchButton}"
implementation "com.readystatesoftware.systembartint:systembartint:${systemBarTint}"
implementation "com.facebook.fresco:fresco:${fresco}"
implementation "com.facebook.fresco:animated-gif:${fresco}"
@ -195,28 +213,21 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:${retrofit}"
implementation "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7
implementation "com.squareup.retrofit2:adapter-rxjava:${retrofit}"
// implementation "com.google.code.gson:gson:${gson}"
implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit}"
implementation "com.j256.ormlite:ormlite-android:${ormlite}"
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:rxjava:${rxJava}"
implementation "io.reactivex:rxandroid:${rxAndroid}"
implementation "com.jakewharton.rxbinding:rxbinding:${rxBinding}"
//TODO update to rx 2.x
// implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
// implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
// implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
implementation "com.google.zxing:core:${zxing}"
implementation "com.google.zxing:android-core:${zxing}"
@ -242,22 +253,36 @@ dependencies {
implementation 'com.google.android:flexbox:0.2.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
kapt 'com.android.databinding:compiler:3.0.1'
kapt 'com.android.databinding:compiler:3.1.3'
implementation 'com.contrarywind:Android-PickerView:4.1.3'
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')
}
File propFile = file('sign.properties')
if (propFile.exists()) {
@ -287,3 +312,31 @@ if (propFile.exists()) {
} else {
android.buildTypes.release.signingConfig = null
}
// 用于测试读取 META-INF 里的 JSON 的代码
//task generateMetaJson {
// def resDir = new File(buildDir, 'generated/FILES_FOR_META_INF/')
// def destDir = new File(resDir, 'META-INF/')
// // Add resDir as a resource directory so that it is automatically included in the APK.
// android {
// sourceSets {
// main.resources {
// srcDir resDir
// }
// }
// }
//
// doLast {
// if (!destDir.exists()) destDir.mkdirs()
// copy {
// into destDir
// from new File('generated/FILES_FOR_META_INF/META-INF/halo_skip.json')
// }
// }
//}
//// Specify when put_files_in_META_INF should run
//project.afterEvaluate {
// tasks.findAll { task ->
// task.name.startsWith('merge') && task.name.endsWith('Resources')
// }.each { t -> t.dependsOn generateMetaJson }
//}

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.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"
@ -299,13 +297,13 @@
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.qa.ask.QuestionEditActivity"
android:name = "com.gh.gamecenter.qa.questions.edit.QuestionEditActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.kaifu.add.AddKaiFuActivity"
android:screenOrientation = "portrait"
android:windowSoftInputMode = "stateHidden"/>
android:windowSoftInputMode = "stateHidden" />
<activity
android:name = "com.gh.gamecenter.kaifu.patch.PatchKaifuActivity"
@ -323,6 +321,65 @@
android:name = "com.gh.gamecenter.NetworkDiagnosisActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.personalhome.fans.FansActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.personalhome.followers.FollowersActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.PersonalHomeActivity"
android:screenOrientation = "portrait" />
<activity
android:name = "com.gh.gamecenter.personalhome.answer.PersonalAnswerActivity"
android:screenOrientation = "portrait" />
<activity
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
android:name = "com.gh.gamecenter.PushProxyActivity"
@ -341,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"
@ -369,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"
@ -383,6 +431,40 @@
</intent-filter >
</receiver >
<receiver android:name = "com.gh.gamecenter.receiver.UmengMessageReceiver" >
<intent-filter >
<action android:name = "com.gh.gamecenter.UMENG" />
</intent-filter >
</receiver >
<!--魅族push应用定义消息receiver声明 -->
<receiver android:name = "com.gh.gamecenter.receiver.MeizuPushReceiver" >
<intent-filter >
<!-- 接收push消息 -->
<action android:name = "com.meizu.flyme.push.intent.MESSAGE" />
<!-- 接收register消息 -->
<action android:name = "com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
<!-- 接收unregister消息-->
<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" />
<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 >
<service android:name = "com.gh.base.GHUmengNotificationService" />
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
</application >

View File

@ -13,7 +13,11 @@ function setupWhenContentEditable() {
e.preventDefault();
var text = (e.originalEvent || e).clipboardData.getData('text/plain');
text = text.replace(/\n/g, '<br>');
document.execCommand("insertHTML", false, text);
if("" != text) {
document.execCommand("insertHTML", false, text);
} else {
window.onPasteListener.onPaste();
}
});
requestContentFocus();

View File

@ -11,5 +11,6 @@
<script type="text/javascript" src="zepto.min.js"></script>
<script type="text/javascript" src="rich_editor.js"></script>
<script type="text/javascript" src="content.js"></script>
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-lazyload/10.15.0/lazyload.min.js"></script>-->
</body>
</html>

View File

@ -0,0 +1,40 @@
emoji_kf_1.png,:smile:
emoji_kf_2.png,:smiley:
emoji_kf_3.png,:laughing:
emoji_kf_4.png,:blush:
emoji_kf_5.png,:heart_eyes:
emoji_kf_6.png,:smirk:
emoji_kf_7.png,:flushed:
emoji_kf_8.png,:kissing_heart:
emoji_kf_9.png,:grin:
emoji_kf_10.png,:wink:
emoji_kf_11.png,:stuck_out_tongue_winking_eye:
emoji_kf_12.png,:stuck_out_tongue_closed eyes:
emoji_kf_13.png,:worried:
emoji_kf_14.png,:sleeping:
emoji_kf_15.png,:expressionless:
emoji_kf_16.png,:sweat_smile:
emoji_kf_17.png,:joy:
emoji_kf_18.png,:cold_sweat:
emoji_kf_19.png,:sob:
emoji_kf_20.png,:angry:
emoji_kf_21.png,:mask:
emoji_kf_22.png,:scream:
emoji_kf_23.png,:sunglasses:
emoji_kf_24.png,:heart:
emoji_kf_25.png,:broken_heart:
emoji_kf_26.png,:star:
emoji_kf_27.png,:anger:
emoji_kf_28.png,:exclamation:
emoji_kf_29.png,:question:
emoji_kf_30.png,:zzz:
emoji_kf_31.png,:thumbsup:
emoji_kf_32.png,:thumbsdown:
emoji_kf_33.png,:ok_hand:
emoji_kf_34.png,:punch:
emoji_kf_35.png,:yeah:
emoji_kf_36.png,:clap:
emoji_kf_37.png,:muscle:
emoji_kf_38.png,:pray:
emoji_kf_39.png,:skull:
emoji_kf_40.png,:trollface:

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,5 @@
# This is a simple Microlog configuration file
microlog.level=DEBUG
microlog.appender=LogCatAppender;FileAppender
microlog.formatter=PatternFormatter
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T

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) {
@ -193,38 +193,54 @@ RE.setBlockquote = function() {
}
RE.insertImage = function(url) {
var html = "<div><img src =\"" + url + "\" style=\" max-width: 100%; display:block; margin:8px auto; height: auto;\"></div><br>"
var html = "<div><img src =\"" + url + "\" style=\" max-width: 100%; display:block; margin:15px auto; height: auto;\"></div><br>"
RE.insertHTML(html);
}
RE.replaceTbImage = function() {
//RE.lazyLoad = function() {
// var myLazyLoad = new LazyLoad({
// elements_selector: ".lazy"
// })
//}
// 替换成缩略图
RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
if(img.src.indexOf("/tb/") > 0) continue;
var imgArr = img.src.split("/");
var tbImg = ""
for (var j = 0; j < imgArr.length; j++) {
if (j == imgArr.length - 1) {
tbImg += "tb/" + imgArr[j];
} else {
tbImg += imgArr[j] + "/";
}
if(img.src.indexOf("?") > 0) continue;
var tbImg
if(img.src.indexOf(".gif") > 0) {
tbImg = img.src + gifRuleFlag
} else {
tbImg = img.src + imgRuleFlag
}
img.style.cssText = "max-width: 30%; display:block; margin:8px auto; height: auto;"
img.style.cssText = "max-width: 60%; display:block; margin:15px auto; height: auto;"
img.src = tbImg;
if (i == 0) {
var bigImg = document.createElement('img');
bigImg.src = "file:///android_asset/web_load_dfimg_icon.png";
bigImg.style.cssText = "max-width: 20%; margin:8px 0 0 0; height: auto;"
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;"
}
}
}
}
RE.replaceAllDfImage = function() {
// 替换成默认图
RE.replaceAllDfImage = function(imgRuleFlag, gifRuleFlag) {
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
@ -232,34 +248,54 @@ RE.replaceAllDfImage = function() {
img.parentNode.removeChild(img.parentNode.childNodes[0]);
i--;
} else {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
img.src = img.src.replace("/tb/", "/");
if(img.src.indexOf(".gif") > 0) {
if(gifRuleFlag.indexOf(",default") > 0) {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
img.src = img.src.split("?")[0] + gifRuleFlag
}
} else {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
img.src = img.src.split("?")[0] + imgRuleFlag
}
}
}
}
// 去除显示大图
RE.hideShowBigPic = function() {
var imgs = document.getElementsByTagName("img");
var j = 0;
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
if(img.src.indexOf("/tb/") > 0) {
if(img.src.indexOf(",thumbnail") > 0 && img.src.indexOf(".gif") == -1) {
j++;
}
}
// 去除显示大图
if (j == 0) {
RE.replaceAllDfImage();
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
if(img.src.indexOf("web_load_dfimg_icon") > 0) {
img.parentNode.removeChild(img.parentNode.childNodes[0]);
break;
}
}
}
}
RE.replaceDfImageByUrl = function(imgUrl) {
RE.replaceDfImageByUrl = function(imgUrl, imgRuleFlag, gifRuleFlag) {
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
if (img.src == imgUrl) {
if (img.src.indexOf(imgUrl) != -1) {
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
img.src = img.src.replace("/tb/", "/");
if(img.src.indexOf(".gif") > 0) {
img.src = img.src.split("?")[0] + gifRuleFlag
} else {
img.src = img.src.split("?")[0] + imgRuleFlag
}
}
}
RE.hideShowBigPic();

View File

@ -1,11 +1,14 @@
package com.gh.base;
import android.app.Activity;
import android.arch.lifecycle.Lifecycle;
import android.content.Intent;
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;
import com.gh.common.util.DialogUtils;
@ -17,6 +20,7 @@ import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SuggestionActivity;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.gh.gamecenter.suggest.SuggestType;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
@ -28,6 +32,8 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import butterknife.ButterKnife;
@ -73,9 +79,25 @@ public abstract class BaseActivity extends BaseToolBarActivity implements EasyPe
}
}
// 小米沉浸式黑色字体
public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
Class<? extends Window> clazz = activity.getWindow().getClass();
try {
int darkModeFlag = 0;
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
} catch (Exception ignore) {
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStatusBarDarkMode(true, this);
EventBus.getDefault().register(this);
ButterKnife.bind(this);
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
@ -143,19 +165,18 @@ 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) {
e.printStackTrace();
}
} else if ("notfound".equals(showDialog.getType())) {
DialogUtils.showAlertDialog(this, "下载失败", "下载链接已失效,建议提交反馈"
, "立即反馈", "取消"
, () -> {
SuggestionActivity.startSuggestionActivity(this, 4,
SuggestionActivity.startSuggestionActivity(this, SuggestType.gameQuestion,
null, showDialog.getPath() + ",问题反馈:下载链接失效");
}, null);
}
@ -189,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,8 +7,11 @@ import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gh.common.util.DisplayUtils;
import com.gh.gamecenter.R;
import com.gh.gamecenter.normal.ToolbarController;
import com.lightgame.BaseAppCompatActivity;
@ -80,6 +83,16 @@ public abstract class BaseToolBarActivity extends BaseAppCompatActivity implemen
}
}
}
// 限制标题实际宽度 防止标题挡住toolbar menu按钮
if (menu.size() > 2 && mTitleTv != null) {
ViewGroup.LayoutParams layoutParams = mTitleTv.getLayoutParams();
if (layoutParams instanceof RelativeLayout.LayoutParams) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) layoutParams;
params.setMargins(DisplayUtils.dip2px(90), 0, DisplayUtils.dip2px(90), 0);
mTitleTv.setLayoutParams(params);
}
}
}
@Override

View File

@ -0,0 +1,19 @@
package com.gh.base
import android.app.Activity
object CurrentActivityHolder {
@JvmStatic
val activitySet = HashSet<Activity>()
@JvmStatic
fun getCurrentActivity(): Activity? {
return if (activitySet.isEmpty()) {
null
} else {
activitySet.iterator().next()
}
}
}

View File

@ -4,6 +4,8 @@ import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
import com.gh.common.im.ImManager;
import com.gh.common.notifier.Notifier;
import com.gh.common.util.DataUtils;
import com.gh.download.DownloadManager;
import com.lightgame.utils.AppManager;
@ -34,6 +36,8 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
public void onActivityResumed(Activity activity) {
DataUtils.onResume(activity);
CurrentActivityHolder.getActivitySet().add(activity);
ImManager.updateFloatingWindow();
//FIXME 这里应该只是部分Activity需要
try {
// 初始化gameMap
@ -46,11 +50,12 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
@Override
public void onActivityPaused(Activity activity) {
DataUtils.onPause(activity);
CurrentActivityHolder.getActivitySet().remove(activity);
}
@Override
public void onActivityStopped(Activity activity) {
Notifier.hide();
}
@Override

View File

@ -6,8 +6,8 @@ import android.os.Bundle;
import com.gh.common.util.EntranceUtils;
import com.gh.gamecenter.GameDetailActivity;
import com.gh.gamecenter.NewsDetailActivity;
import com.gh.gamecenter.SubjectActivity;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.subject.SubjectActivity;
import com.umeng.message.UmengNotificationClickHandler;
import com.umeng.message.entity.UMessage;
@ -38,7 +38,7 @@ public class GHUmengNotificationClickHandler extends UmengNotificationClickHandl
bundle.putString(EntranceUtils.KEY_GAMEID, target);
break;
case EntranceUtils.HOST_COLUMN:
bundle.putString(EntranceUtils.KEY_TO, SubjectActivity.class.getSimpleName());
bundle.putString(EntranceUtils.KEY_TO, SubjectActivity.class.getName());
bundle.putString(EntranceUtils.KEY_ID, target);
break;
case EntranceUtils.HOST_WEB:

View File

@ -0,0 +1,260 @@
package com.gh.base
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.preference.PreferenceManager
import android.support.v4.app.NotificationCompat
import android.text.TextUtils
import android.view.View
import com.gh.common.notifier.Notifier
import com.gh.common.util.DataUtils
import com.gh.common.util.EntranceUtils
import com.gh.common.util.PackageUtils
import com.gh.common.util.StringUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
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() {
companion object {
const val ACTION_UMENG = "com.gh.gamecenter.UMENG"
const val MESSAGE_FROM_SYSTEM = "message_from_system"
const val HALO_MESSAGE_DIALOG = "HALO_MESSAGE_DIALOG"
const val HALO_MESSAGE_CENTER = "HALO_MESSAGE_CENTER"
const val ANSWER = "answer"
const val FOLLOW_QUESTION = "follow_question"
const val NOTIFICATION_ID = 2015
const val DISPLAY_TYPE_NOTIFICATION = "notification"
const val DISPLAY_TYPE_CUSTOM = "custom"
}
val notificationTags = arrayOf("GH_UMENG_TAG_1", "GH_UMENG_TAG_2", "GH_UMENG_TAG_3")
val gson = Gson()
override fun onMessage(context: Context, intent: Intent) {
val message = intent.getStringExtra(AgooConstants.MESSAGE_BODY)
val isMessageFromSystem = intent.getBooleanExtra(MESSAGE_FROM_SYSTEM, false)
try {
val pushData = gson.fromJson(message, PushEntity::class.java)
pushData?.let { handlePushData(context, it, message, isMessageFromSystem) }
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun handlePushData(context: Context, pushData: PushEntity, message: String, isMessageFromSystem: Boolean) {
val notificationManager = context.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (pushData.displayType == DISPLAY_TYPE_NOTIFICATION) {
// 其它类型的透传信息
// 显示到通知栏
val msg = gson.fromJson(message, PushNotificationEntity::class.java)
val data = msg?.extra?.data
// 系统推送,直接处理跳转
if (isMessageFromSystem) {
val intent = Intent()
intent.setClass(context, UmengMessageReceiver::class.java)
intent.putExtra(EntranceUtils.KEY_DATA, data?.link)
intent.putExtra(EntranceUtils.KEY_TYPE, UmengMessageReceiver.DIRECT_ONLY)
intent.putExtra(EntranceUtils.KEY_MESSAGE, message)
context.sendBroadcast(intent)
return
}
// 判断是否过滤该消息
if (validatePush(data?.condition)) {
val clickIntent = Intent()
val removeIntent = Intent()
clickIntent.setClass(context, UmengMessageReceiver::class.java)
clickIntent.putExtra(EntranceUtils.KEY_DATA, data?.link)
clickIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
clickIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_CLICK)
removeIntent.setClass(context, UmengMessageReceiver::class.java)
removeIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_REMOVE)
removeIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
val clickPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(),
clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val deletePendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt() + 1,
removeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("Halo_Push", "Halo_Push", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(context, "Halo_Push")
.setSmallIcon(R.drawable.ic_notification)
.setTicker(pushData.body?.ticker)
.setContentTitle(pushData.body?.title)
.setContentText(pushData.body?.text)
.setContentIntent(clickPendingIntent)
.setDeleteIntent(deletePendingIntent)
.build()
notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
}
} else {
if (HALO_MESSAGE_DIALOG == pushData.body?.custom) {
// 回答了问题或者关注了问题的消息
val msg = gson.fromJson(message, PushMessageEntity::class.java)
val data = msg?.extra?.data
val type = if (ANSWER == data?.type) {
"回答了你的问题"
} else {
"回答了你关注的问题"
}
val userName = StringUtils.shrinkStringWithDot(data?.userEntity?.name, 8)
val displayText = userName + type
if (Notifier.isActivityValid(CurrentActivityHolder.getCurrentActivity()) &&
Notifier.shouldShowNotifier(data?.answer?.id + displayText)) {
Notifier.create(CurrentActivityHolder.getCurrentActivity())
.setText(displayText)
.setDuration(5000)
.setIcon(data?.userEntity?.icon)
.setOnClickListener(View.OnClickListener { _ ->
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_ANSWER_ID, data?.answer?.id)
bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG)
bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
EntranceUtils.jumpActivity(context, bundle)
DataUtils.onMtaEvent(context, "消息弹窗",
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()
})
.show(false)
Notifier.tagNotifierAsShowed(data?.answer?.id + displayText)
}
} else if (HALO_MESSAGE_CENTER == pushData.body?.custom) {
// 消息中心逻辑
val msg = gson.fromJson(message, PushMessageUnreadEntity::class.java)
val data = msg?.extra?.data
data?.let { MessageUnreadRepository.loadMessageUnreadData() }
}
}
}
private fun validatePush(condition: PushNotificationEntity.Data.Condition?): Boolean {
if (condition == null) return true
// 校验渠道是否匹配
condition.ghzs?.channel?.let {
if (it.isNotEmpty() && it != HaloApp.getInstance().channel) {
return false
}
}
// 校验光环版本版本是否匹配
condition.ghzs?.version?.let {
if (it.isNotEmpty() && !BuildConfig.VERSION_NAME.contains(it)) {
return false
}
}
// 校验已安装的应用里是否存在条件的包名
if (condition.packageName.isNotEmpty()) {
val installedPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
for (packageName in installedPackageList) {
if (condition.packageName == packageName) {
return true
}
}
return false
}
return true
}
/**
* 规则:最多三条消息,以旧换新
*
* @return NotificationTag
*/
private fun getNotificationTag(context: Context): String {
val sp = PreferenceManager.getDefaultSharedPreferences(context)
val edit = sp.edit()
val timeTagMap = HashMap<Long, String>()
for (tag in notificationTags) {
val time = sp.getLong(tag, 0)
if (time == 0L) {
edit.putLong(tag, System.currentTimeMillis()).apply()
return tag
} else {
timeTagMap[time] = tag
}
}
val minTime = Collections.min(timeTagMap.keys)
val tag = timeTagMap[minTime]
edit.putLong(tag, System.currentTimeMillis()).apply()
return if (TextUtils.isEmpty(tag)) notificationTags[0] else tag!!
}
}

View File

@ -10,6 +10,7 @@ import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -29,9 +30,9 @@ import java.lang.ref.WeakReference;
import java.util.List;
import butterknife.ButterKnife;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
@ -42,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;
@ -111,6 +114,9 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
super.onCreate(savedInstanceState);
final Intent intent = getActivity().getIntent();
mEntrance = intent.getStringExtra(KEY_ENTRANCE);
if (TextUtils.isEmpty(mEntrance) && getArguments() != null) {
mEntrance = getArguments().getString(KEY_ENTRANCE);
}
isEverPause = false;
EventBus.getDefault().register(this);
@ -126,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

@ -1,5 +1,6 @@
package com.gh.base.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -54,7 +55,18 @@ 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
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
List<Fragment> fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
@Override

View File

@ -21,6 +21,8 @@ public class WaitingDialogFragment extends BaseDialogFragment {
private OnDialogBackListener mBackListener;
private TextView message;
public static WaitingDialogFragment newInstance(String message) {
Bundle args = new Bundle();
args.putString(KEY_MSG, message);
@ -43,7 +45,7 @@ public class WaitingDialogFragment extends BaseDialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.set_wait_dialog, null);
final TextView message = (TextView) view.findViewById(R.id.set_wait_message);
message = (TextView) view.findViewById(R.id.set_wait_message);
message.setText(getArguments().getString(KEY_MSG));
return view;
}
@ -62,6 +64,10 @@ public class WaitingDialogFragment extends BaseDialogFragment {
this.mBackListener = backListener;
}
public void uploadWaitingHint(String hint) {
if (message != null) message.setText(hint);
}
@Override
public boolean onBack() {
if (mBackListener != null) {

View File

@ -0,0 +1,25 @@
package com.gh.common
import android.os.Handler
import android.os.Looper
import java.util.concurrent.Executor
import java.util.concurrent.Executors
object AppExecutor {
@JvmStatic
var ioExecutor = Executors.newSingleThreadExecutor()
@JvmStatic
var uiExecutor = MainThreadExecutor()
class MainThreadExecutor : Executor {
private val mainThreadHandler = Handler(Looper.getMainLooper())
override fun execute(command: Runnable) {
mainThreadHandler.post(command)
}
fun executeWithDelay(command: Runnable, delay: Long) {
mainThreadHandler.postDelayed(command, delay)
}
}
}

View File

@ -0,0 +1,39 @@
package com.gh.common
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.gh.common.im.ImManager
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.m7.imkfsdk.chat.ChatActivity
import io.reactivex.schedulers.Schedulers
/**
* 可使用 [LocalBroadcastManager] 来进行简单的模块间消息通知
*/
class LocalBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
when (intent.action) {
ChatActivity.ACTION_DISMISS_FLOATING_WINDOW -> {
ImManager.dismissFloatingWindow()
RetrofitManager.getInstance(HaloApp.getInstance().application).api.postImEnding(UserManager.getInstance().userId)
.subscribeOn(Schedulers.io())
.subscribe()
}
ChatActivity.ACTION_HIDE_UNREAD_DOT -> {
ImManager.updateShouldShowFloatingWindowDot(false)
}
else -> return
}
}
}
}

View File

@ -0,0 +1,137 @@
package com.gh.common
import android.preference.PreferenceManager
import com.gh.base.GHUmengNotificationService
import com.gh.common.constant.Config
import com.gh.common.exposure.meta.MetaUtil
import com.gh.common.util.edit
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.entity.AliasEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.Gson
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.umeng.commonsdk.UMConfigure
import com.umeng.message.IUmengRegisterCallback
import com.umeng.message.PushAgent
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import org.android.agoo.huawei.HuaWeiRegister
import org.android.agoo.mezu.MeizuRegister
import org.android.agoo.xiaomi.MiPushRegistar
import org.json.JSONObject
object PushManager {
var gson = Gson()
var deviceToken: String? = ""
var previousAlias: AliasEntity? = null
var application = HaloApp.getInstance().application
const val SP_PUSH_ALIAS = "push_alias"
@JvmStatic
fun init(channel: String) {
//初始化友盟推送
UMConfigure.init(application,
Config.UMENG_APPKEY, channel,
UMConfigure.DEVICE_TYPE_PHONE,
Config.UMENG_MESSAGE_SECRET)
// 注册小米、华为和魅族通道
MiPushRegistar.register(application, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
HuaWeiRegister.register(application)
MeizuRegister.register(application, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
//友盟推送
val pushAgent = PushAgent.getInstance(application)
pushAgent.onAppStart() // 开启App统计
//注册推送服务每次调用register方法都会回调该接口
registerDevice()
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(application).getString(SP_PUSH_ALIAS, "")
previousAlias = gson.fromJson(aliasInSp, AliasEntity::class.java)
if (previousAlias == null) {
getAndSetAlias()
}
// 完全自定义处理(透传)
pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
}
private fun registerDevice() {
PushAgent.getInstance(application).register(object : IUmengRegisterCallback {
override fun onSuccess(dToken: String) {
//注册成功会返回device token
deviceToken = dToken
getAndSetAlias()
Utils.log("deviceToken::$dToken")
}
override fun onFailure(s: String, s1: String) {
Utils.log("deviceToken::" + "注册失败")
}
})
}
@JvmStatic
fun getAndSetAlias() {
if (deviceToken.isNullOrEmpty()) {
registerDevice()
return
}
val meta = MetaUtil.getMeta()
val jsonObject = JSONObject()
jsonObject.put("device_token", deviceToken)
jsonObject.put("imei", meta.imei)
jsonObject.put("android_id", meta.android_id)
jsonObject.put("model", meta.model)
jsonObject.put("manufacturer", meta.manufacturer)
jsonObject.put("os", meta.os)
jsonObject.put("os_version", meta.android_version)
jsonObject.put("mac", meta.mac)
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
RetrofitManager.getInstance(application).api.getAlias(body)
.subscribeOn(Schedulers.io())
.subscribe(
{ setAlias(it) },
{ it.printStackTrace() }
)
}
@JvmStatic
fun setAlias(alias: AliasEntity) {
val pushAgent = PushAgent.getInstance(application)
previousAlias = alias
PreferenceManager.getDefaultSharedPreferences(application).edit {
putString(SP_PUSH_ALIAS, gson.toJson(previousAlias))
}
pushAgent.setAlias(alias.alias, alias.aliasType) { b, s ->
Utils.log("注册别名 $b + $s")
}
}
@JvmStatic
fun deleteAlias() {
val pushAgent = PushAgent.getInstance(application)
previousAlias?.let {
pushAgent.deleteAlias(it.alias, it.aliasType) { b, s ->
Utils.log("删除别名 $b + $s")
}
}
PreferenceManager.getDefaultSharedPreferences(application).edit {
putString(SP_PUSH_ALIAS, "")
}
previousAlias = null
}
}

View File

@ -0,0 +1,115 @@
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(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 {
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) {
resumeCounting()
}
}
override fun onFragmentPaused(fm: FragmentManager?, f: Fragment?) {
if (f === fragment) {
pauseCounting()
}
}
override fun onFragmentViewDestroyed(fm: FragmentManager?, f: Fragment?) {
if (f === fragment) {
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
}
}
}, false)
}
private fun resumeCounting() {
isWorking = true
TimeElapsedThreadHolder.threadService.execute {
while (isWorking) {
try {
elapsedTime++
if (timeout != 0 && timeout == elapsedTime) {
timeoutCallback?.run {
AppExecutor.uiExecutor.execute {
onTimeout()
}
}
}
Thread.sleep(1000)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
private fun pauseCounting() {
isWorking = false
}
}
object TimeElapsedThreadHolder {
val threadService = Executors.newSingleThreadExecutor()
}
interface TimeoutCallback {
fun onTimeout()
}

View File

@ -6,6 +6,7 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.gh.common.util.GsonUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.NewsEntity;
import com.gh.gamecenter.entity.SettingsEntity;
@ -41,11 +42,12 @@ 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";
private static SettingsEntity mSettingsEntity;
public static boolean isShow() {
@ -54,9 +56,9 @@ public class Config {
if (!isExistDownloadFilter()) return false;
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
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;
}
}
@ -76,10 +78,13 @@ public class Config {
public static boolean isShowDownload(String gameId) {
if (PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication())
.getBoolean("isFixDownload", false)) return true;
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
return false;
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
for (SettingsEntity.Download entity : getSettings().getDownload()) {
if (gameId.equals(entity.getGame())) {
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
return true;
@ -87,8 +92,7 @@ public class Config {
return false;
}
} else if ("all".equals(entity.getGame())) {
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())
|| PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).getBoolean("isFixDownload", false)) {
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
return true;
}
}
@ -102,15 +106,15 @@ public class Config {
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
return false;
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
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;
}
}
@ -123,9 +127,9 @@ public class Config {
if (!isExistDownloadFilter())
return false;
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
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;
}
}
@ -147,15 +151,29 @@ public class Config {
}
public static void setSettings(SettingsEntity settingsEntity) {
SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit();
edit.putString(SETTINGS_KEY, GsonUtils.getInstance().toJson(settingsEntity)).apply();
mSettingsEntity = settingsEntity;
}
public static SettingsEntity getSettings() {
if (mSettingsEntity == null) {
try {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
String json = sp.getString(SETTINGS_KEY, null);
if (!TextUtils.isEmpty(json)) {
mSettingsEntity = GsonUtils.getInstance().fromJsonBean(json, SettingsEntity.class);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mSettingsEntity;
}
private static boolean isExistDownloadFilter() {
if (mSettingsEntity == null || mSettingsEntity.getDownload() == null || mSettingsEntity.getDownload().size() == 0) {
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
return false;
} else {
return true;

View File

@ -15,6 +15,14 @@ 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";
//手机号码匹配规则
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
public static final String REGEX_ACCOUNT = "^[a-zA-Z_]\\w{5,17}$";

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

@ -22,10 +22,12 @@ import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
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;
@ -38,8 +40,9 @@ 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;
@ -56,9 +59,15 @@ import java.util.Locale;
public class BindingAdapters {
@BindingAdapter("imageIcon")
public static void loadIcon(SimpleDraweeView view, String imageUrl) {
ImageUtils.displayIcon(view, imageUrl);
}
@BindingAdapter("imageUrl")
public static void loadImage(SimpleDraweeView view, String imageUrl) {
view.setImageURI(imageUrl);
ImageUtils.display(view, imageUrl);
}
@BindingAdapter({"addDetailKaiFuView", "addDetailKaiFuViewListener", "isReadyPatch"})
@ -96,6 +105,12 @@ public class BindingAdapters {
}
}
// 如果超过10000则转换为1.0W
@BindingAdapter("transSimpleCount")
public static void transSimpleCount(TextView view, int count) {
view.setText(NumberUtils.transSimpleCount(count));
}
@BindingAdapter({"addKaiFuView", "clickListener"})
public static void addKaiFuView(LinearLayout view, List<KaiFuCalendarEntity> list, OnViewClickListener listener) {
if (list == null) return;
@ -302,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:
@ -332,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);
@ -341,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);
@ -372,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);
@ -401,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("更新")) {
@ -420,15 +429,16 @@ public class BindingAdapters {
ApkEntity apkEntity = gameEntity.getApk().get(0);
String msg = FileUtils.isCanDownload(progressBar.getContext(), apkEntity.getSize());
if (TextUtils.isEmpty(msg)) {
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), "(我的光环:我的游戏)", "下载开始");
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), "(我的光环:我的游戏)", "下载开始", method);
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
DownloadManager.createDownload(progressBar.getContext(),
apkEntity,
gameEntity,
method,
StringUtils.buildString("(我的光环:我的游戏)"), "我的光环-我的游戏:" + gameEntity.getName(),
isSubscribe,
downloadExposureEvent);
progressBar.setProgress(0);
@ -470,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

@ -4,13 +4,10 @@ import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import rx.functions.Action1
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() {
@ -22,12 +19,12 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentResumed(fm: FragmentManager?, f: Fragment?) {
throttleBus = ExposureThrottleBus(Action1 { commitExposure(it) }, Action1(Throwable::printStackTrace))
throttleBus = ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace))
}
override fun onFragmentPaused(fm: FragmentManager?, f: Fragment?) {
visibleState?.let { commitExposure(it) }
throttleBus?.unsubscribe()
throttleBus?.clear()
}
}, false)
}
@ -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,150 +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 LOG_STORE = "exposure"
private const val STORE_SIZE = 100
private const val STORE_FORCE_UPLOAD_PERIOD = 300 * 1000L
private const val LOG_STORE = BuildConfig.EXPOSURE_REPO
private val loghubHelper = LoghubHelper.getInstance()
private lateinit var client: LGLOGClient
private lateinit var db: ExposureEventDao
private val storeList = arrayListOf<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()
storeList.addAll(eventList)
})
exposureExecutor.execute {
val eventList = exposureDao.getAll()
exposureSet.addAll(eventList)
}
fixedRateTimer(name = "ExposureManager-Store-Checker", initialDelay = 500, period = STORE_FORCE_UPLOAD_PERIOD) {
checkAndUploadFromStore(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 storeList, upload when storeList size exceeds STORE_SIZE
*/
private fun store(event: ExposureEvent) {
storeOpThread.execute({
fun log(event: ExposureEvent) {
exposureExecutor.execute {
if (!exposureCache.contains(event.id)) {
storeList.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}")
}
})
checkAndUploadFromStore()
}
}
/**
* Store Many Events to storeList, upload when storeList 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)) {
storeList.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}")
}
}
})
checkAndUploadFromStore()
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 checkAndUploadFromStore(isForceUpload: Boolean = false) {
if (storeList.size < STORE_SIZE && !isForceUpload || storeList.size == 0) return
storeOpThread.execute({
if (storeList.size < STORE_SIZE && !isForceUpload || storeList.size == 0) return@execute
val uploaded = storeList.toList()
try {
client.PostLog(buildLogGroup(uploaded), LOG_STORE)
} catch (exception: LogException) {
// Return to insure no logs lost because of online commit failure
return@execute
}
storeList.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))
@ -157,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,38 +1,37 @@
package com.gh.common.exposure
import rx.Subscription
import rx.functions.Action1
import rx.schedulers.Schedulers
import rx.subjects.PublishSubject
import rx.subjects.Subject
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import java.util.concurrent.TimeUnit
class ExposureThrottleBus(var onSuccess: Action1<VisibleState>, var onError: Action1<Throwable>) {
class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Consumer<Throwable>) {
companion object {
private const val THRESHOLD_TIME = 300L
}
private val mPublishSubject: Subject<VisibleState, VisibleState>
private val mSubscription: Subscription
private val mPublishSubject: PublishSubject<VisibleState> = PublishSubject.create()
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
init {
mPublishSubject = PublishSubject.create()
/**
* Since onScroll() callback will be triggered multiple times for every swipe, we use
* distinctUntilChanged() to prevent committing the same visibleState event and
* throttleWithTimeout() to pass a visibleState event with a delay and drop current event if another event arrives before the timeout.
*/
mSubscription = mPublishSubject
val disposable = mPublishSubject
.distinctUntilChanged()
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.subscribe(onSuccess, onError)
mCompositeDisposable.add(disposable)
}
fun unsubscribe() {
mSubscription.unsubscribe()
fun clear() {
mCompositeDisposable.clear()
}
fun postVisibleState(visibleState: VisibleState) {

View File

@ -1,12 +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 {
fun logADownloadExposureEvent(entity: GameEntity, platform: String?, traceEvent: ExposureEvent?, downloadType: DownloadType): ExposureEvent {
@JvmStatic
fun logADownloadExposureEvent(entity: GameEntity,
platform: String?,
traceEvent: ExposureEvent?,
downloadType: DownloadType): ExposureEvent {
val gameEntity = entity.clone()
gameEntity.platform = platform
gameEntity.downloadType = downloadType.toString()
@ -14,20 +18,24 @@ object ExposureUtils {
source = traceEvent?.source ?: ArrayList(),
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
event = ExposureType.DOWNLOAD)
ExposureManager.log(exposureEvent, false)
ExposureManager.log(exposureEvent)
return exposureEvent
}
fun logADownloadCompleteExposureEvent(entity: GameEntity, platform: String?, trace: String?, downloadType: DownloadType) {
@JvmStatic
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,9 +15,10 @@ 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? = ""
val userId: String? = "",
val exposureVersion: String? = ""
) : Parcelable

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)
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 {
@ -51,7 +60,7 @@ object MetaUtil {
*/
fun getMac(): String? {
var mac: String
var mac: String = ""
//Plan A
try {
@ -71,7 +80,12 @@ object MetaUtil {
// Plan C
val wifiManager = application.getSystemService(Context.WIFI_SERVICE) as WifiManager
mac = wifiManager.connectionInfo.macAddress
try {
mac = wifiManager.connectionInfo.macAddress
} catch (e: Exception) {
// e.printStackTrace()
}
return mac.trim()
}
@ -87,7 +101,7 @@ object MetaUtil {
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
if (Build.VERSION.SDK_INT >= 26) {
return "!" + telephonyManager.imei
return telephonyManager.imei
}
return telephonyManager.getDeviceId()
@ -135,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"
}
@ -155,10 +169,6 @@ object MetaUtil {
}
fun getIP(): String {
return "unknown"
}
fun getOS(): String {
return "android"
}

View File

@ -1,8 +1,10 @@
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 rx.schedulers.Schedulers
import io.reactivex.schedulers.Schedulers
import kotlin.concurrent.fixedRateTimer
class Corrector {
@ -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

@ -0,0 +1,67 @@
package com.gh.common.im
import android.app.Activity
import android.support.v4.view.ViewCompat
import android.view.View
import android.view.ViewGroup
object ImHintHelper {
@JvmStatic
fun show(activity: Activity?) {
activity?.let {
var hintView = retrieveHintViewFromActivity(it)
if (hintView == null) {
hintView = ImHintView(it)
hintView.showDot(ImManager.shouldShowFloatingWindowDot)
val decorView = it.window.decorView as ViewGroup
it.runOnUiThread {
decorView.addView(hintView)
}
} else {
hintView.showDot(ImManager.shouldShowFloatingWindowDot)
}
}
}
@JvmStatic
fun dismiss(activity: Activity?) {
activity?.let {
clearCurrent(it)
}
}
private fun retrieveHintViewFromActivity(activity: Activity?) : ImHintView? {
(activity?.window?.decorView as? ViewGroup)?.let {
for (i in 0..it.childCount) {
val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
if (childView != null && childView.windowToken != null) {
return childView
}
}
return null
}
return null
}
private fun clearCurrent(activity: Activity?) {
(activity?.window?.decorView as? ViewGroup)?.let {
for (i in 0..it.childCount) {
val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
if (childView != null && childView.windowToken != null) {
ViewCompat.animate(childView).alpha(0f).withEndAction(getRemoveViewRunnable(childView))
}
}
}
}
private fun getRemoveViewRunnable(childView: View?): Runnable {
return Runnable {
childView?.let {
(childView.parent as? ViewGroup)?.removeView(childView)
}
}
}
}

View File

@ -0,0 +1,84 @@
package com.gh.common.im
import android.app.Activity
import android.content.Context
import android.os.Build
import android.support.v4.view.ViewCompat
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.View
import android.view.ViewConfiguration
import android.widget.RelativeLayout
import com.gh.gamecenter.R
import kotlinx.android.synthetic.main.view_im_hint.view.*
class ImHintView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: RelativeLayout(context, attrs, defStyle) {
init {
inflate(context, R.layout.view_im_hint, this)
ViewCompat.setTranslationZ(this, Integer.MAX_VALUE.toFloat() - 1)
ivContainer.setOnClickListener {
if (context is Activity) {
ImManager.startChatActivity(context)
ImManager.removeNotification()
}
}
val lp = ivContainer.layoutParams as RelativeLayout.LayoutParams
lp.setMargins(0, 0, dp2px(30f), dp2px(106f) + retrieveNavigationHeight())
}
fun showDot(show: Boolean) {
if (show) {
unreadDot.visibility = View.VISIBLE
} else {
unreadDot.visibility = View.GONE
}
}
private fun dp2px(dp: Float): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.applicationContext.resources.displayMetrics).toInt()
}
private fun hasSoftKeys(): Boolean {
if (context !is Activity) return false
val hasSoftwareKeys: Boolean
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
val d = (context as Activity).windowManager.defaultDisplay
val realDisplayMetrics = DisplayMetrics()
d.getRealMetrics(realDisplayMetrics)
val realHeight = realDisplayMetrics.heightPixels
val realWidth = realDisplayMetrics.widthPixels
val displayMetrics = DisplayMetrics()
d.getMetrics(displayMetrics)
val displayHeight = displayMetrics.heightPixels
val displayWidth = displayMetrics.widthPixels
hasSoftwareKeys = realWidth - displayWidth > 0 || realHeight - displayHeight > 0
} else {
val hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey()
val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
hasSoftwareKeys = !hasMenuKey && !hasBackKey
}
return hasSoftwareKeys
}
private fun retrieveNavigationHeight(): Int {
val resources = context.resources
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0 && hasSoftKeys()) resources.getDimensionPixelSize(resourceId) else 0
}
}

View File

@ -0,0 +1,146 @@
package com.gh.common.im
import android.app.Activity
import android.app.NotificationManager
import android.content.Context
import com.gh.base.CurrentActivityHolder
import com.gh.common.util.SPUtils
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.MessageActivity
import com.gh.gamecenter.SuggestSelectActivity
import com.gh.gamecenter.manager.UserManager
import com.halo.assistant.HaloApp
import com.m7.imkfsdk.KfStartHelper
import com.moor.imkf.ChatListener
import com.moor.imkf.IMChat
import com.moor.imkf.IMChatManager
import com.moor.imkf.IMMessage
object ImManager {
const val IM_KEY = "893be270-9c75-11e8-a344-212975ba32b9"
const val SP_FLOATING_WINDOW_KEY = "IM_FLOATING_WINDOW"
const val SP_FLOATING_WINDOW_DOT_KEY = "IM_FLOATING_WINDOW_DOT"
var shouldShowFloatingWindow = false
var shouldShowFloatingWindowDot = false
@JvmStatic
fun attachIm() {
try {
if (UserManager.getInstance().userInfoEntity != null) {
IMChatManager.getInstance().init(
HaloApp.getInstance().application,
ImReceiver.UNIQUE_BROADCAST_ACTION,
IM_KEY,
UserManager.getInstance().userInfoEntity.name + "(" + UserManager.getInstance().userId + ")",
UserManager.getInstance().userId)
shouldShowFloatingWindow = SPUtils.getBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId)
shouldShowFloatingWindowDot = SPUtils.getBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId)
updateFloatingWindow()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
@JvmStatic
fun detachIm() {
try {
IMChatManager.getInstance().quitSDk()
shouldShowFloatingWindow = false
updateFloatingWindow()
removeNotification()
} catch (e: Exception) {
e.printStackTrace()
}
}
@JvmStatic
fun startChatActivity(activity: Activity) {
if (!UserManager.getInstance().userId.isNullOrEmpty()) {
try {
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, false)
shouldShowFloatingWindowDot = false
val chatHelper = KfStartHelper(activity, UserManager.getInstance().userInfoEntity.icon)
chatHelper.initSdkChat(
ImReceiver.UNIQUE_BROADCAST_ACTION,
IM_KEY,
UserManager.getInstance().userInfoEntity.name + "(" + UserManager.getInstance().userId + ")",
UserManager.getInstance().userId)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
@JvmStatic
fun showFloatingWindow() {
updateShouldShowFloatingWindow(true)
updateShouldShowFloatingWindowDot(true)
updateFloatingWindow()
}
@JvmStatic
fun dismissFloatingWindow() {
updateShouldShowFloatingWindow(false)
updateShouldShowFloatingWindowDot(false)
updateFloatingWindow()
}
@JvmStatic
fun removeNotification() {
val notificationManager = HaloApp.getInstance().application?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(ImReceiver.NOTIFICATION_ID)
}
@JvmStatic
fun updateFloatingWindow() {
try {
CurrentActivityHolder.getCurrentActivity()?.let {
if (isActivityValid(it)) {
if (shouldShowFloatingWindow) {
ImHintHelper.show(it)
} else {
ImHintHelper.dismiss(it)
removeNotification()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
@JvmStatic
fun sendFeedbackMessage(message: String) {
val fromToMessage = IMMessage.createTxtMessage(message)
HaloApp.getInstance().mainExecutor.execute {
IMChat.getInstance().sendMessage(fromToMessage, object : ChatListener {
override fun onProgress(p0: Int) {}
override fun onSuccess() {}
override fun onFailed() {}
})
}
}
fun updateShouldShowFloatingWindow(show: Boolean) {
SPUtils.setBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId, show)
shouldShowFloatingWindow = show
}
fun updateShouldShowFloatingWindowDot(show: Boolean) {
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, show)
shouldShowFloatingWindowDot = show
}
private fun isActivityValid(activity: Activity): Boolean {
return when (activity) {
is MainActivity -> true
is SuggestSelectActivity -> true
is MessageActivity -> true
else -> false
}
}
}

View File

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

View File

@ -0,0 +1,170 @@
package com.gh.common.notifier
import android.app.Activity
import android.support.v4.view.ViewCompat
import android.view.View
import android.view.ViewGroup
import com.gh.common.util.SPUtils
import com.gh.gamecenter.*
import java.lang.ref.WeakReference
@Suppress("DEPRECATION")
class Notifier private constructor() {
companion object {
private var activityWeakReference: WeakReference<Activity>? = null
private const val SP_VIEWED_NOTIFIER = "viewed_notifier"
/**
* 根据内容决定是否显示 Notifier
*/
@JvmStatic
fun shouldShowNotifier(content: String): Boolean {
val viewedNotifierCollection = SPUtils.getString(SP_VIEWED_NOTIFIER)
return !viewedNotifierCollection.contains(content)
}
/**
* 标记相应内容的 Notifier 已经显示过了
*/
@JvmStatic
fun tagNotifierAsShowed(content: String) {
val viewedNotifierCollection = SPUtils.getString(SP_VIEWED_NOTIFIER)
if (viewedNotifierCollection.length > 3000) {
SPUtils.setString(SP_VIEWED_NOTIFIER, content)
} else {
SPUtils.setString(SP_VIEWED_NOTIFIER, viewedNotifierCollection + content)
}
}
@JvmStatic
fun create(activity: Activity?): Notifier {
if (activity == null) {
throw IllegalArgumentException("Activity cannot be null!")
}
val notifier = Notifier()
// Hide current NotifierView, if one is active
clearCurrent(activity)
notifier.setActivity(activity)
notifier.notifierView = NotifierView(activity)
return notifier
}
@JvmStatic
fun isActivityValid(activity: Activity?): Boolean {
if (activity == null) return false
return when (activity) {
is MessageActivity -> false
is DownloadManagerActivity -> false
is CleanApkActivity -> false
is SplashScreenActivity -> false
else -> isNotExistInActivity(activity)
}
}
@JvmStatic
fun isNotExistInActivity(activity: Activity?): Boolean {
if (activity == null) return false
(activity.window?.decorView as? ViewGroup)?.let {
//Find all NotifierView Views in Parent layout
for (i in 0..it.childCount) {
val childView = if (it.getChildAt(i) is NotifierView) it.getChildAt(i) as NotifierView else null
if (childView != null && childView.windowToken != null) {
return false
}
}
}
return true
}
/**
* Cleans up the currently showing notifierView view, if one is present
*
* @param activity The current Activity
*/
@JvmStatic
fun clearCurrent(activity: Activity?) {
(activity?.window?.decorView as? ViewGroup)?.let {
//Find all NotifierView Views in Parent layout
for (i in 0..it.childCount) {
val childView = if (it.getChildAt(i) is NotifierView) it.getChildAt(i) as NotifierView else null
if (childView != null && childView.windowToken != null) {
ViewCompat.animate(childView).alpha(0f).withEndAction(getRemoveViewRunnable(childView))
}
}
}
}
@JvmStatic
fun hide() {
activityWeakReference?.get()?.let { clearCurrent(it) }
}
private fun getRemoveViewRunnable(childView: NotifierView?): Runnable {
return Runnable {
childView?.let {
(childView.parent as? ViewGroup)?.removeView(childView)
}
}
}
}
private var notifierView: NotifierView? = null
private val activityDecorView: ViewGroup?
get() {
var decorView: ViewGroup? = null
activityWeakReference?.get()?.let {
decorView = it.window.decorView as ViewGroup
}
return decorView
}
fun show(showVerticalTranslateAnimation: Boolean, delay: Long? = 0): NotifierView? {
activityWeakReference?.get()?.let {
it.runOnUiThread {
activityDecorView?.postDelayed({
notifierView?.showVerticalTranslateAnimation = showVerticalTranslateAnimation
activityDecorView?.addView(notifierView)
}, delay!!)
}
}
return notifierView
}
fun setIcon(url: String?): Notifier {
url?.let { notifierView?.setIcon(it) }
return this
}
fun setText(text: String?): Notifier {
notifierView?.setText(text)
return this
}
fun setDuration(time: Long): Notifier {
notifierView?.duration = time
return this
}
fun setOnClickListener(onClickListener: View.OnClickListener): Notifier {
notifierView?.findViewById<View>(R.id.cardView)?.setOnClickListener(onClickListener)
return this
}
private fun setActivity(activity: Activity) {
activityWeakReference = WeakReference(activity)
}
}

View File

@ -0,0 +1,336 @@
package com.gh.common.notifier
import android.animation.*
import android.app.Activity
import android.content.Context
import android.graphics.Path
import android.os.Build
import android.support.v4.view.ViewCompat
import android.text.TextUtils
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.util.Log
import android.util.TypedValue
import android.view.*
import android.widget.FrameLayout
import com.gh.common.util.ImageUtils
import com.gh.common.util.doOnEnd
import com.gh.common.util.doOnStart
import com.gh.gamecenter.R
import kotlinx.android.synthetic.main.view_notifier.view.*
class NotifierView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: FrameLayout(context, attrs, defStyle) {
companion object {
const val SCALE_MINI = 0.2F
const val SCALE_DEFAULT = 1F
const val DEFAULT_DURATION = 500L
}
var onShowListener: OnShowNotificationListener? = null
var onHideListener: OnHideNotificationListener? = null
lateinit var expandAnimator: ValueAnimator
lateinit var shrinkAnimator: ValueAnimator
lateinit var translateUpAnimator: ObjectAnimator
lateinit var translateDownAnimator: ObjectAnimator
lateinit var translateToLeftAnimator: ObjectAnimator
lateinit var translateToRightAnimator: ObjectAnimator
lateinit var zoomInAnimator: ObjectAnimator
lateinit var zoomOutAnimator: ObjectAnimator
var showAnimatorSet: AnimatorSet
var hideAnimatorSet: AnimatorSet
var rightToLeftPath: Path
var leftToRightPath: Path
var veryRight: Float = 0F
var veryBottom: Float = 0F
var centerX: Float = 0F
var navigationHeight = 0
var textWidth: Int = 0
var cardViewWidth: Int = 0
var verticalAnimationOffset: Int = 0
var duration = DEFAULT_DURATION
var showVerticalTranslateAnimation: Boolean = true
init {
inflate(context, R.layout.view_notifier, this)
ViewCompat.setTranslationZ(this, Integer.MAX_VALUE.toFloat())
cardView.scaleX = SCALE_MINI
cardView.scaleY = SCALE_MINI
verticalAnimationOffset = dp2px(100F)
navigationHeight = retrieveNavigationHeight()
rightToLeftPath = Path()
leftToRightPath = Path()
showAnimatorSet = AnimatorSet()
hideAnimatorSet = AnimatorSet()
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
centerX = (left + right - cardViewWidth) / 2F
// TODO Provide method to change these absolute offset.
val r = right - dp2px(72F).toFloat()
val b = bottom - dp2px(145F).toFloat() - navigationHeight
// Only set
if (veryRight != r || veryBottom != b) {
veryRight = r
veryBottom = b
rightToLeftPath.moveTo(r, b)
rightToLeftPath.lineTo(centerX, b)
leftToRightPath.moveTo(centerX, b)
leftToRightPath.lineTo(r, b)
initAnimator()
}
}
private fun initAnimator() {
expandAnimator = ValueAnimator.ofFloat(0F, 1F)
expandAnimator.duration = DEFAULT_DURATION
expandAnimator.addUpdateListener { a ->
val progress = a?.animatedValue as Float
tvText.width = (textWidth * progress).toInt()
}
expandAnimator.doOnEnd {
enableSwipeToDismiss()
shrinkAfterDelay()
}
shrinkAnimator = ValueAnimator.ofFloat(1F, 0F)
shrinkAnimator.duration = DEFAULT_DURATION
shrinkAnimator.addUpdateListener { a ->
val progress = a?.animatedValue as Float
tvText.width = (textWidth * progress).toInt()
}
shrinkAnimator.doOnEnd {
val lp = FrameLayout.LayoutParams(cardView.layoutParams)
lp.gravity = Gravity.NO_GRAVITY
cardView.layoutParams = lp
disableSwipeToDismiss()
}
translateToLeftAnimator = ObjectAnimator.ofFloat(cardView, "translationX", veryRight, centerX)
translateToLeftAnimator.duration = DEFAULT_DURATION
translateToLeftAnimator.doOnEnd {
onShowListener?.onShow()
val lp = FrameLayout.LayoutParams(cardView.layoutParams)
lp.gravity = Gravity.CENTER_HORIZONTAL
cardView.layoutParams = lp
cardView.translationX = 0f
expandAnimator.start()
}
translateToRightAnimator = ObjectAnimator.ofFloat(cardView, "translationX", centerX, veryRight)
translateToRightAnimator.duration = DEFAULT_DURATION
translateUpAnimator = ObjectAnimator.ofFloat(cardView, "translationY", veryBottom + verticalAnimationOffset, veryBottom)
translateUpAnimator.duration = DEFAULT_DURATION
translateUpAnimator.doOnStart { cardView.translationX = veryRight }
translateDownAnimator = ObjectAnimator.ofFloat(cardView, "translationY", veryBottom, veryBottom + verticalAnimationOffset)
translateDownAnimator.duration = DEFAULT_DURATION
zoomInAnimator = ObjectAnimator.ofPropertyValuesHolder(cardView, PropertyValuesHolder.ofFloat("scaleX", SCALE_DEFAULT),
PropertyValuesHolder.ofFloat("scaleY", SCALE_DEFAULT))
zoomInAnimator.duration = DEFAULT_DURATION
zoomInAnimator.doOnStart { cardView.translationX = veryRight }
zoomInAnimator.doOnStart { cardView.translationY = veryBottom }
zoomOutAnimator = ObjectAnimator.ofPropertyValuesHolder(cardView, PropertyValuesHolder.ofFloat("scaleX", SCALE_MINI),
PropertyValuesHolder.ofFloat("scaleY", SCALE_MINI))
zoomOutAnimator.duration = DEFAULT_DURATION
zoomOutAnimator.doOnEnd { removeFromParent() }
if (showVerticalTranslateAnimation) {
showAnimatorSet.play(translateUpAnimator).with(zoomInAnimator).before(translateToLeftAnimator)
} else {
showAnimatorSet.play(zoomInAnimator).before(translateToLeftAnimator)
}
showAnimatorSet.start()
}
private fun enableSwipeToDismiss() {
cardView?.setOnTouchListener(SwipeDismissTouchListener(cardView, object : SwipeDismissTouchListener.DismissCallbacks {
override fun canDismiss(): Boolean {
return true
}
override fun onDismiss(view: View) {
removeFromParent()
}
override fun onTouch(view: View, touch: Boolean) {
// Ignore.
}
}))
}
private fun disableSwipeToDismiss() {
cardView?.setOnTouchListener(null)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
showAnimatorSet.cancel()
hideAnimatorSet.cancel()
try {
removeAllListeners(expandAnimator,
shrinkAnimator,
translateUpAnimator,
translateDownAnimator,
translateToLeftAnimator,
translateToRightAnimator)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun removeAllListeners(vararg ts: Animator) {
for (a in ts) {
a.removeAllListeners()
if (a is ValueAnimator) {
a.removeAllUpdateListeners()
}
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
performClick()
return super.onTouchEvent(event)
}
private fun shrinkAfterDelay() {
postDelayed({ shrink() }, duration)
}
private fun shrink() {
shrinkAnimator.doOnEnd { hide() }
shrinkAnimator.start()
}
private fun removeFromParent() {
clearAnimation()
visibility = View.GONE
postDelayed(object : Runnable {
override fun run() {
try {
if (parent == null) {
Log.e(javaClass.simpleName, "getParent() returning Null")
} else {
try {
(parent as ViewGroup).removeView(this@NotifierView)
onHideListener?.onHide()
} catch (ex: Exception) {
Log.e(javaClass.simpleName, "Cannot remove from parent layout")
}
}
} catch (ex: Exception) {
Log.e(javaClass.simpleName, Log.getStackTraceString(ex))
}
}
}, 100)
}
fun setText(text: String?) {
if (!TextUtils.isEmpty(text)) {
tvText.text = text
tvText.measure(0, 0)
textWidth = tvText.measuredWidth
tvText.width = 0
cardView.measure(0, 0)
cardViewWidth = cardView.measuredWidth
}
}
fun hide() {
if (showVerticalTranslateAnimation) {
hideAnimatorSet.play(translateDownAnimator).with(zoomOutAnimator).after(translateToRightAnimator)
} else {
hideAnimatorSet.play(zoomOutAnimator).after(translateToRightAnimator)
}
hideAnimatorSet.start()
}
fun setIcon(url: String) {
ImageUtils.display(ivIcon, url)
}
private fun dp2px(dp: Float): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.applicationContext.resources.displayMetrics).toInt()
}
private fun hasSoftKeys(): Boolean {
if (context !is Activity) return false
val hasSoftwareKeys: Boolean
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
val d = (context as Activity).windowManager.defaultDisplay
val realDisplayMetrics = DisplayMetrics()
d.getRealMetrics(realDisplayMetrics)
val realHeight = realDisplayMetrics.heightPixels
val realWidth = realDisplayMetrics.widthPixels
val displayMetrics = DisplayMetrics()
d.getMetrics(displayMetrics)
val displayHeight = displayMetrics.heightPixels
val displayWidth = displayMetrics.widthPixels
hasSoftwareKeys = realWidth - displayWidth > 0 || realHeight - displayHeight > 0
} else {
val hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey()
val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
hasSoftwareKeys = !hasMenuKey && !hasBackKey
}
return hasSoftwareKeys
}
private fun retrieveNavigationHeight(): Int {
val resources = context.resources
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0 && hasSoftKeys()) resources.getDimensionPixelSize(resourceId) else 0
}
interface OnShowNotificationListener {
fun onShow()
}
interface OnHideNotificationListener {
fun onHide()
}
}

View File

@ -0,0 +1,238 @@
package com.gh.common.notifier
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Modifications Copyright (C) 2017 David Kwon
*/
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.os.Build
import android.support.annotation.RequiresApi
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewConfiguration
/**
* A [View.OnTouchListener] that makes any [View] dismissable when the
* user swipes (drags her finger) horizontally across the view.
*
* @param view The view to make dismissable.
* @param callbacks The callback to trigger when the user has indicated that she would like to
* dismiss this view.
*/
class SwipeDismissTouchListener(
private val mView: View,
private val mCallbacks: DismissCallbacks) : View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values
private val mSlop: Int
private val mMinFlingVelocity: Int
private val mAnimationTime: Long
private var mViewWidth = 1 // 1 and not 0 to prevent dividing by zero
// Transient properties
private var mDownX: Float = 0.toFloat()
private var mDownY: Float = 0.toFloat()
private var mSwiping: Boolean = false
private var mSwipingSlop: Int = 0
private var mVelocityTracker: VelocityTracker? = null
private var mTranslationX: Float = 0.toFloat()
init {
val vc = ViewConfiguration.get(mView.context)
mSlop = vc.scaledTouchSlop
mMinFlingVelocity = vc.scaledMinimumFlingVelocity * 16
mAnimationTime = mView.context.resources.getInteger(
android.R.integer.config_shortAnimTime).toLong()
}
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
// offset because the view is translated during swipe
motionEvent.offsetLocation(mTranslationX, 0f)
if (mViewWidth < 2) {
mViewWidth = mView.width
}
when (motionEvent.actionMasked) {
MotionEvent.ACTION_DOWN -> {
mDownX = motionEvent.rawX
mDownY = motionEvent.rawY
if (mCallbacks.canDismiss()) {
mVelocityTracker = VelocityTracker.obtain()
mVelocityTracker!!.addMovement(motionEvent)
}
mCallbacks.onTouch(view, true)
return false
}
MotionEvent.ACTION_UP -> {
mVelocityTracker?.run {
val deltaX = motionEvent.rawX - mDownX
this.addMovement(motionEvent)
this.computeCurrentVelocity(1000)
val velocityX = this.xVelocity
val absVelocityX = Math.abs(velocityX)
val absVelocityY = Math.abs(this.yVelocity)
var dismiss = false
var dismissRight = false
if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
dismiss = true
dismissRight = deltaX > 0
} else if (mMinFlingVelocity <= absVelocityX && absVelocityY < absVelocityX && mSwiping) {
// dismiss only if flinging in the same direction as dragging
dismiss = velocityX < 0 == deltaX < 0
dismissRight = this.xVelocity > 0
}
if (dismiss) {
// dismiss
mView.animate()
.translationX((if (dismissRight) mViewWidth else -mViewWidth).toFloat())
.alpha(0f)
.setDuration(mAnimationTime)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
performDismiss()
}
})
} else if (mSwiping) {
// cancel
mView.animate()
.translationX(0f)
.alpha(1f)
.setDuration(mAnimationTime)
.setListener(null)
mCallbacks.onTouch(view, false)
}
this.recycle()
mVelocityTracker = null
mTranslationX = 0f
mDownX = 0f
mDownY = 0f
mSwiping = false
}
}
MotionEvent.ACTION_CANCEL -> {
mVelocityTracker?.run {
mView.animate()
.translationX(0f)
.alpha(1f)
.setDuration(mAnimationTime)
.setListener(null)
this.recycle()
mVelocityTracker = null
mTranslationX = 0f
mDownX = 0f
mDownY = 0f
mSwiping = false
}
}
MotionEvent.ACTION_MOVE -> {
mVelocityTracker?.run {
this.addMovement(motionEvent)
val deltaX = motionEvent.rawX - mDownX
val deltaY = motionEvent.rawY - mDownY
if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
mSwiping = true
mSwipingSlop = if (deltaX > 0) mSlop else -mSlop
mView.parent.requestDisallowInterceptTouchEvent(true)
// Cancel listview's touch
val cancelEvent = MotionEvent.obtain(motionEvent)
cancelEvent.action = MotionEvent.ACTION_CANCEL or (motionEvent.actionIndex shl MotionEvent.ACTION_POINTER_INDEX_SHIFT)
mView.onTouchEvent(cancelEvent)
cancelEvent.recycle()
}
if (mSwiping) {
mTranslationX = deltaX
mView.translationX = deltaX - mSwipingSlop
// TODO: use an ease-out interpolator or such
mView.alpha = Math.max(0f, Math.min(1f,
1f - 2f * Math.abs(deltaX) / mViewWidth))
return true
}
}
}
else -> {
view.performClick()
return false
}
}
return false
}
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
private fun performDismiss() {
// Animate the dismissed view to zero-height and then fire the dismiss callback.
// This triggers layout on each animation frame; in the future we may want to do something
// smarter and more performant.
val lp = mView.layoutParams
val originalHeight = mView.height
val animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime)
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
mCallbacks.onDismiss(mView)
// Reset view presentation
mView.alpha = 1f
mView.translationX = 0f
lp.height = originalHeight
mView.layoutParams = lp
}
})
animator.addUpdateListener { valueAnimator ->
lp.height = valueAnimator.animatedValue as Int
mView.layoutParams = lp
}
animator.start()
}
/**
* The callback interface used by [SwipeDismissTouchListener] to inform its client
* about a successful dismissal of the view for which it was created.
*/
interface DismissCallbacks {
/**
* Called to determine whether the view can be dismissed.
*
* @return boolean The view can dismiss.
*/
fun canDismiss(): Boolean
/**
* Called when the user has indicated they she would like to dismiss the view.
*
* @param view The originating [View]
*/
fun onDismiss(view: View)
/**
* Called when the user touches the view or release the view.
*
* @param view The originating [View]
* @param touch The view is being touched.
*/
fun onTouch(view: View, touch: Boolean)
}
}

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

@ -0,0 +1,128 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.gh.common.util
import android.animation.Animator
import android.support.annotation.RequiresApi
/**
* Since [Android KTX] has not release a stable build yet,
* we copy a single class to achieve the same goal.
*
* You might check the original extension class in the link below.
*
* https://github.com/android/android-ktx/blob/master/src/main/java/androidx/core/animation/Animator.kt.
*/
/**
* Add an action which will be invoked when the animation has ended.
*
* @return the [Animator.AnimatorListener] added to the Animator
* @see Animator.end
*/
fun Animator.doOnEnd(action: (animator: Animator) -> Unit) = addListener(onEnd = action)
/**
* Add an action which will be invoked when the animation has started.
*
* @return the [Animator.AnimatorListener] added to the Animator
* @see Animator.start
*/
fun Animator.doOnStart(action: (animator: Animator) -> Unit) = addListener(onStart = action)
/**
* Add an action which will be invoked when the animation has been cancelled.
*
* @return the [Animator.AnimatorListener] added to the Animator
* @see Animator.cancel
*/
fun Animator.doOnCancel(action: (animator: Animator) -> Unit) = addListener(onCancel = action)
/**
* Add an action which will be invoked when the animation has repeated.
* @return the [Animator.AnimatorListener] added to the Animator
*/
fun Animator.doOnRepeat(action: (animator: Animator) -> Unit) = addListener(onRepeat = action)
/**
* Add an action which will be invoked when the animation has resumed after a pause.
*
* @return the [Animator.AnimatorPauseListener] added to the Animator
* @see Animator.resume
*/
@RequiresApi(19)
fun Animator.doOnResume(action: (animator: Animator) -> Unit) = addPauseListener(onResume = action)
/**
* Add an action which will be invoked when the animation has been paused.
*
* @return the [Animator.AnimatorPauseListener] added to the Animator
* @see Animator.pause
*/
@RequiresApi(19)
fun Animator.doOnPause(action: (animator: Animator) -> Unit) = addPauseListener(onPause = action)
/**
* Add a listener to this Animator using the provided actions.
*/
fun Animator.addListener(
onEnd: ((animator: Animator) -> Unit)? = null,
onStart: ((animator: Animator) -> Unit)? = null,
onCancel: ((animator: Animator) -> Unit)? = null,
onRepeat: ((animator: Animator) -> Unit)? = null
): Animator.AnimatorListener {
val listener = object : Animator.AnimatorListener {
override fun onAnimationRepeat(animator: Animator) {
onRepeat?.invoke(animator)
}
override fun onAnimationEnd(animator: Animator) {
onEnd?.invoke(animator)
}
override fun onAnimationCancel(animator: Animator) {
onCancel?.invoke(animator)
}
override fun onAnimationStart(animator: Animator) {
onStart?.invoke(animator)
}
}
addListener(listener)
return listener
}
/**
* Add a pause and resume listener to this Animator using the provided actions.
*/
@RequiresApi(19)
fun Animator.addPauseListener(
onResume: ((animator: Animator) -> Unit)? = null,
onPause: ((animator: Animator) -> Unit)? = null
): Animator.AnimatorPauseListener {
val listener = object : Animator.AnimatorPauseListener {
override fun onAnimationPause(animator: Animator) {
onPause?.invoke(animator)
}
override fun onAnimationResume(animator: Animator) {
onResume?.invoke(animator)
}
}
addPauseListener(listener)
return listener
}

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

@ -2,7 +2,6 @@ package com.gh.common.util;
import android.text.TextUtils;
import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -12,16 +11,16 @@ import java.util.regex.Pattern;
public class AskUtils {
public static String voteCountFormat(int voteCount) {
String vote;
if (voteCount >= 10000) {
DecimalFormat df = new DecimalFormat("#.0万");
vote = df.format(voteCount / 10000f);
} else {
vote = String.valueOf(voteCount);
}
return vote;
}
// public static String voteCountFormat(int voteCount) {
// String vote;
// if (voteCount >= 10000) {
// DecimalFormat df = new DecimalFormat("#.0万");
// vote = df.format(voteCount / 10000f);
// } else {
// vote = String.valueOf(voteCount);
// }
// return vote;
// }
public static String stripHtml(String htmlStr) {

View File

@ -6,6 +6,7 @@ import android.text.TextUtils;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.manager.UserManager;
import com.lightgame.utils.Utils;
/**
* Created by khy on 28/06/17.
@ -13,19 +14,13 @@ import com.gh.gamecenter.manager.UserManager;
public class CheckLoginUtils {
public static void checkLogin(final Context context, OnLoginListener listener) {
// String token = LoginUtils.getToken(context);
public static void checkLogin(final Context context, String entrance, OnLoginListener listener) {
if (TextUtils.isEmpty(UserManager.getInstance().getToken())) {
AskLogUtils.login(context, "dialog", null);
DialogUtils.showWarningDialog(context, "登录提示", "需要登录才能使用该功能喔!", "取消", "快速登录",
new DialogUtils.ConfirmListener() {
@Override
public void onConfirm() {
AskLogUtils.login(context, "activity", null);
Intent intent = LoginActivity.getIntent(context);
context.startActivity(intent);
}
}, null);
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();
}

View File

@ -10,7 +10,11 @@ public class ClassUtils {
name = "GameDetailActivity";
}
try {
return Class.forName("com.gh.gamecenter." + name);
if (!name.contains("com.gh")) {
return Class.forName("com.gh.gamecenter." + name);
} else {
return Class.forName(name);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

View File

@ -5,13 +5,13 @@ import com.gh.gamecenter.eventbus.EBCollectionChanged
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import retrofit2.HttpException
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
/**
* Created by khy on 26/07/17.
@ -19,7 +19,7 @@ import rx.schedulers.Schedulers
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,17 +568,17 @@ 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(String.valueOf(entity.getVote()));
holder.commentLikeCountTv.setText(NumberUtils.transSimpleCount(entity.getVote()));
}
//检查是否是自身评论
@ -456,17 +589,27 @@ public class CommentUtils {
} else {
holder.commentUserNameTv.setText(userInfo.getName());
}
ImageUtils.Companion.display(holder.commentUserIconDv, userInfo.getIcon());
if (userInfo.getAuth() != null) {
ImageUtils.display(holder.commentUserBadgeIv, userInfo.getAuth().getIcon());
} else {
ImageUtils.display(holder.commentUserBadgeIv, "");
}
ImageUtils.displayIcon(holder.commentUserIconDv, userInfo.getIcon());
} else {
if (entity.getMe() != null && entity.getMe().isAnswerOwn()) {
holder.commentUserNameTv.setText(entity.getUser().getName() + "(作者)");
} else {
holder.commentUserNameTv.setText(entity.getUser().getName());
}
if (TextUtils.isEmpty(entity.getUser().getIcon())) {
ImageUtils.Companion.display(holder.commentUserIconDv, R.drawable.user_default_icon_comment);
if (entity.getUser().getAuth() != null) {
ImageUtils.display(holder.commentUserBadgeIv, entity.getUser().getAuth().getIcon());
} else {
ImageUtils.Companion.display(holder.commentUserIconDv, entity.getUser().getIcon());
ImageUtils.display(holder.commentUserBadgeIv, "");
}
if (TextUtils.isEmpty(entity.getUser().getIcon())) {
ImageUtils.display(holder.commentUserIconDv, R.drawable.user_default_icon_comment);
} else {
ImageUtils.displayIcon(holder.commentUserIconDv, entity.getUser().getIcon());
}
}
}

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

@ -0,0 +1,163 @@
package com.gh.common.util
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import com.gh.common.constant.Config
import com.gh.gamecenter.entity.SettingsEntity
import com.halo.assistant.HaloApp
import java.io.File
import java.io.FileOutputStream
/**
* Created by khy on 02/08/18.
* 图片压缩工具类
* 资料参考:https://github.com/zetbaitsu/Compressor
* 压缩算法:http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/298
*/
object CompressImageUtils {
private const val compressLimitSize: Long = 50 * 1024
private const val defaultQuality = 90
private const val defaultRatio = 2
private const val defaultCompressBorder = 1280
/**
* 压缩图片并保存到目标文件
* 该压缩方法是同步执行 请勿在主线程执行
* 返回源文件的三种情况:小于特定值,图片类型为GIF,压缩失败
*/
@Throws(Exception::class)
fun compressImageAndSaveToFile(imageFile: File, compressGif: Boolean): File {
// 小于300K直接返回原图
if (imageFile.length() < getImageSetting().processLimitSize) {
return imageFile
}
val cacheDir = getImageCacheDir()
val parentFile = cacheDir.parentFile
if (!parentFile.exists()) parentFile.mkdirs()
var fileOutputStream: FileOutputStream? = null
try {
// 确定图片类型
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(imageFile.absolutePath, options)
val formatType = if (options.outMimeType.contains("png")) {
Bitmap.CompressFormat.PNG
} else if (options.outMimeType.contains("gif") && !compressGif) { // gif直接返回原图
return imageFile
} else {
Bitmap.CompressFormat.WEBP
}
fileOutputStream = FileOutputStream(cacheDir)
// write the compressed bitmap at the destination specified by destinationPath.
decodeSampledBitmapFromFile(imageFile).compress(formatType, getImageSetting().quality, fileOutputStream)
return cacheDir
} catch (e: Exception) {
e.printStackTrace()
if (cacheDir.exists()) {
cacheDir.delete()
}
} finally {
if (fileOutputStream != null) {
fileOutputStream.flush()
fileOutputStream.close()
}
}
return imageFile
}
private fun getImageCacheDir(): File {
// return File(Environment.getExternalStorageDirectory().absolutePath + "/Pictures/test/" + System.currentTimeMillis() + ".jpg")
// 统一用jpg保存应该没有影响吧
return File(HaloApp.getInstance().application.cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg")
}
// 根据图片获取压缩后的位图
@Throws(Exception::class)
private fun decodeSampledBitmapFromFile(imageFile: File): Bitmap {
// First decode with inJustDecodeBounds=true to check dimensions
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(imageFile.absolutePath, options)
// Raw height and width of image
val height = options.outHeight
val width = options.outWidth
var inSampleSize = 1
var compressType: CompressType? = null
val longSide = Math.max(height, width) //最长边
val shortSide = Math.min(height, width) //最短边
val scale = longSide.toFloat() / shortSide // 长短边比例
val compressLimit = getImageSetting().size
if (longSide > compressLimit && shortSide > compressLimit) {
if (scale > getImageSetting().ratio) {
inSampleSize = if (shortSide / compressLimit == 0) 1 else shortSide / compressLimit
compressType = CompressType.LIMIT_SHORT // 横向长方形
} else {
inSampleSize = if (longSide / compressLimit == 0) 1 else longSide / compressLimit
compressType = CompressType.LIMIT_LONG // 纵向长方形
}
} else if (longSide > compressLimit && shortSide < compressLimit) {
if (scale <= getImageSetting().ratio) {
inSampleSize = if (longSide / compressLimit == 0) 1 else longSide / compressLimit
compressType = CompressType.LIMIT_LONG
}
}
// Calculate inSampleSize
options.inSampleSize = inSampleSize
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false
var scaledBitmap = BitmapFactory.decodeFile(imageFile.absolutePath, options)
val matrix = Matrix() // 精确缩放
if (compressType != null) {
val targetMatrixScale = if (compressType == CompressType.LIMIT_SHORT) {
if (scaledBitmap.width > scaledBitmap.height) {
compressLimit.toFloat() / scaledBitmap.height
} else {
compressLimit.toFloat() / scaledBitmap.width
}
} else {
if (scaledBitmap.width > scaledBitmap.height) {
compressLimit.toFloat() / scaledBitmap.width
} else {
compressLimit.toFloat() / scaledBitmap.height
}
}
matrix.setScale(targetMatrixScale, targetMatrixScale)
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.width, scaledBitmap.height, matrix, true)
}
return scaledBitmap
}
fun getImageSetting(): SettingsEntity.Image {
val settings = Config.getSettings()
if (settings == null && settings?.image != null) {
return settings.image!!
}
val image = SettingsEntity.Image()
image.processLimitSize = compressLimitSize
image.size = defaultCompressBorder
image.ratio = defaultRatio
image.quality = defaultQuality
return image
}
}
enum class CompressType {
// 0: 短边等比压缩至1280 H:长边 W:短边
LIMIT_SHORT,
// 1: 取长边等比压缩至1280 H:短边 W: 长边
LIMIT_LONG
}

View File

@ -69,7 +69,7 @@ public class ConcernContentUtils {
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
lparams.weight = 1;
imageView.setLayoutParams(lparams);
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
ImageUtils.display(context.getResources(), imageView, width / 3 - DisplayUtils.dip2px(context, 4),
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
break;
case 1:
@ -78,7 +78,7 @@ public class ConcernContentUtils {
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
imageView.setLayoutParams(lparams);
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
ImageUtils.display(context.getResources(), imageView, lparams.width,
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
break;
default:
@ -89,7 +89,7 @@ public class ConcernContentUtils {
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
lparams.weight = 1;
imageView.setLayoutParams(lparams);
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
ImageUtils.display(context.getResources(), imageView, width / 2 - DisplayUtils.dip2px(context, 4),
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
break;
}

View File

@ -5,14 +5,14 @@ import com.gh.gamecenter.eventbus.EBConcernChanged
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONArray
import retrofit2.HttpException
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
/**
* Created by khy on 2016/8/24.
@ -21,9 +21,6 @@ import rx.schedulers.Schedulers
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)
.subscribeOn(Schedulers.io())
@ -69,8 +66,7 @@ object ConcernUtils {
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody) {
super.onResponse(response)
override fun onResponse(response: ResponseBody?) {
EventBus.getDefault().post(EBConcernChanged())
}
})

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

@ -2,10 +2,11 @@ package com.gh.common.util;
import android.content.Context;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.gh.gamecenter.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Util_System_Phone_State;
import com.lightgame.utils.Utils;
import org.json.JSONObject;
@ -13,11 +14,11 @@ import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by LGT on 2016/12/8.
@ -37,12 +38,12 @@ 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);
map.put("user", user);
map.put("device_id", TokenUtils.getDeviceId(context));
map.put("device_id", Util_System_Phone_State.getDeviceId(context));
map.put("channel", channel);
Map<String, String> params = new HashMap<>();

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) {
@ -163,26 +152,55 @@ public class DataUtils {
StatService.trackCustomKVEvent(var0, var1, prop);
}
public static void trackTimeEvent(Context context, String eventId, int costTime, String... 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);
}
}
}
if (prop.size() == 0) return;
StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
}
// 游戏下载
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status) {
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
Map<String, Object> kv = new HashMap<>();
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
kv.put("版本", platform);
kv.put("状态", status);
kv.put("用户机型", Build.MODEL);
kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
kv.put("位置", entrance);
kv.put("类型", method);
kv.put("厂商", Build.MANUFACTURER);
kv.put("Android版本", Build.VERSION.RELEASE);
onEvent(context, "游戏下载", gameName, kv);
Map<String, Object> kv2 = new HashMap<>();
kv2.put("版本", 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

@ -0,0 +1,134 @@
package com.gh.common.util
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.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Phone_State
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.File
object DeviceTokenUtils {
const val DEVICE_ID = "uuid"
// 同步服务器时间
@JvmStatic
@Synchronized
fun syncServerTime(context: Context) {
val sp = PreferenceManager.getDefaultSharedPreferences(context)
RetrofitManager.getInstance(context).api.time
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.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()
}
}
})
}
@JvmStatic
fun getLaunchType(): LunchType {
var lunchType: LunchType? = null
val values = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application).all
// 版本更新
if (values.isNotEmpty()) {
for (value in values) {
if (value.key.contains("isNewFirstLaunchV")) {
lunchType = LunchType.UPDATE
break
}
}
}
// 再次重装
if (lunchType == null && !getDeviceId().isNullOrEmpty()) {
lunchType = LunchType.AGAIN
}
// 首次安装
if (lunchType == null) {
lunchType = LunchType.FIRST
}
// 保存deviceId
var deviceId = Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
if (deviceId.isNullOrEmpty()) {
deviceId = Utils.getTime(HaloApp.getInstance().application).toString()
}
setDeviceId(deviceId)
return lunchType
}
private fun getDeviceFileList(): List<File> {
val sdCardDir = Environment.getExternalStorageDirectory()
val fileList: MutableList<File> = ArrayList()
fileList.add(File(sdCardDir.path + "/gh-uuid/$DEVICE_ID"))
fileList.add(File(sdCardDir.path + "/system/$DEVICE_ID"))
fileList.add(File(sdCardDir.path + "/data/$DEVICE_ID"))
return fileList
}
@Synchronized
private fun setDeviceId(deviceId: String) {
//将deviceId存到sp
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application)
val edit = sp.edit()
edit.putString(DEVICE_ID, deviceId)
edit.apply()
Utils.log("saveDeviceId", "保存成功SP")
//将deviceId存到SD卡
for (file in getDeviceFileList()) {
try {
val parentFile = file.parentFile
if (!parentFile.exists()) parentFile.mkdirs()
file.writeText(deviceId)
Utils.log("saveDeviceId", "保存成功SDCard目录为${file.path}")
} catch (e: Exception) {
Utils.log("保存u${DEVICE_ID}到SDCard异常${file.path} " + e.toString())
e.printStackTrace()
}
}
}
private fun getDeviceId(): String? {
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application)
var deviceId = sp.getString(DEVICE_ID, null)
if (deviceId.isNullOrEmpty()) {
val fileList = getDeviceFileList()
for (file in fileList) {
if (file.exists()) {
try {
deviceId = file.readText()
Utils.log("getDeviceId", "获取成功DataFile$DEVICE_ID")
return deviceId
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
if (BuildConfig.DEBUG) {
Utils.log("getDeviceId", "获取成功SP$DEVICE_ID")
}
return deviceId
}
}
enum class LunchType {
FIRST,
UPDATE,
AGAIN
}

View File

@ -158,45 +158,50 @@ public class DeviceUtils {
}
public static String getNetwork(Context context) {
NetworkInfo info = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connManager == null) return null;
NetworkInfo info = connManager.getActiveNetworkInfo();
if (info != null && info.isConnected()) {
int typeMobile = info.getType();
if (typeMobile == ConnectivityManager.TYPE_WIFI) {
return "WIFI";
} else if (typeMobile == ConnectivityManager.TYPE_MOBILE) {
String status;
switch (typeMobile) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
status = "2G";
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
status = "3G";
break;
case TelephonyManager.NETWORK_TYPE_LTE:
status = "4G";
break;
default:
status = "未知";
break;
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager != null) {
int networkType = telephonyManager.getNetworkType();
String status;
switch (networkType) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
status = "2G";
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
status = "3G";
break;
case TelephonyManager.NETWORK_TYPE_LTE:
status = "4G";
break;
default:
status = "未知";
break;
}
return status;
}
return status;
}
}
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;
}
@ -345,15 +348,66 @@ public class DialogUtils {
, "取消", "前往QQ", new ConfirmListener() {
@Override
public void onConfirm() {
QQUtils.startQQSession(context, qq);
DirectUtils.directToQqConversation(context, qq);
}
}, 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

@ -0,0 +1,301 @@
package com.gh.common.util
import android.content.Context
import android.content.Intent
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.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
import org.greenrobot.eventbus.EventBus
/**
* 跳转用的方法
*/
object DirectUtils {
/**
* 跳转到特定页面,根据 [type] 决定跳转页面,[path] 为跳转前的页面名称
*/
@JvmStatic
fun directToSpecificPage(context: Context, type: String, link: String, text: String? = "", entrance: String? = null, path: String? = null) {
when (type) {
EntranceUtils.HOST_ARTICLE -> directToArticle(context, id = link, entrance = entrance)
EntranceUtils.HOST_GAME -> directToGameDetail(context, id = link, entrance = entrance)
EntranceUtils.HOST_GAME_DOWNLOAD -> directToGameDetail(context, id = link, entrance = entrance, autoDownload = true)
EntranceUtils.HOST_COLUMN -> directToSubject(context, id = link, subjectName = text, entrance = entrance)
EntranceUtils.HOST_QUESTION -> directToQuestionDetail(context, id = link, entrance = entrance, path = path)
EntranceUtils.HOST_ANSWER -> directToAnswerDetail(context, id = link, entrance = entrance, path = path)
EntranceUtils.HOST_WEB -> directToWebView(context, url = link, entrance = entrance)
EntranceUtils.HOST_DOWNLOAD -> directToDownloadManagerAndStartDownload(context, gameId = link, packageName = text, entrance = entrance)
EntranceUtils.HOST_UPDATE -> directToDownloadManagerAndStartUpdate(context, gameId = link, packageName = text, entrance = entrance)
EntranceUtils.HOST_LIBAO -> directToGiftDetail(context, giftId = link, entrance = entrance)
EntranceUtils.HOST_COMMUNITY -> directToCommunity(context, CommunityEntity(link, text!!))
}
}
/**
* 跳转到特定页面,只支持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)
}
}
/**
* 跳转到文章详情
*/
@JvmStatic
fun directToArticle(context: Context, id: String, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, NewsDetailActivity::class.java.simpleName)
bundle.putString(KEY_NEWSID, id)
EntranceUtils.jumpActivity(context, bundle)
}
/**
* 跳转到游戏详情
*/
@JvmStatic
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, GameDetailActivity::class.java.simpleName)
bundle.putString(KEY_GAMEID, id)
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
EntranceUtils.jumpActivity(context, bundle)
}
// 专栏
@JvmStatic
fun directToSubject(context: Context, id: String, subjectName: String? = "", entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
bundle.putParcelable(EntranceUtils.KEY_SUBJECT_DATA, SubjectData(id, subjectName, false, null, null, null, null))
EntranceUtils.jumpActivity(context, bundle)
}
// 反馈
@JvmStatic
fun directToFeedback(context: Context, content: String? = null, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SuggestionActivity::class.java.simpleName)
bundle.putString(KEY_CONTENT, content)
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
bundle.putSerializable(EntranceUtils.KEY_SUGGESTTYPE, SuggestType.gameQuestion)
EntranceUtils.jumpActivity(context, bundle)
}
@JvmStatic
fun directToDownloadManager(context: Context, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
EntranceUtils.jumpActivity(context, bundle)
}
/**
* 跳转到下载管理器并开始下载 [gameId] 和 [packageName] 用于唯一确定一个下载文件
*/
@JvmStatic
fun directToDownloadManagerAndStartDownload(context: Context, gameId: String? = "", packageName: String? = "", entrance: String? = null) {
DownloadHelper.createABrandNewDownloadTaskQuietly(gameId, packageName) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
bundle.putString(KEY_GAMEID, gameId)
bundle.putString(KEY_PACKAGENAME, packageName)
bundle.putBoolean(KEY_AUTO_DOWNLOAD, true)
EntranceUtils.jumpActivity(context, bundle)
}
}
@JvmStatic
fun directToDownloadManagerAndStartUpdate(context: Context, gameId: String? = "", packageName: String? = "", entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
bundle.putString(KEY_GAMEID, gameId)
bundle.putString(KEY_PACKAGENAME, packageName)
bundle.putInt(BaseFragment_TabLayout.PAGE_INDEX, INDEX_UPDATE)
EntranceUtils.jumpActivity(context, bundle)
}
@JvmStatic
fun directToAnswerDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, AnswerDetailActivity::class.java.name)
bundle.putString(KEY_PATH, path)
bundle.putString(KEY_ANSWER_ID, id)
EntranceUtils.jumpActivity(context, bundle)
}
@JvmStatic
fun directToQuestionDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, QuestionsDetailActivity::class.java.name)
bundle.putString(KEY_PATH, path)
bundle.putString(KEY_QUESTIONS_ID, id)
EntranceUtils.jumpActivity(context, bundle)
}
@JvmStatic
fun directToWebView(context: Context, url: String, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(EntranceUtils.KEY_TO, WebActivity::class.java.simpleName)
bundle.putString(EntranceUtils.KEY_URL, url)
EntranceUtils.jumpActivity(context, bundle)
}
// 个人-系统消息
@JvmStatic
fun directToOfficialNotification(context: Context, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(EntranceUtils.KEY_TO, MessageKeFuActivity::class.java.simpleName)
EntranceUtils.jumpActivity(context, bundle)
}
// 跳转 QQ
@JvmStatic
fun directToQqConversation(context: Context, qqNumber: String? = null) {
var qq = qqNumber
if (TextUtils.isEmpty(qq)) {
qq = "2586716223"
}
if (ShareUtils.isQQClientAvailable(context)) {
// 安装了 QQ 直接调用QQ打开手机QQ进行会话 默认 QQ 号2586716223
val chatType: String
if (qq!!.startsWith("400") || qq.startsWith("800")) {
chatType = "crm"
} else {
chatType = "wpa"
}
val str = "mqqwpa://im/chat?chat_type=$chatType&uin=$qq&version=1&src_type=web"
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(str)))
} else {
// 没有安装QQ 复制账号
Util_System_ClipboardManager.setText(context, qq)
Utils.toast(context, "已复制 QQ $qq")
}
}
// 跳转 QQ 群
@JvmStatic
fun directToQqGroup(context: Context, groupNumber: String? = null): Boolean {
val intent = Intent()
intent.data = Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$groupNumber")
// 此Flag可根据具体产品需要自定义如设置则在加群界面按返回返回手Q主界面不设置按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent)
return true
} catch (e: Exception) {
// 未安装手Q或安装的版本不支持
return false
}
}
/**
* 跳转到 礼包详情
*/
@JvmStatic
fun directToGiftDetail(context: Context, giftId: String, entrance: String? = null) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(EntranceUtils.KEY_TO, LibaoDetailActivity::class.java.simpleName)
bundle.putString(EntranceUtils.KEY_ID, giftId)
EntranceUtils.jumpActivity(context, bundle)
}
/**
* 切换到社区页面
*/
@JvmStatic
fun directToCommunity(context: Context, community: CommunityEntity?) {
if (MainActivity::class.java.name != RunningUtils.getTopActivity(context)) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
}
UserManager.getInstance().setCommunityData(community)
// 这里换个线程操作是为了做一点延时
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

@ -0,0 +1,52 @@
package com.gh.common.util
import com.gh.download.DownloadManager
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
/**
* 不想写这个类的,但是与其在一个糟糕的类里插入同样的代码,我想独立写一个类相较而已还没那么糟糕
*/
object DownloadHelper {
/**
* 根据 game_id 和 packageName 悄悄地开启一个下载任务,如果可以的话
* @param block 成功添加下载任务后执行的代码块
*/
fun createABrandNewDownloadTaskQuietly(gameId: String? = "", packageName: String? = "", block: () -> Unit) {
RetrofitManager.getInstance(HaloApp.getInstance().application)
.api
.getGameDigest(gameId)
.map(ApkActiveUtils.filterMapper)
.subscribeOn(Schedulers.io())
.subscribe(object : Response<GameEntity>() {
override fun onResponse(response: GameEntity?) {
response?.let {
if (response.getApk().size > 1) {
for (apk in response.getApk()) {
if (packageName == apk.packageName) {
DownloadManager.createDownload(HaloApp.getInstance().application,
apk, response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", false, null)
block.invoke()
}
}
} else if (response.getApk().size == 1) {
DownloadManager.createDownload(HaloApp.getInstance().application,
response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", false, null)
block.invoke()
}
}
}
override fun onFailure(e: HttpException?) {
e?.printStackTrace()
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;
@ -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,21 @@ 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) {
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 {
@ -224,6 +177,8 @@ 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);
@ -274,7 +229,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 +240,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 +258,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 +316,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,14 +353,15 @@ 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)) {
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "下载");
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
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 +376,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, "下载开始");
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "插件化");
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.PLUGIN_DOWNLOAD);
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 +417,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.INSTANCE.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.UPDATE);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, downloadExposureEvent);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.UPDATE);
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, downloadExposureEvent);
}
}

View File

@ -25,22 +25,33 @@ 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";
public static final String HOST_WEB = "web";
public static final String HOST_QQ = "qq";
public static final String HOST_DOWNLOAD = "download";
public static final String HOST_UPDATE = "update";
public static final String HOST_LIBAO = "libao";
public static final String HOST_COMMUNITY = "community";
public static final String HOST_SUGGESTION = "suggestion";
public static final String HOST_ANSWER = "answer";
public static final String HOST_QUESTION = "question";
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";
public static final String ENTRANCE_BROWSER = "(浏览器)";
public static final String ENTRANCE_WELCOME = "(启动弹窗)";
public static final String ENTRANCE_UMENG = "(友盟推送)";
public static final String ENTRANCE_MIPUSH = "(小米推送)";
public static final String ENTRANCE_DOWNLOAD = "(下载跳转)";
public static final String ENTRANCE_RECOMMEND = "(落地页)";
public static final String ENTRANCE_BLOCK_RECOMMEND = "(推荐入口)";
public static final String KEY_SUGGEST_HINT_TYPE = "suggestHintType";
public static final String KEY_PACKAGENAME = "packageName";
public static final String KEY_PLATFORM = "platform";
@ -51,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";
@ -70,6 +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_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";
@ -80,9 +93,24 @@ public class EntranceUtils {
public static final String KEY_BLOCK_DATA = "blockData";
public static final String KEY_ASK_TAG = "askTag";
public static final String KEY_ASK_COLUMN_TAG = "askColumnTag";
public static final String KEY_COMMUNITY_ID = "community_id";
public static final String KEY_COMMUNITY_NAME = "community_name";
public static final String KEY_COMMUNITY_DATA = "communityData";
public static final String KEY_TRACE_EVENT = "trace_event";
public static final String KEY_SUBJECT_DATA = "subjectData";
public static final String KEY_SHOW_SELECT_COMMUNITY = "show_select_community";
public static final String KEY_USER_ID = "user_id";
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_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,95 @@
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
/**
* 创建以 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()
}
}

View File

@ -12,7 +12,8 @@ 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.manager.PackagesManager;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
@ -46,13 +47,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,7 +64,7 @@ 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; // 可更新数量
@ -90,14 +91,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 +107,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 +141,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

@ -11,6 +11,7 @@ class GsonUtils private constructor() {
val mGson: Gson = Gson()
companion object {
@JvmStatic
fun getInstance(): GsonUtils {
return Inner.anotherSingle
}

View File

@ -7,7 +7,6 @@ import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.support.annotation.DrawableRes
import android.support.v4.content.ContextCompat
import android.text.TextUtils
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
@ -21,32 +20,118 @@ import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.gh.common.constant.Config
import com.gh.gamecenter.R
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.Response
import com.lightgame.config.CommonDebug
import com.lightgame.download.FileUtils
import com.lightgame.utils.Utils
import org.json.JSONObject
import retrofit2.HttpException
import rx.Observable
import rx.Observer
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import java.io.File
import java.net.HttpURLConnection
class ImageUtils private constructor() {
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, listener: BaseControllerListener<ImageInfo>) {
object ImageUtils {
private const val PIC_MAX_FILE_SIZE: Long = 10 * 1024 * 1024
@JvmStatic
fun getUploadFileMaxSize(): Long {
val uploadLimitSize = Config.getSettings()?.image?.uploadLimitSize
if (uploadLimitSize != null) {
return uploadLimitSize
}
return PIC_MAX_FILE_SIZE
}
@JvmStatic
fun getDefaultGifRule(): String? {
val gifConfig = Config.getSettings()?.image?.oss?.gif
if (gifConfig != null) {
return gifConfig
}
return ""
}
@JvmStatic
fun getWatermarkWidthGifRule(width: Int?): String? {
val gifConfig = Config.getSettings()?.image?.oss?.gitThumb
val gifWaterMark = Config.getSettings()?.image?.oss?.gifWaterMark
if (gifConfig != null && gifWaterMark != null) {
return "$gifConfig,w_$width$gifWaterMark"
}
return ""
}
@JvmStatic
fun getLimitWidthRule(width: Int?): String? {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$jpegConfig,w_$width"
}
return ""
}
@JvmStatic
fun addLimitWidth(imageUrl: String?, width: Int?): String? {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,w_$width"
}
return imageUrl
}
@JvmStatic
fun addLimitHeight(imageUrl: String, height: Int): String {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,h_$height"
}
return imageUrl
}
@JvmStatic
fun addLimitWidthAndHeight(imageUrl: String, width: Int, height: Int): String {
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
if (jpegConfig != null) {
return "$imageUrl$jpegConfig,w_$width,h_$height"
}
return imageUrl
}
@JvmStatic
fun getGitStaticImage(imageUrl: String): String {
val gifThumb = Config.getSettings()?.image?.oss?.gitThumb
if (gifThumb != null) {
return "$imageUrl$gifThumb"
}
return imageUrl
}
@JvmStatic
fun addLimitWidthAndLoad(draweeView: SimpleDraweeView?, imageUrl: String, width: Int) {
val newUrl = addLimitWidth(imageUrl, width)
draweeView?.setImageURI(newUrl)
}
@JvmStatic
fun addLimitWidthAndLoad(draweeView: SimpleDraweeView?, imageUrl: String?, width: Int?, onLoadListener: OnImageloadListener?) {
val newUrl = getTransformLimitUrl(imageUrl, width, draweeView?.context)
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
onLoadListener?.onLoadFinal(imageInfo)
}
}
draweeView?.controller = Fresco.newDraweeControllerBuilder()
.setUri(newUrl)
.setControllerListener(listener)
.build()
}
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, width: Int?, listener: BaseControllerListener<ImageInfo>) {
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
.setUri(url)
.setUri(getTransformLimitUrl(url, width, simpleDraweeView?.context))
.setControllerListener(listener)
.build()
}
// 自适应图片宽高
@JvmStatic
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, width: Int) {
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
@ -60,15 +145,17 @@ class ImageUtils private constructor() {
}
}
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
.setUri(url)
.setControllerListener(listener)
.setUri(getTransformLimitUrl(url, width, simpleDraweeView?.context))
.build()
}
// 自适应图片宽高
@JvmStatic
fun displayScale(simpleDraweeView: SimpleDraweeView?, url: String?, height: Int) {
val listener = object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
if (imageInfo == null) {
return
}
@ -85,7 +172,8 @@ class ImageUtils private constructor() {
}
// 设置缩放类型,设置按压状态下的叠加图
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?,
@JvmStatic
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?, width: Int,
scaleType: ScalingUtils.ScaleType?, url: String?) {
if (simpleDraweeView == null) return
val context = simpleDraweeView.context ?: return
@ -96,11 +184,11 @@ class ImageUtils private constructor() {
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setActualImageScaleType(scaleType)
.build()
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url)
simpleDraweeView.setImageURI(getTransformLimitUrl(url, width, context))
}
// 设置占位符
@JvmStatic
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?, url: String?, placeholderImage: Int) {
if (simpleDraweeView == null) return
val context = simpleDraweeView.context ?: return
@ -110,7 +198,6 @@ class ImageUtils private constructor() {
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
.setPlaceholderImage(placeholderImage)
.build()
// simpleDraweeView.setImageURI(url);
display(simpleDraweeView, url)
}
@ -125,6 +212,7 @@ class ImageUtils private constructor() {
}
// 获取bitmap
@JvmStatic
fun display(context: Context?, url: String?, dataSubscriber: BaseBitmapDataSubscriber) {
val imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse(url))
@ -136,113 +224,68 @@ class ImageUtils private constructor() {
.subscribe(dataSubscriber, CallerThreadExecutor.getInstance())
}
companion object {
const val RESPONSE403: String = "RESPONSE403"
fun getInstance(): ImageUtils {
return Inner.anotherSingle
/**
* 规则 width>0 Wifi/4G:x2 traffic:x1
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
*/
@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))
}
}
}
private object Inner {
val anotherSingle = ImageUtils()
}
fun display(simpleDraweeView: SimpleDraweeView, url: String?) {
simpleDraweeView.setImageURI(url)
}
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {
draweeView.setImageURI("res:///" + res)
}
fun postImageArr(context: Context, imgArr: List<String>, listener: OnPostArrImageListener) {
val imgMap: HashMap<String, String> = HashMap()
Observable.create(Observable.OnSubscribe<JSONObject> { subscriber ->
var path: String
var index = 0
for (s in imgArr) {
path = context.getCacheDir().path + File.separator + System.currentTimeMillis() + index + ".jpg"
if (BitmapUtils.savePicture(path, s, 1024 * 1024)) {
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", path, s, UserManager.getInstance().token))
index++
} else {
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", s, s, UserManager.getInstance().token))
}
}
subscriber.onCompleted()
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<JSONObject> {
override fun onCompleted() {
Utils.log("图片上传完成")
listener.postSuccess(imgMap)
}
override fun onError(e: Throwable) {
Utils.log("图片上传失败" + e.toString())
listener.postError()
}
override fun onNext(result: JSONObject?) {
if (result != null) {
try {
val statusCode = result.getInt("statusCode")
if (statusCode == HttpURLConnection.HTTP_OK) {
imgMap.put(result.getString("realPath"), result.getString("icon"))
} else if (statusCode == 403) {
imgMap.put(result.getString("realPath"), RESPONSE403)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
})
}
fun postImage(context: Context?, picturePath: String?, listener: OnPostImageListener): Subscription? {
if (context == null || TextUtils.isEmpty(picturePath)) return null
return Observable.create(Observable.OnSubscribe<JSONObject> { subscriber ->
val path = context.getCacheDir().path + File.separator + System.currentTimeMillis() + ".jpg"
if (BitmapUtils.savePicture(path, picturePath, 1024 * 1024)) {
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", path, UserManager.getInstance().token))
// Wifi/4G:x2 traffic:x1
private fun getTransformLimitUrl(url: String?, width: Int?, context: Context?): String? {
var transformUrl: String? = url
if (width != null && width > 0) {
val transformUrlX2 = addLimitWidth(url, width * 2)
val transformUrlX1 = addLimitWidth(url, width)
if (NetworkUtils.isWifiOr4GConnected(context)) {
transformUrl = transformUrlX2
} else {
// 检查X2大图是否被缓存
if (Fresco.getImagePipeline().isInBitmapMemoryCache(Uri.parse(transformUrlX2)) ||
Fresco.getImagePipeline().isInDiskCacheSync(Uri.parse(transformUrlX2))) {
transformUrl = transformUrlX2
} else {
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", picturePath, UserManager.getInstance().token))
transformUrl = transformUrlX1
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<JSONObject>() {
override fun onResponse(response: JSONObject?) {
if (CommonDebug.IS_DEBUG) {
Utils.log("postImage:onResponse=>" + response.toString())
}
listener.postSuccess(response)
}
override fun onFailure(e: HttpException?) {
listener.postError()
}
})
}
}
// Utils.log("displayPost::viewWidth->$width----transformUrl->$transformUrl")
return transformUrl
}
// 规则 width>0 Wifi/4G:x2 traffic:x2
@JvmStatic
fun displayIcon(view: SimpleDraweeView?, url: String?) {
val width = view?.layoutParams?.width
if (width != null && width > 0) {
view.setImageURI(addLimitWidth(url, width * 2))
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
} else {
view?.post {
view.setImageURI(addLimitWidth(url, view.width * 2))
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
}
}
}
interface OnPostImageListener {
fun postSuccess(response: JSONObject?)
fun postError()
@JvmStatic
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {
draweeView.setImageURI("res:///" + res)
}
interface OnPostArrImageListener {
/**
* key: 图片本地路径
* value: 图片提交成功后的链接
*/
fun postSuccess(imgMap: HashMap<String, String>)
fun postError()
public interface OnImageloadListener {
fun onLoadFinal(imageInfo: ImageInfo?)
}
}

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,13 +33,14 @@ 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;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by khy on 2016/12/16.
@ -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,106 +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;
}
}
Utils.toast(context, "发生异常");
}
});
break;
}
});
}
Utils.toast(context, "发生异常");
}
});
break;
}
});
});
}
@ -448,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);
}
@ -522,12 +526,10 @@ 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;
}
}
@ -553,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

@ -1,10 +1,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;
@ -18,46 +20,78 @@ import org.json.JSONObject;
/**
* Created by khy on 2/01/18.
*/
public class AskLogUtils {
public class LogUtils {
public static void uploadQuestions(Context context, String tracers, Questions questions) {
if (context == null) return;
public static void uploadCommunityArticle(String tracers, String articleId, String articleTitle,
int readTime, CommunityEntity community) {
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("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(context, object);
upload(object);
}
public static void uploadAnswers(Context context, String tracers, Questions questions, String answerId) {
if (context == null) return;
public static void uploadDevice(LunchType launchType) {
JSONObject object = new JSONObject();
Application application = HaloApp.getInstance().getApplication();
try {
object.put("subject", "halo_device");
object.put("launch_time", Utils.getTime(application));
object.put("launch_type", launchType.name());
object.put("manufacture", Build.MANUFACTURER);
} catch (JSONException e) {
e.printStackTrace();
}
upload(object);
}
public static void uploadAnswerReadTime(String tracers, int readTime, String answerId, Questions questions) {
JSONObject object = new JSONObject();
try {
object.put("subject", "answer");
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);
object.put("read", readTime);
} catch (JSONException e) {
e.printStackTrace();
}
upload(context, object);
upload(object);
}
public static void uploadSearch(Context context, String searchKey) {
if (TextUtils.isEmpty(searchKey) || context == null) return;
public static void uploadQuestionReadTime(String tracers, int readTime, Questions questions) {
JSONObject object = new JSONObject();
try {
object.put("subject", "question");
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("tracers", tracers);
object.put("read", readTime);
} catch (JSONException e) {
e.printStackTrace();
}
upload(object);
}
public static void uploadSearch(String searchKey) {
if (TextUtils.isEmpty(searchKey)) return;
JSONObject object = new JSONObject();
try {
@ -69,54 +103,57 @@ public class AskLogUtils {
e.printStackTrace();
}
upload(context, object);
upload(object);
}
public static void communityRefresh(Context context, int dataCount) {
if (context == null) return;
public static void communityRefresh(int dataCount, boolean manualRefresh) {
JSONObject object = new JSONObject();
try {
object.put("subject", "community_refresh");
object.put("community_id", UserManager.getInstance().getCommunity().getId());
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));
} 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) {
Context context = HaloApp.getInstance().getApplication();
try {
object.put("version", BuildConfig.PATCH_VERSION_NAME);
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

@ -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.retrofit.JSONObjectResponse;
@ -11,12 +12,14 @@ 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;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by khy on 7/07/17.
@ -25,50 +28,6 @@ import rx.schedulers.Schedulers;
// TODO: 1/12/17 逐步整理 删除
public class LoginUtils {
// public static void checkPhoneNum(final Context context, final String phoneName, final onCaptchaCallBackListener listener) { // 老用户登录检查手机是否登录过
// RetrofitManager.getInstance(context).getApi()
// .checkPhoneNum(phoneName)
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(new Response<ResponseBody>() {
// @Override
// public void onResponse(ResponseBody response) {
// super.onResponse(response);
// try {
// JSONObject content = new JSONObject(response.string());
// String status = content.getString("status");
// if ("ok".equals(status)) {
// getPhoneCaptcha(context, phoneName, listener);
// } else {
// DialogUtils.showWarningDialog(context, null, "手机号已存在,请使用未登录过的手机号,以保证数据正常同步到新账号上"
// , null, "我知道了", null, null);
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
//
// @Override
// public void onFailure(HttpException e) {
// super.onFailure(e);
// if (e == null) {
// Utils.toast(context, "请检查网络是否可用");
// return;
// }
// try {
// ResponseBody responseBody = e.response().errorBody();
// String string = responseBody.string();
// JSONObject content = new JSONObject(string);
// int code = content.getInt("code");
// outputErrorHint(context, code);
// } catch (Exception e1) {
// e1.printStackTrace();
// }
// }
// });
//
// }
// 获取验证码
public static void getPhoneCaptcha(final Context context, String phoneNum, final onCaptchaCallBackListener listener) {
JSONObject content = new JSONObject();
@ -147,39 +106,67 @@ public class LoginUtils {
});
}
public static boolean userPostErrorToast(Throwable throwable, Context context, boolean isComment) {
if (throwable instanceof HttpException) {
HttpException exception = (HttpException) throwable;
if (exception.code() == 403) {
try {
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
int errorCode = errorJson.getInt("code");
switch (errorCode) {
case 403019:
if (isComment) {
Utils.toast(context, R.string.comment_failed_userblocked);
} else {
Utils.toast(context, R.string.comment_failed_userbanned);
}
break;
case 403020:
Utils.toast(context, R.string.comment_failed_toofrequent);
break;
case 403021:
Utils.toast(context, R.string.comment_failed_illegal);
break;
default:
Utils.toast(context, R.string.comment_failed_unknown);
break;
}
} catch (Exception ex) {
ex.printStackTrace();
Utils.toast(context, "无法识别错误类型");
}
return true;
}
/**
* 请用 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:
Utils.toast(context, R.string.comment_failed_userblocked);
break;
case 403020:
if (isQuestion) {
DialogUtils.showAlertDialog(context, "限制提醒"
, "提问过于频繁,请先休息一下哦", "知道了"
, null, null, null);
} else {
Utils.toast(context, R.string.comment_failed_toofrequent);
}
break;
case 403021:
Utils.toast(context, R.string.comment_failed_illegal);
break;
case 403047:
Utils.toast(context, R.string.deny_vote_answer);
break;
default:
Utils.toast(context, R.string.post_failure_hint);
break;
}
} catch (Exception e) {
Utils.toast(context, R.string.post_failure_hint);
e.printStackTrace();
}
return false;
}
public static void captchaErrorHint(Context context, JSONObject content) {
@ -328,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

@ -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

@ -44,6 +44,20 @@ public class NetworkUtils {
return false;
}
public static boolean isWifiOr4GConnected(Context context) {
String network = DeviceUtils.getNetwork(context);
if ("WIFI".equals(network) || "4G".equals(network)) {
return true;
}
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

@ -15,9 +15,9 @@ 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.ResponseBody;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class NewsUtils {
@ -156,7 +156,7 @@ public class NewsUtils {
} else {
textView.setText(String.format(Locale.getDefault(), "%d小时前", hour));
}
} else if (day >= today - 86400 * 1000 && day < today) {
} else if (day >= today - 86400 * 1000 * 100 && day < today) {
format.applyPattern("HH:mm");
textView.setText("昨天 ");
} else {

View File

@ -0,0 +1,19 @@
package com.gh.common.util
import java.math.BigDecimal
object NumberUtils {
@JvmStatic
fun transSimpleCount(count: Int): String {
val s: String
if (count > 10000) {
val number = count / 10000f
val bd = BigDecimal(number.toDouble())
s = bd.setScale(1, BigDecimal.ROUND_DOWN).toString() + "W"
} else {
s = count.toString()
}
return s
}
}

View File

@ -0,0 +1,59 @@
package com.gh.common.util
import android.content.Context
import android.content.pm.ApplicationInfo
import com.gh.common.AppExecutor
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() {
AppExecutor.ioExecutor.execute {
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

@ -9,10 +9,13 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
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;
@ -41,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) {
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());
@ -65,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;
}
@ -107,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;
}
/*
* 解析签名
*/
@ -127,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());
}
}
@ -148,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;
}
@ -158,6 +213,11 @@ public class PackageUtils {
return true;
}
// 由于新增了非插件的也能更新的功能,倘若两个签名一样的话就不走下面的光环签名判断了
if (compareSignatureBetweenInstalledAppWithApk(context, packageName, path)) {
return true;
}
String signature = getApkSignatureByPackageName(context, packageName);
return publicKey.equals(signature);
}
@ -168,8 +228,18 @@ public class PackageUtils {
public static Intent getInstallIntent(Context context, String path) {
Uri uri = Uri.fromFile(new File(path));
Intent installIntent = new Intent(Intent.ACTION_VIEW);
// installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
if ("smartisan".equals(Build.MANUFACTURER)) {
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
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;
}
@ -223,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

@ -30,9 +30,9 @@ import java.util.Locale;
import java.util.Properties;
import java.util.Set;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.HttpException;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class PlatformUtils {

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;
@ -11,13 +12,13 @@ import com.lightgame.utils.Utils;
import org.json.JSONObject;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by khy on 2016/11/9.
@ -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

@ -1,51 +0,0 @@
package com.gh.common.util;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import com.lightgame.utils.Util_System_ClipboardManager;
import com.lightgame.utils.Utils;
/**
* Created by khy on 2017/3/30.
*/
public class QQUtils {
public static void startQQSession(Context context, String qq) {
if (TextUtils.isEmpty(qq)) {
qq = "2586716223";
}
if (ShareUtils.isQQClientAvailable(context)) {
//安装了QQ会直接调用QQ打开手机QQ进行会话 QQ号2586716223
String chatType;
if (qq.startsWith("400") || qq.startsWith("800")) {
chatType = "crm";
} else {
chatType = "wpa";
}
String str = "mqqwpa://im/chat?chat_type=" + chatType + "&uin=" + qq + "&version=1&src_type=web";
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(str)));
} else {
//没有安装QQ 复制账号
// ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
// cmb.setText(qq);
Util_System_ClipboardManager.setText(context, qq);
Utils.toast(context, "已复制" + qq);
}
}
public static boolean joinQQGroup(Context context, String key) {
Intent intent = new Intent();
intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D" + key));
// 此Flag可根据具体产品需要自定义如设置则在加群界面按返回返回手Q主界面不设置按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent);
return true;
} catch (Exception e) {
// 未安装手Q或安装的版本不支持
return false;
}
}
}

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