Compare commits
425 Commits
v4.9.6-338
...
v5.1.2-372
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fd7197909 | |||
| 58178d2871 | |||
| 880838c263 | |||
| 17e5c0535d | |||
| 66fee84b49 | |||
| bbe0350f2c | |||
| 1a35b5ded0 | |||
| efd81a4e0c | |||
| 493e08ce2c | |||
| 1906451060 | |||
| f865e95ae1 | |||
| 3e7e98d555 | |||
| 7537963a8e | |||
| bb9fd24068 | |||
| eda1eea2de | |||
| 62e60f4309 | |||
| b1fef73c54 | |||
| c4fc31c963 | |||
| 812eb842e2 | |||
| 783cb95f24 | |||
| 5969fa2ca5 | |||
| 0187608918 | |||
| 98531376d9 | |||
| 86edc8b919 | |||
| 7903751d85 | |||
| 2620a29a2b | |||
| 5cc40c09dc | |||
| 5c02d37852 | |||
| 2e5d445d65 | |||
| c8bae7d89b | |||
| 2c98c38721 | |||
| 4f28c54591 | |||
| 06b5b885e9 | |||
| 612cc2ca9b | |||
| 18f7b695e5 | |||
| f29e2fe1de | |||
| 799c22093f | |||
| 2496c1d96e | |||
| 8ee76af30f | |||
| 2f35442558 | |||
| 81fa6a6233 | |||
| e5778d5b5f | |||
| f69d607ecb | |||
| 79fc2e1f93 | |||
| 6dfdbb9ee8 | |||
| 5d8f7b3f8d | |||
| cd4601a9c9 | |||
| 462a011401 | |||
| 31d55dae14 | |||
| 8dc9731299 | |||
| 66c19c644e | |||
| 2b617e2697 | |||
| 3a60a497e1 | |||
| a9337aee63 | |||
| c80cd47ccc | |||
| d9c2371488 | |||
| 096d19751a | |||
| ef70119090 | |||
| 95dba71bb9 | |||
| ec37c7a6f8 | |||
| dcc9352301 | |||
| c509c6bb38 | |||
| 4784d689f8 | |||
| 8903a075be | |||
| 48d6e91b0e | |||
| 30865239d2 | |||
| 8b7cd92ae8 | |||
| 69f336553e | |||
| ed82f96ae3 | |||
| 8f02016a76 | |||
| c06f397d12 | |||
| 912b7280cd | |||
| 50f7dd2c63 | |||
| 23469543c7 | |||
| 2d3f70dd12 | |||
| f57d19e797 | |||
| 8c529f0724 | |||
| 1583f1957a | |||
| 676ccb133f | |||
| 489b8143a1 | |||
| c4cf3efa21 | |||
| 871cfd638d | |||
| 1f3ae1c687 | |||
| 59eb101a48 | |||
| b3b8b6ba29 | |||
| 42baaa8950 | |||
| 61ad70d3b8 | |||
| 04252e3b91 | |||
| b40543d7b5 | |||
| 903fa49b71 | |||
| 03ae2699c6 | |||
| 8ecc4078bb | |||
| ebaf4f02f0 | |||
| e85437379a | |||
| 5a77522a04 | |||
| e5512604fa | |||
| 146a46f8be | |||
| 91f33f06d3 | |||
| 59da7b6ba6 | |||
| 0a1ad238f8 | |||
| 302e6c145c | |||
| a6bbf0dfc7 | |||
| 9c3d22964c | |||
| ab60ed8473 | |||
| 9a00e70cc4 | |||
| 35954f52c5 | |||
| e13d80d063 | |||
| 73ed15689d | |||
| 65d949bade | |||
| 33d0d01051 | |||
| 9998ed0a14 | |||
| 85a8a17acb | |||
| 4032cb8abe | |||
| fc2e87063e | |||
| a63b809642 | |||
| c30048c268 | |||
| 956d5a39be | |||
| 76fd1ab7e3 | |||
| 2c4c954c64 | |||
| aef4da961d | |||
| 31e00bb681 | |||
| 369fdd24ef | |||
| 2a57994c7f | |||
| 6f84b14277 | |||
| 10ed05c8ef | |||
| 799bd1042f | |||
| 6f9acab2d2 | |||
| 387d8eb5af | |||
| c813c5d5ef | |||
| 1c6df6741f | |||
| b54ab5f824 | |||
| 37fdf6c18e | |||
| 2685de9b3e | |||
| c049100f5f | |||
| 711d1f9d65 | |||
| 5d7453afec | |||
| e4acf466ba | |||
| 2d66cbd29c | |||
| 8786f7d500 | |||
| 3d40d7a819 | |||
| 6f7862a0f2 | |||
| 58c6211d54 | |||
| d10b187a1f | |||
| 1ebf34c83a | |||
| 01e2a3c708 | |||
| c9b97552d4 | |||
| 428f39aa86 | |||
| 5fecb723bc | |||
| 0168b0d93a | |||
| 895fa510fe | |||
| 0aae59a1ba | |||
| 574a2b4dc7 | |||
| acae608966 | |||
| 6ca6c34f92 | |||
| 16724a2d2e | |||
| 8b50cc561a | |||
| 1ec1d482c4 | |||
| 869b9d507b | |||
| 514fe66347 | |||
| 657c91a5ef | |||
| 82354a1156 | |||
| b7619f0c93 | |||
| 598a3ad0b6 | |||
| bf0be93dc9 | |||
| 90a676f778 | |||
| a675e4bbe3 | |||
| 5eee8c6785 | |||
| 3c54e4313c | |||
| 67c4b76de9 | |||
| 34fd08d06a | |||
| d08b95021d | |||
| 8517a2aef1 | |||
| cbe90141f1 | |||
| fd43bc9426 | |||
| 34a143b632 | |||
| d96e02eca0 | |||
| 398b1ae58b | |||
| 0749205bef | |||
| 54ec115fee | |||
| ebe7b84dc8 | |||
| 332abe66f5 | |||
| 9dccbfbd51 | |||
| 23a8c9e6aa | |||
| 1e4408ac6e | |||
| 05ece9c999 | |||
| 216905e455 | |||
| a1bd88dad8 | |||
| 16c66c707f | |||
| 50cdea2b03 | |||
| 95b0fda15a | |||
| 9c99273f81 | |||
| 8d9d36a5df | |||
| b22d168e97 | |||
| 1fee166e3b | |||
| 7c098c29b2 | |||
| ffc9dc46e2 | |||
| c491a4084c | |||
| 0f076a03c5 | |||
| 3345ab2044 | |||
| 5874bdd311 | |||
| 4669211196 | |||
| 4879e7f0aa | |||
| f5283d386b | |||
| 602333f923 | |||
| e9810c129e | |||
| c503f15df9 | |||
| cba1012bbd | |||
| 646493ae61 | |||
| b649089ab0 | |||
| e97fd9023e | |||
| 478dd658ab | |||
| b313feac01 | |||
| c04b82549e | |||
| 842e62f909 | |||
| 51c6de0506 | |||
| d350f65c1f | |||
| aaf8e28abc | |||
| 7cb921e969 | |||
| 3a4b41058d | |||
| 26308d1852 | |||
| af54932309 | |||
| 83799048ed | |||
| ce410ad2a0 | |||
| 933c40458f | |||
| 6ae7578281 | |||
| 72b804e26e | |||
| 7e58cdc59e | |||
| d782ea90b6 | |||
| efffd752f5 | |||
| 47f3f45fe6 | |||
| b4e12e2ec3 | |||
| 2d331f6294 | |||
| feb4137f84 | |||
| 6a2c4a2967 | |||
| 68fc5532ff | |||
| 43ae479271 | |||
| 7a3ea4d939 | |||
| 1bcb343355 | |||
| 1b7a601cee | |||
| 8bc9544dc2 | |||
| e586e65e44 | |||
| 8096da5f50 | |||
| 91868fda15 | |||
| a71e8824ce | |||
| 6cbc354921 | |||
| 79e2077a3d | |||
| 6ea3ed067d | |||
| 84fe33becc | |||
| 276f53fead | |||
| 0789cc6fdf | |||
| 3a563b7bd0 | |||
| 9b8ba0c3e6 | |||
| 258f054161 | |||
| 258c8db0f9 | |||
| 741d0b11af | |||
| 9267896b50 | |||
| 85c0bd69c1 | |||
| 2436507b7b | |||
| 1b68b07e53 | |||
| c4ba28de1a | |||
| 8daa55c16a | |||
| 5e6c6aca13 | |||
| e08ab790ee | |||
| a394901cb4 | |||
| 2aaa7f2795 | |||
| 7b0d2a25c8 | |||
| e3f553a96f | |||
| 809a25e3e2 | |||
| 88041d9b5f | |||
| a11d741f6f | |||
| 1283def6da | |||
| 9c621c31a2 | |||
| 9e3f40723f | |||
| 682bb9a3e7 | |||
| 9f2d164c70 | |||
| bad5130047 | |||
| e3f831e0ca | |||
| a1432452f5 | |||
| b3cc68b7c6 | |||
| cc1f5a269a | |||
| a2892a713a | |||
| c342e22ce4 | |||
| 57dcbab096 | |||
| 5aa4c5bcbc | |||
| 039e1fc957 | |||
| f7b2d10543 | |||
| 38972eca76 | |||
| c2d853d709 | |||
| 239209dbf2 | |||
| ba1f3e20d3 | |||
| 92ac62d949 | |||
| 6499e3b718 | |||
| 5f0d2604ec | |||
| 5f7bb6cb49 | |||
| 7360eef244 | |||
| 52e6feab59 | |||
| 5f44252410 | |||
| 7ae3b1cafb | |||
| 0fb77e79fd | |||
| d4ae878947 | |||
| 37a2e3cc0e | |||
| 30595741cc | |||
| 11f177d572 | |||
| 9e13675ca5 | |||
| 144a0641b6 | |||
| 95266f6f68 | |||
| 9ded647c0d | |||
| f566e4d5c3 | |||
| 5df3efd087 | |||
| 98f4361bf0 | |||
| 000d1e020a | |||
| 93431a7e37 | |||
| d54523cdb6 | |||
| ed468b7c73 | |||
| bad6211bf5 | |||
| 2743d4d0de | |||
| a0f5387917 | |||
| 1abfcfdb51 | |||
| ecc0a75f52 | |||
| c98bf26337 | |||
| 187d07d02d | |||
| c47c23ad21 | |||
| e6ea1738e5 | |||
| 40983ecebc | |||
| fbe73ce4da | |||
| d46617237f | |||
| 0894957d73 | |||
| 7f2145d0ef | |||
| acefbba6bf | |||
| 660a091b7b | |||
| 103078d63e | |||
| 178395f531 | |||
| 8db213d040 | |||
| 5904d3c5c7 | |||
| 1a511ebbad | |||
| ef97e8cc6d | |||
| 7b11b0e99a | |||
| 01034f093a | |||
| 8e28766449 | |||
| d06d0bd15c | |||
| 4fe4a33b80 | |||
| 4a8e91bbff | |||
| b1f6c7d55c | |||
| 727eeac52e | |||
| fb26ec0c13 | |||
| 3e25619bf8 | |||
| e81fa4ff1a | |||
| d7d2bf2667 | |||
| c763a0a9e6 | |||
| 2afb99b603 | |||
| 2e09ac033b | |||
| 54747143d1 | |||
| 076c98977d | |||
| b96104fcd9 | |||
| daece9337c | |||
| 3547330e2a | |||
| 4d76fb0159 | |||
| f34a95b36f | |||
| 6e3cb7a196 | |||
| 03f87c46ba | |||
| b052ba1635 | |||
| d1183199cd | |||
| 31fed948f0 | |||
| f1c5b80dc2 | |||
| 86f2aec9ca | |||
| a218f13ccb | |||
| 1fc37571df | |||
| 576f06f250 | |||
| 3805cb52f6 | |||
| f8d7377236 | |||
| 354fa13a35 | |||
| 3c533b896b | |||
| 11c6618c0f | |||
| 898bf3e432 | |||
| 0faf408762 | |||
| 1dbabe3cda | |||
| a107a19d95 | |||
| 58ea0bb51d | |||
| 557f22b23b | |||
| f40a192e82 | |||
| 84f3556275 | |||
| cddc2bff2b | |||
| a0b8caa60a | |||
| 22cadc77f0 | |||
| 28fb45f0b8 | |||
| 3d7f8b3f41 | |||
| bba326cfd9 | |||
| f76bb7070a | |||
| a6a3d769bd | |||
| ea5627b3da | |||
| d9807227ec | |||
| 5cc1cfa1a6 | |||
| 35cdd140cc | |||
| 87597dbd1f | |||
| 398f7b6642 | |||
| f0ca0a2ab1 | |||
| c9ffd4e5bd | |||
| d354b07fe2 | |||
| 71a61fdef0 | |||
| 2eded37321 | |||
| f35baf0e5b | |||
| 4d64281c78 | |||
| 95f1692434 | |||
| f1302dd1bb | |||
| fec34f1efa | |||
| def3b55e51 | |||
| 4549f78ede | |||
| 3054b56f4a | |||
| 4cf5e0f2f4 | |||
| 1a18c82f06 | |||
| b8fbb429f1 | |||
| 005229fe8a | |||
| 3a0bbbf3d0 | |||
| 868e6d31b8 | |||
| a687f8d877 | |||
| 3e86a40215 | |||
| 6a68839d0f | |||
| 2140c9eb40 | |||
| 942af39b2d | |||
| a0331f0437 | |||
| 63798c94cf | |||
| 6c2ff6a94f | |||
| 2211f562c7 | |||
| 7a0165375c | |||
| e280ea008a |
93
README.md
93
README.md
@ -1,69 +1,68 @@
|
||||
# 光环助手Android客户端
|
||||
|
||||
### APK打包配置
|
||||
### 概述
|
||||
|
||||
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
|
||||
* 打包命令,视情况使用:
|
||||
光环助手Android客户端目前使用 Kotlin 作为主要开发语言,以 MVVM 作为参考架构模式进行开发
|
||||
|
||||
> 打包Tinker基准包:`./scripts/tinker_release_base.sh`
|
||||
### 约束
|
||||
|
||||
> 以Tinker基准包打渠道包:`./scripts/tinker_release_channel.sh`
|
||||
为编写易读易维护且较健壮的代码,可参考以下约束
|
||||
|
||||
> 以Tinker基准包打补丁包:`./scripts/tinker_release_patch.sh`
|
||||
1. 尽量将逻辑代码放置于 ViewModel 中,View 中只执行 UI 操作
|
||||
2. 尽量使 View 在被销毁之后仍能恢复状态,处理方式可参考 [保存界面状态](https://developer.android.com/topic/libraries/architecture/saving-states)
|
||||
3. 尽量参考原有文件结构及命名规范,即以 大模块 - 小模块 的形式生成包关系
|
||||
4. 遵循最小改动原则,在提交代码前务必先检查变动的代码,尽量以可控的变动规模来构成一个 commit ,以便日后追踪问题
|
||||
5. 代码规范可参考 [AOSP Java 风格](https://source.android.com/setup/contribute/code-style)
|
||||
6. 尽量使用 Kotlin 来写新文件
|
||||
7. RecyclerView 的 ViewHolder 尽量使用 DataBinding 来减少代码以及提高可读性
|
||||
8. Commit 前请确保不带入非项目必须文件,可手动修改 [.gitignore](https://stackoverflow.com/questions/8527597/how-do-i-ignore-files-in-a-directory-in-git) 文件忽略
|
||||
9. 新页面请勿使用 ButterKnife 来进行 View 获取和绑定,请使用 ViewBinding
|
||||
10. No AsyncTask!
|
||||
|
||||
### 混淆配置
|
||||
### 公用部分
|
||||
|
||||
* 配置文件:Android默认配置+proguard-rules.txt等
|
||||
* 参考libraries下每个项目独立的配置文件`proguard-project.txt`
|
||||
本项目使用 LiveData 实现了一个简单通用的基础列表分页功能,具体可见 `ListFragment`, `ListViewModel` 等类,理想情况下只需少量代码即可新建一个简单分页列表
|
||||
|
||||
### apk大小优化
|
||||
### 首次拉取项目代码
|
||||
|
||||
* 限制resConfig资源集
|
||||
* 开启ShrinkResources
|
||||
* 开启混淆,使用minifyEnabled(仅在release开启)
|
||||
* pngquant对png压缩、png/jpg->webp(未尝试)
|
||||
`git clone -b dev git@git.ghzs.com:halo/android/assistant-android.git --recursive`
|
||||
|
||||
### git 版本管理
|
||||
|
||||
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.ghzs.com/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
|
||||
|
||||
### API 环境配置
|
||||
|
||||
本项目使用 Build Variants 来切换 API 环境
|
||||
|
||||
* internal 为测试环境
|
||||
* publish 为正式环境
|
||||
|
||||
### 图片资源配置
|
||||
|
||||
* 新增图片资源时,默认只添加最高规格的 xxxhdpi 文件
|
||||
* 新增图片资源时,需要将其转换为 .webp 格式 (包括含透明图层的图片,默认质量为90%) (转换后体积变大的文件除外)
|
||||
|
||||
### 第三方appkey等配置
|
||||
|
||||
* 修改`gradle.properties`文件将各种key填入其中,实现统一管理
|
||||
* 通过gradle文件内的resValue/buildConfigField/manifestPlaceHolder方式实现编译期间修改,具体情况请参考``./build.gradle``和``./app/build.gradle``配置
|
||||
|
||||
### 拉取代码步骤
|
||||
### 混淆配置
|
||||
|
||||
1. 拉取主项目代码: `git clone -b dev git@gitlab.ghzhushou.com:halo/assistant-android.git`
|
||||
2. 初始化公用类库: `bash ./scripts/submodules_init.sh`
|
||||
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
|
||||
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)
|
||||
|
||||
### submodule管理方式(只拉取master)
|
||||
### APK打包配置
|
||||
|
||||
* 提交代码,需要cd到submodule文件夹去做修改
|
||||
* 更新远端代码,`bash ./scripts/submodules_update.sh`
|
||||
* 本项目使用了 [VasDolly](https://github.com/Tencent/VasDolly) 作为渠道包实现方案
|
||||
* 打包命令,具体参数请见相应文件:
|
||||
|
||||
> 打内部测试包:`./scripts/test_build.sh`
|
||||
> 打正式发布包:`./scripts/build_with_simple_backup.sh`
|
||||
|
||||
### TODO
|
||||
|
||||
* GSON 序列化用统一的一个, GsonUtil fromJson
|
||||
* CleanApkAdapter 转化字符串size工具函数 比如SpeedUtils
|
||||
* getString 解决 字符串hardcode问题
|
||||
* ~~Adapter 里面clicklistener 用接口传参将点击操作委托给controller~~
|
||||
* ~~Adapter ViewHolder的功能,部分重写到ViewHolder类本身~~
|
||||
|
||||
* ~~activity 统一入口未完成(外部入口相关),去除多余activity使用,统一toolbar~~
|
||||
* ~~release / debug compile不同的类库,不需要再做什么开关~~
|
||||
|
||||
* ~~Toolbar分离,有图形按钮/没有图形按钮~~
|
||||
|
||||
### TODO Since 3.1
|
||||
|
||||
- 解决 Utils 工具类引发的内存泄漏问题
|
||||
- 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
- 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
- ~~将 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)~~
|
||||
|
||||
- ~~把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题~~
|
||||
|
||||
- ~~rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) 解决方法->com.gh.gamecenter.retrofit.Response~~
|
||||
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
|
||||
|
||||
- 搞清楚 GameManager 的用途,看能不能去掉
|
||||
- 重构一下 MainActivity
|
||||
* 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
* 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
* 重构 MainActivity
|
||||
@ -46,6 +46,8 @@ android {
|
||||
}
|
||||
|
||||
ndk {
|
||||
// 如果不添加 `arm64` 调用系统的 PackageManager 的方法读取安装包信息的时候会出现 native 层闪退,草
|
||||
// 微博 SDK 没有 64位的 SO,添加了 arm64 又会无法使用微博登录,下个版本更新微博 SDK 刻不容缓了!
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
||||
@ -216,11 +218,9 @@ dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
|
||||
debugImplementation "com.facebook.stetho:stetho:${stetho}"
|
||||
debugImplementation "com.facebook.stetho:stetho-okhttp3:${stetho}"
|
||||
debugImplementation "com.squareup.okhttp3:logging-interceptor:${okHttp}"
|
||||
debugImplementation "com.gu.android:toolargetool:${toolargetool}"
|
||||
debugImplementation "com.github.nichbar:WhatTheStack:$whatTheStack"
|
||||
debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}"
|
||||
|
||||
implementation "androidx.core:core-ktx:${core}"
|
||||
implementation "androidx.fragment:fragment-ktx:${fragment}"
|
||||
@ -276,8 +276,6 @@ dependencies {
|
||||
|
||||
implementation "com.daimajia.swipelayout:library:${swipeLayout}"
|
||||
|
||||
implementation "com.sina.weibo.sdk:core:${weiboSDK}"
|
||||
|
||||
// bugly with tinker support
|
||||
// implementation "com.tencent.bugly:crashreport_upgrade:${buglyTinkerSupport}"
|
||||
|
||||
@ -300,11 +298,11 @@ dependencies {
|
||||
implementation "com.squareup.picasso:picasso:${picasso}"
|
||||
|
||||
// for video streaming
|
||||
implementation("com.shuyu:gsyVideoPlayer-java:$gsyVideo", {
|
||||
implementation("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-java:$gsyVideo", {
|
||||
exclude module: "gsyvideoplayer-androidvideocache"
|
||||
exclude group: "tv.danmaku.ijk.media"
|
||||
})
|
||||
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
|
||||
implementation "com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo"
|
||||
|
||||
implementation "android.arch.work:work-runtime:${workManager}"
|
||||
|
||||
@ -317,22 +315,22 @@ dependencies {
|
||||
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}"
|
||||
implementation "com.github.nichbar:AndroidRomChecker:${romChecker}"
|
||||
|
||||
debugImplementation "com.github.nichbar.chucker:library:$chucker"
|
||||
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
|
||||
debugImplementation "com.github.nichbar.chucker:library:${chucker}"
|
||||
releaseImplementation "com.github.nichbar.chucker:library-no-op:${chucker}"
|
||||
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
|
||||
// implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
|
||||
// implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
|
||||
|
||||
implementation "com.aliyun.dpa:oss-android-sdk:${oss}"
|
||||
|
||||
implementation "com.airbnb.android:lottie:$lottie"
|
||||
implementation "com.airbnb.android:lottie:${lottie}"
|
||||
|
||||
implementation "net.lingala.zip4j:zip4j:${zip4j}"
|
||||
|
||||
// plugin 需要字符串,故不能用值
|
||||
implementation "io.sentry:sentry-android:3.2.0"
|
||||
|
||||
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
implementation("com.github.piasy:BigImageViewer:${bigImageViewer}", {
|
||||
exclude group: 'com.squareup.okhttp3'
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
exclude group: 'com.github.bumptech.glide'
|
||||
@ -340,10 +338,13 @@ dependencies {
|
||||
})
|
||||
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
|
||||
|
||||
implementation "com.github.hsiafan:apk-parser:$apkParser"
|
||||
implementation "org.nanohttpd:nanohttpd:$nanohttpd"
|
||||
implementation "com.github.hsiafan:apk-parser:${apkParser}"
|
||||
implementation "org.nanohttpd:nanohttpd:${nanohttpd}"
|
||||
|
||||
implementation "com.aliyun.openservices:aliyun-log-android-sdk:$aliyunLog"
|
||||
implementation "com.aliyun.openservices:aliyun-log-android-sdk:${aliyunLog}"
|
||||
implementation "com.github.princekin-f:EasyFloat:${easyFloat}"
|
||||
|
||||
implementation "io.github.florent37:shapeofview:$shapeOfView"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
// implementation project(':libraries:MTA')
|
||||
@ -461,6 +462,11 @@ andResGuard {
|
||||
"R.drawable.ic_search_no_18",
|
||||
"R.drawable.ic_search_no_19",
|
||||
"R.drawable.ic_search_no_20",
|
||||
"R.drawable.ic_recommend_activity",
|
||||
"R.drawable.ic_recommend_discount",
|
||||
"R.drawable.ic_recommend_function",
|
||||
"R.drawable.ic_recommend_gift",
|
||||
"R.drawable.ic_recommend_role",
|
||||
"R.drawable.login_btn_bg",
|
||||
"R.drawable.ic_quick_login_check",
|
||||
"R.drawable.ic_quick_login_uncheck",
|
||||
|
||||
BIN
app/libs/sina-weibo-2.0.3.aar
Normal file
BIN
app/libs/sina-weibo-2.0.3.aar
Normal file
Binary file not shown.
@ -131,4 +131,12 @@
|
||||
|
||||
### 中国移动一键登录
|
||||
-dontwarn com.cmic.sso.sdk.**
|
||||
-keep class com.cmic.sso.sdk.* { *; }
|
||||
-keep class com.cmic.sso.sdk.* { *; }
|
||||
|
||||
### EasyFloat
|
||||
-keep class com.lzf.easyfloat.* {*;}
|
||||
|
||||
### 避免 WebChromeClient 被混淆
|
||||
-keepclassmembers class * extends android.webkit.WebChromeClient{
|
||||
public void openFileChooser(...);
|
||||
}
|
||||
@ -2,8 +2,6 @@ package com.gh.gamecenter;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.stetho.Stetho;
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
@ -17,9 +15,6 @@ import okhttp3.logging.HttpLoggingInterceptor;
|
||||
public class Injection {
|
||||
|
||||
public static boolean appInit(Application application) {
|
||||
// init stetho
|
||||
Stetho.initializeWithDefaults(application);
|
||||
|
||||
// 监控Bundle大小,预防溢出(需要调试的时候再开启吧!)
|
||||
// TooLargeTool.startLogging(application);
|
||||
return true;
|
||||
@ -30,7 +25,6 @@ public class Injection {
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
builder.addNetworkInterceptor(interceptor);
|
||||
builder.addNetworkInterceptor(new StethoInterceptor());
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@ -30,14 +30,8 @@
|
||||
android:name="android.permission.PACKAGE_USAGE_STATS"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
|
||||
<!-- bugly with tinker -->
|
||||
<!-- <uses-permission android:name="android.permission.READ_LOGS" />-->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
|
||||
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
|
||||
<!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
|
||||
|
||||
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
@ -47,9 +41,11 @@
|
||||
com.shuyu.gsyvideoplayer.armv7a,
|
||||
com.shuyu.gsyvideoplayer.x86,
|
||||
com.shuyu.gsy.base,
|
||||
shuyu.com.androidvideocache,
|
||||
com.google.android.exoplayer2,
|
||||
tv.danmaku.ijk.media.exo2,
|
||||
pl.droidsonroids.gif" />
|
||||
pl.droidsonroids.gif,
|
||||
com.lzf.easyfloat"/>
|
||||
|
||||
<!-- 去掉 SDK 一些流氓权限 -->
|
||||
<uses-permission
|
||||
@ -70,9 +66,9 @@
|
||||
android:icon="@mipmap/logo"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:resizeableActivity="true"
|
||||
android:theme="@style/AppCompatTheme.APP"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:replace="android:allowBackup"
|
||||
tools:targetApi="n">
|
||||
|
||||
@ -85,7 +81,6 @@
|
||||
android:name="io.sentry.breadcrumbs.system-events"
|
||||
android:value="false" />
|
||||
|
||||
<!--android:launchMode = "singleTask"-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SplashScreenActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
@ -112,7 +107,6 @@
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!--android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" 退出时屏幕抖动 -->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ImageViewerActivity"
|
||||
android:theme="@style/Theme.Transparent" />
|
||||
@ -170,6 +164,10 @@
|
||||
android:name="com.gh.gamecenter.WebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SingletonWebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.FullScreenWebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -475,7 +473,7 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.editor.VideoActivity"
|
||||
android:name="com.gh.gamecenter.qa.editor.LocalMediaActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
@ -513,6 +511,12 @@
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.dialog.ChooseForumActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.detail.VideoDetailActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
@ -552,10 +556,6 @@
|
||||
android:name=".forum.select.ForumSelectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.follow.ForumMyFollowActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.detail.ForumDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -564,6 +564,10 @@
|
||||
android:name=".forum.moderator.ModeratorListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.moderator.ApplyModeratorActivity"
|
||||
android:screenOrientation="portrait"/>
|
||||
|
||||
<activity
|
||||
android:name=".video.label.VideoLabelActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -585,10 +589,6 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name=".personalhome.excellentcomments.ExcellentCommentsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".simulatorgame.SimulatorGameActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -611,8 +611,8 @@
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyCenterActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTask" />
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".energy.EnergyHouseActivity"
|
||||
@ -638,13 +638,53 @@
|
||||
android:name=".personal.DeliveryInfoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.editor.PreviewVideoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.video.publish.VideoPublishActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".setting.GameDownloadSettingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".setting.VideoSettingActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.video.detail.ForumVideoDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".video.videomanager.VideoDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.questions.newdetail.NewQuestionDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.editor.FullScreenVideoActivity"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@style/AppFullScreenTheme" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.list.ForumListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.answer.detail.SimpleAnswerDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="portrait"
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
android:theme="@android:style/Theme.Dialog" />
|
||||
|
||||
|
||||
<activity
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,58 @@
|
||||
package androidx.swiperefreshlayout.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
public class ViewPagerSwipeRefreshLayout extends SwipeRefreshLayout {
|
||||
|
||||
private float startY;
|
||||
private float startX;
|
||||
// 记录viewPager是否拖拽的标记
|
||||
private boolean mIsVpDragger;
|
||||
private final int mTouchSlop;
|
||||
|
||||
public ViewPagerSwipeRefreshLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
int action = ev.getAction();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// 记录手指按下的位置
|
||||
startY = ev.getY();
|
||||
startX = ev.getX();
|
||||
// 初始化标记
|
||||
mIsVpDragger = false;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// 如果viewpager正在拖拽中,那么不拦截它的事件,直接return false;
|
||||
if(mIsVpDragger) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取当前手指位置
|
||||
float endY = ev.getY();
|
||||
float endX = ev.getX();
|
||||
float distanceX = Math.abs(endX - startX);
|
||||
float distanceY = Math.abs(endY - startY);
|
||||
// 如果X轴位移大于Y轴位移,那么将事件交给viewPager处理。
|
||||
if(distanceX > mTouchSlop && distanceX > distanceY) {
|
||||
mIsVpDragger = true;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
// 初始化标记
|
||||
mIsVpDragger = false;
|
||||
break;
|
||||
}
|
||||
// 如果是Y轴位移大于X轴,事件交给swipeRefreshLayout处理。
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,9 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -15,7 +13,6 @@ import android.os.TransactionTooLargeException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
@ -49,12 +46,10 @@ import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity;
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog;
|
||||
import com.lightgame.BaseAppCompatActivity;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.Util_System_Keyboard;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.tencent.tauth.Tencent;
|
||||
|
||||
@ -96,6 +91,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
private View mTaskBackView;
|
||||
private WindowManager mWM;
|
||||
private WindowManager.LayoutParams mWmParams;
|
||||
public long startPageTime = 0;
|
||||
|
||||
protected final Handler mBaseHandler = new BaseHandler(this);
|
||||
|
||||
@ -147,6 +143,8 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
|
||||
}
|
||||
|
||||
disableAutofill();
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY);
|
||||
String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL);
|
||||
@ -165,10 +163,12 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
startPageTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@ -214,6 +214,15 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 editText 自动填充帐号 (我们也用不上),开启的时候有小概率出发 TimeoutException
|
||||
*/
|
||||
private void disableAutofill() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
getWindow().getDecorView().setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
|
||||
}
|
||||
}
|
||||
|
||||
private View getRootViewWithEnvIndicator(View view) {
|
||||
RelativeLayout screenRootView = new RelativeLayout(this);
|
||||
screenRootView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
@ -274,9 +283,9 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
});
|
||||
} else if (SIGNATURE_CONFLICT.equals(showDialog.getType())) {
|
||||
DialogHelper.showSignatureConflictDialog(this, () -> {
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
return null;
|
||||
});
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
return null;
|
||||
});
|
||||
} else if (LOGIN_EXCEPTION.equals(showDialog.getType())) {
|
||||
if (mIsExistLogoutDialog) return;
|
||||
mIsExistLogoutDialog = true;
|
||||
@ -308,10 +317,6 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
|
||||
mWM.removeView(mTaskBackView);
|
||||
mHasAddTaskFloat = false;
|
||||
}
|
||||
|
||||
if (isFinishing()) {
|
||||
onFinish();
|
||||
@ -323,90 +328,6 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_TASK_FLOAT) && !this.getClass().getName().equals(EnergyCenterActivity.class.getName())) {
|
||||
addTaskBackView();
|
||||
mHasAddTaskFloat = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void addTaskBackView() {
|
||||
mWM = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
mWmParams = new WindowManager.LayoutParams();
|
||||
mWmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
mWmParams.format = PixelFormat.RGBA_8888;
|
||||
mWmParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
|
||||
mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
mWmParams.width = DisplayUtils.dip2px(76F);
|
||||
mWmParams.height = DisplayUtils.dip2px(36F);
|
||||
mWmParams.y = SPUtils.getInt(Constants.SP_TASK_FLOAT_LAST_Y, DisplayUtils.dip2px(114F));
|
||||
mTaskBackView = View.inflate(this, R.layout.layout_task_back, null);
|
||||
mTaskBackView.setOnClickListener(v -> {
|
||||
// 如果当前是在键盘输入时,点击"返回任务"要先收起键盘
|
||||
Util_System_Keyboard.hideSoftKeyboard(this);
|
||||
startActivity(EnergyCenterActivity.Companion.getIntent(this));
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
mWM.removeView(mTaskBackView);
|
||||
mHasAddTaskFloat = false;
|
||||
});
|
||||
setFloatTouchListener();
|
||||
mWM.addView(mTaskBackView, mWmParams);
|
||||
}
|
||||
|
||||
private void setFloatTouchListener() {
|
||||
int screenHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
|
||||
mTaskBackView.setOnTouchListener(new View.OnTouchListener() {
|
||||
|
||||
private int intervalY;
|
||||
private int startY;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final int y = (int) event.getRawY();
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
intervalY = y;
|
||||
startY = y;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mWmParams.y -= (y - intervalY);
|
||||
if (mWmParams.y < 0) {
|
||||
mWmParams.y = 0;
|
||||
}
|
||||
|
||||
if (mWmParams.y > screenHeight) {
|
||||
mWmParams.y = screenHeight;
|
||||
}
|
||||
|
||||
if (mWM != null && mTaskBackView != null && mHasAddTaskFloat) {
|
||||
mWM.updateViewLayout(mTaskBackView, mWmParams);
|
||||
}
|
||||
|
||||
intervalY = y;
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
// 滑动距离少于10视为点击,返回false,否则视为拖动,返回true
|
||||
if (Math.abs(y - startY) <= 10) {
|
||||
return false;
|
||||
} else {
|
||||
// 记录位置
|
||||
SPUtils.setInt(Constants.SP_TASK_FLOAT_LAST_Y, mWmParams.y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 此回调可用于确认当前 activity 已经执行了 finish() 方法并处于 isFinishing 状态
|
||||
*/
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ClipboardManager
|
||||
@ -9,32 +10,42 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.widget.CheckBox
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.RichEditor
|
||||
import com.gh.gamecenter.CropImageActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
|
||||
import com.gh.gamecenter.entity.LocalVideoEntity
|
||||
import com.gh.gamecenter.entity.VideoEntity
|
||||
import com.gh.gamecenter.qa.editor.GameActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity
|
||||
import com.gh.gamecenter.qa.editor.VideoActivity
|
||||
import com.gh.gamecenter.qa.editor.LocalMediaActivity
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.entity.EditorInsertEntity
|
||||
import com.gh.gamecenter.video.poster.PosterEditActivity
|
||||
import com.gh.gamecenter.video.upload.UploadManager
|
||||
import com.google.gson.JsonObject
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
import com.lightgame.utils.Utils
|
||||
import com.lightgame.view.CheckableImageView
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotterknife.bindView
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
|
||||
abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> : ToolBarActivity(),
|
||||
KeyboardHeightObserver, UploadVideoListener {
|
||||
|
||||
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
|
||||
|
||||
@ -55,24 +66,31 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
private val mEditorParagraphContainer by bindView<View>(R.id.editor_paragraph_container)
|
||||
private val mEditorLinkContainer by bindView<View>(R.id.editor_link_container)
|
||||
private val mEditorInsertDetailContainer by bindView<View>(R.id.editor_insert_detail_container)
|
||||
val mAddLabelContainer by bindView<View>(R.id.add_label_container)
|
||||
val mAddLabelTv by bindView<TextView>(R.id.add_label_tv)
|
||||
val mLabelNumTv by bindView<TextView>(R.id.label_num_tv)
|
||||
val mLabelArrowIv by bindView<ImageView>(R.id.label_arrow)
|
||||
val mTagsContainer by bindView<FrameLayout>(R.id.tagsContainer)
|
||||
private val mTagsContainer by bindView<FrameLayout>(R.id.tagsContainer)
|
||||
private val mUploadVideoGuideContainer by bindView<View>(R.id.uploadVideoGuideContainer)
|
||||
protected val mOriginalCb by bindView<CheckBox>(R.id.originalCb)
|
||||
private val mOriginalTipsContainer by bindView<View>(R.id.originalTipsContainer)
|
||||
private val mOriginalTipsClose by bindView<TextView>(R.id.originalTipsClose)
|
||||
|
||||
private var mCurrentParagraphStyle = ""
|
||||
private var mIsExtendedKeyboardShow = false
|
||||
|
||||
private var mAgreePostPic: Boolean = false
|
||||
private var mGuideDisposable: Disposable? = null
|
||||
protected lateinit var mViewModel: VM
|
||||
protected var mIsKeyBoardShow = false
|
||||
private var mKeyboardHeightProvider: KeyboardHeightProvider? = null
|
||||
private var mMaxUploadVideoGuideCount = 2
|
||||
val FILE_HOST = "file:///"
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
DialogUtils.fixWebViewKeyboardNotWorking(this)
|
||||
if (resultCode != Activity.RESULT_OK) return
|
||||
var insertData: EditorInsertEntity? = null
|
||||
val insertData: EditorInsertEntity?
|
||||
when (requestCode) {
|
||||
INSERT_ANSWER_CODE -> {
|
||||
val answer = data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
|
||||
val answer =
|
||||
data?.getParcelableExtra<AnswerEntity>(AnswerEntity::class.java.simpleName)
|
||||
if (answer != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(answer)
|
||||
@ -80,7 +98,8 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
}
|
||||
}
|
||||
INSERT_ARTICLE_CODE -> {
|
||||
val article = data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
|
||||
val article =
|
||||
data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
|
||||
if (article != null) {
|
||||
mRichEditor.focusEditor()
|
||||
insertData = EditorInsertEntity.transform(article)
|
||||
@ -95,11 +114,22 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mRichEditor.insertCustomStyleLink(insertData)
|
||||
}
|
||||
}
|
||||
VideoActivity.INSERT_VIDEO_CODE -> {
|
||||
val video = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
|
||||
if (video != null) {
|
||||
REQUEST_CODE_IMAGE -> {
|
||||
if (data != null) mViewModel.uploadPic(data)
|
||||
}
|
||||
INSERT_VIDEO_CODE -> {
|
||||
val localVideoList =
|
||||
data?.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name)
|
||||
?: arrayListOf()
|
||||
if (localVideoList.isNotEmpty()) {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertCustomVideo(video)
|
||||
uploadVideo(localVideoList)
|
||||
}
|
||||
}
|
||||
REQUEST_CODE_IMAGE_CROP -> {
|
||||
val imagePath = data?.getStringExtra(CropImageActivity.RESULT_CLIP_PATH)
|
||||
if (!imagePath.isNullOrEmpty()) {
|
||||
mViewModel.uploadPoster(imagePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,19 +137,55 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
private fun uploadVideo(localVideoList: ArrayList<LocalVideoEntity>) {
|
||||
mViewModel.localVideoList.addAll(localVideoList)
|
||||
runOnIoThread {
|
||||
localVideoList.forEach {
|
||||
if (it.poster.startsWith("http")) {
|
||||
runOnUiThread {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertPlaceholderVideo(it.id, it.poster)
|
||||
}
|
||||
} else {
|
||||
val videoThumbnail = BitmapUtils.getVideoThumbnail(it.filePath)
|
||||
val filePath = "${cacheDir.absolutePath}${File.separator}${it.id}.webp"
|
||||
BitmapUtils.saveBitmap(videoThumbnail, filePath)
|
||||
it.poster = filePath
|
||||
runOnUiThread {
|
||||
mRichEditor.focusEditor()
|
||||
mRichEditor.insertPlaceholderVideo(it.id, "$FILE_HOST${it.poster}")
|
||||
}
|
||||
}
|
||||
}
|
||||
mViewModel.uploadVideo()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mAddLabelContainer.visibility = if (this is ArticleEditActivity) View.VISIBLE else View.GONE
|
||||
mViewModel = provideViewModel()
|
||||
mViewModel.setUploadVideoListener(this)
|
||||
mKeyboardHeightProvider = KeyboardHeightProvider(this)
|
||||
mRichEditor.post { mKeyboardHeightProvider?.start() }
|
||||
mRichEditor.setPadding(20, 15, 20, 15)
|
||||
// 防止个别手机在Js里无法获取粘贴内容
|
||||
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
|
||||
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
|
||||
mRichEditor.addJavascriptInterface(OnEditorTextChangeListener(), "OnEditorTextChangeListener")
|
||||
mRichEditor.addJavascriptInterface(
|
||||
OnEditorTextChangeListener(),
|
||||
"OnEditorTextChangeListener"
|
||||
)
|
||||
mRichEditor.addJavascriptInterface(OnVideoListener(), "onVideoListener")
|
||||
mRichEditor.addJavascriptInterface(
|
||||
OnQuoteCountChangeListener(),
|
||||
"OnQuoteCountChangeListener"
|
||||
)
|
||||
mRichEditor.setInputEnabled(true)
|
||||
mRichEditor.setPadding(16, 15, 16, 15)
|
||||
|
||||
mRichEditor.setOnTouchListener { _, _ ->
|
||||
if (mIsExtendedKeyboardShow) {
|
||||
@ -129,14 +195,46 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mRichEditor.hasFocus()
|
||||
} else false
|
||||
}
|
||||
mOriginalCb.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
mOriginalTipsContainer.alpha = 0f
|
||||
mOriginalTipsContainer.visibility = View.VISIBLE
|
||||
ObjectAnimator.ofFloat(mOriginalTipsContainer, "alpha", 0f, 1f).setDuration(200).start()
|
||||
}
|
||||
}
|
||||
observeData()
|
||||
}
|
||||
|
||||
private fun observeData() {
|
||||
mViewModel.chooseImagesUpload.observe(this, Observer {
|
||||
mRichEditor.focusEditor()
|
||||
for (key in it.keys) {
|
||||
mRichEditor.insertPlaceholderImage(key)
|
||||
}
|
||||
})
|
||||
mViewModel.chooseImagesUploadSuccess.observe(this, Observer {
|
||||
val jsonArray = JSONArray()
|
||||
for (key in it.keys) {
|
||||
val jsonObject = JSONObject()
|
||||
jsonObject.put("id", key)
|
||||
jsonObject.put("url", it[key])
|
||||
jsonArray.put(jsonObject)
|
||||
}
|
||||
mRichEditor.replacePlaceholderImage(jsonArray.toString())
|
||||
})
|
||||
}
|
||||
|
||||
override fun onKeyboardHeightChanged(height: Int, orientation: Int) {
|
||||
mIsKeyBoardShow = height > 0
|
||||
if (height > 0) {
|
||||
closeExtendedKeyboard()
|
||||
}
|
||||
}
|
||||
|
||||
fun closeExtendedKeyboard() {
|
||||
mEditorInsertDetailContainer.visibility = View.GONE
|
||||
mEditorFont.isChecked = false
|
||||
mEditorLink.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
mIsExtendedKeyboardShow = false
|
||||
}
|
||||
|
||||
@ -144,41 +242,15 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mEditorFont.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
fun changeAddLabel(isLabelContainerShow: Boolean) {
|
||||
if (isLabelContainerShow) {
|
||||
mLabelNumTv.visibility = View.GONE
|
||||
mLabelArrowIv.visibility = View.VISIBLE
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.bg_editor_insert_add_label)
|
||||
} else {
|
||||
val selectedLabel = getSelectedLabel()
|
||||
if (selectedLabel == 0) {
|
||||
mAddLabelTv.text = "添加标签"
|
||||
mLabelNumTv.visibility = View.GONE
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.text_666666))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.ic_add_label), null, null, null)
|
||||
} else {
|
||||
mAddLabelTv.text = "标签"
|
||||
mLabelNumTv.visibility = View.VISIBLE
|
||||
mLabelNumTv.text = selectedLabel.toString()
|
||||
mAddLabelTv.setTextColor(ContextCompat.getColor(this, R.color.theme_font))
|
||||
mAddLabelTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
|
||||
}
|
||||
mLabelArrowIv.visibility = View.GONE
|
||||
mAddLabelContainer.background = ContextCompat.getDrawable(this, R.drawable.border_round_stroke_eee_999)
|
||||
}
|
||||
}
|
||||
|
||||
open fun getSelectedLabel(): Int = 0
|
||||
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.add_label_container, R.id.editor_font_underline,
|
||||
R.id.editor_font_bold, R.id.editor_font_italic, R.id.editor_font_strikethrough,
|
||||
R.id.editor_paragraph_h1, R.id.editor_paragraph_h2, R.id.editor_paragraph_h3,
|
||||
R.id.editor_paragraph_h4, R.id.editor_font_container, R.id.editor_paragraph_container,
|
||||
R.id.editor_paragraph_quote, R.id.editor_link_answer, R.id.editor_link_article,
|
||||
R.id.editor_link_game, R.id.editor_link_video)
|
||||
@OnClick(
|
||||
R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_font_underline,
|
||||
R.id.editor_font_bold, R.id.editor_font_italic, R.id.editor_font_strikethrough,
|
||||
R.id.editor_paragraph_h1, R.id.editor_paragraph_h2, R.id.editor_paragraph_h3,
|
||||
R.id.editor_paragraph_h4, R.id.editor_font_container, R.id.editor_paragraph_container,
|
||||
R.id.editor_paragraph_quote, R.id.editor_link_answer, R.id.editor_link_article,
|
||||
R.id.editor_link_game, R.id.editor_link_video, R.id.uploadVideoGuideClose,
|
||||
R.id.originalTipsClose
|
||||
)
|
||||
fun onRichClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.editor_font -> {
|
||||
@ -187,9 +259,6 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
R.id.editor_link -> {
|
||||
controlEditorLinkContainer()
|
||||
}
|
||||
R.id.add_label_container -> {
|
||||
controlAddLabelContainer()
|
||||
}
|
||||
R.id.editor_font_bold -> {
|
||||
mEditorFontBold.isChecked = !mEditorFontBold.isChecked
|
||||
mRichEditor.setBold()
|
||||
@ -267,32 +336,108 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
}
|
||||
R.id.editor_link_answer -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-回答")
|
||||
startActivityForResult(InsertAnswerWrapperActivity.getIntent(this), INSERT_ANSWER_CODE)
|
||||
startActivityForResult(
|
||||
InsertAnswerWrapperActivity.getIntent(this),
|
||||
INSERT_ANSWER_CODE
|
||||
)
|
||||
}
|
||||
R.id.editor_link_article -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-文章")
|
||||
startActivityForResult(InsertArticleWrapperActivity.getIntent(this), INSERT_ARTICLE_CODE)
|
||||
startActivityForResult(
|
||||
InsertArticleWrapperActivity.getIntent(this),
|
||||
INSERT_ARTICLE_CODE
|
||||
)
|
||||
}
|
||||
R.id.editor_link_game -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-游戏")
|
||||
startActivityForResult(GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE), INSERT_GAME_CODE)
|
||||
startActivityForResult(
|
||||
GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE),
|
||||
INSERT_GAME_CODE
|
||||
)
|
||||
}
|
||||
R.id.editor_link_video -> {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(this,
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
startActivityForResult(VideoActivity.getIntent(this@BaseRichEditorActivity), VideoActivity.INSERT_VIDEO_CODE)
|
||||
}
|
||||
})
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
startActivityForResult(
|
||||
LocalMediaActivity.getIntent(
|
||||
this@BaseRichEditorActivity,
|
||||
LocalMediaActivity.ChooseType.VIDEO,
|
||||
3,
|
||||
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
|
||||
), INSERT_VIDEO_CODE
|
||||
)
|
||||
NewLogUtils.logChooseMedia(
|
||||
"view_media",
|
||||
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
|
||||
"视频"
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
R.id.editor_image -> {
|
||||
if (!mAgreePostPic && !NetworkUtils.isWifiOr4GOr3GConnected(this)) {
|
||||
mAgreePostPic = true
|
||||
DialogUtils.showAlertDialog(
|
||||
this,
|
||||
"警告",
|
||||
"当前使用移动网络,上传图片会消耗手机流量",
|
||||
"我知道了", "", { startMediaStore() }, null
|
||||
)
|
||||
return
|
||||
}
|
||||
startMediaStore()
|
||||
NewLogUtils.logChooseMedia(
|
||||
"view_media",
|
||||
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
|
||||
"图片"
|
||||
)
|
||||
}
|
||||
R.id.uploadVideoGuideClose -> {
|
||||
hideUploadVideoGuide()
|
||||
if (mGuideDisposable != null && !mGuideDisposable!!.isDisposed) {
|
||||
mGuideDisposable!!.dispose()
|
||||
mGuideDisposable = null
|
||||
}
|
||||
}
|
||||
R.id.originalTipsClose -> {
|
||||
val animator = ObjectAnimator.ofFloat(mOriginalTipsContainer, "alpha", 1f, 0f).setDuration(200)
|
||||
animator.doOnEnd {
|
||||
mOriginalTipsContainer.visibility = View.GONE
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startMediaStore() {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入图片", "插入图片")
|
||||
if (mViewModel.mapImages.size >= 50) {
|
||||
toast(R.string.answer_edit_max_img_hint)
|
||||
return
|
||||
}
|
||||
try {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(this, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
val intent = LocalMediaActivity.getIntent(
|
||||
this@BaseRichEditorActivity,
|
||||
LocalMediaActivity.ChooseType.IMAGE,
|
||||
10,
|
||||
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
|
||||
)
|
||||
startActivityForResult(intent, REQUEST_CODE_IMAGE)
|
||||
}
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
toast(R.string.media_image_hint)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun controlEditorFontContainer() {
|
||||
mEditorFont.isChecked = !mEditorFont.isChecked
|
||||
mEditorLink.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
val isShouldDelay = if (mEditorFont.isChecked) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
true
|
||||
@ -301,20 +446,20 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetailContainer.visibility =
|
||||
if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorParagraphContainer.visibility =
|
||||
if (mEditorFont.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = View.GONE
|
||||
mTagsContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mEditorFont.isChecked
|
||||
changeAddLabel(false)
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
private fun controlEditorLinkContainer() {
|
||||
mEditorLink.isChecked = !mEditorLink.isChecked
|
||||
mEditorFont.isChecked = false
|
||||
mAddLabelContainer.isSelected = false
|
||||
val isShouldDelay = if (mEditorLink.isChecked) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
true
|
||||
@ -323,38 +468,16 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorInsertDetailContainer.visibility =
|
||||
if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
|
||||
mEditorFontContainer.visibility = View.GONE
|
||||
mEditorParagraphContainer.visibility = View.GONE
|
||||
mTagsContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mEditorLink.isChecked
|
||||
changeAddLabel(false)
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
fun controlAddLabelContainer() {
|
||||
mEditorLink.isChecked = false
|
||||
mEditorFont.isChecked = false
|
||||
mAddLabelContainer.isSelected = !mAddLabelContainer.isSelected
|
||||
val isShouldDelay = if (mAddLabelContainer.isSelected) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(this)
|
||||
changeAddLabel(true)
|
||||
true
|
||||
} else {
|
||||
Util_System_Keyboard.showSoftKeyboard(this)
|
||||
changeAddLabel(false)
|
||||
false
|
||||
}
|
||||
mEditorInsertDetailContainer.postDelayed({
|
||||
mEditorInsertDetailContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
|
||||
mTagsContainer.visibility = if (mAddLabelContainer.isSelected) View.VISIBLE else View.GONE
|
||||
mEditorLinkContainer.visibility = View.GONE
|
||||
mEditorFontContainer.visibility = View.GONE
|
||||
mEditorParagraphContainer.visibility = View.GONE
|
||||
mIsExtendedKeyboardShow = mAddLabelContainer.isSelected
|
||||
}, if (isShouldDelay) 200 else 0L)
|
||||
}
|
||||
|
||||
override fun handleBackPressed(): Boolean {
|
||||
if (mIsExtendedKeyboardShow) {
|
||||
@ -364,6 +487,53 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
return super.handleBackPressed()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(null)
|
||||
}
|
||||
|
||||
//视频上传功能引导
|
||||
fun showUploadVideoGuide() {
|
||||
mUploadVideoGuideContainer.postDelayed({
|
||||
val count = SPUtils.getInt(getVideoGuideKey(), 0)
|
||||
if (count >= mMaxUploadVideoGuideCount) return@postDelayed
|
||||
mUploadVideoGuideContainer.alpha = 0f
|
||||
mUploadVideoGuideContainer.visibility = View.VISIBLE
|
||||
mUploadVideoGuideContainer.animate().alpha(1f).setDuration(200).start()
|
||||
mGuideDisposable = countDownTimer(3) { finish, _ ->
|
||||
if (finish) {
|
||||
hideUploadVideoGuide()
|
||||
}
|
||||
}
|
||||
SPUtils.setInt(getVideoGuideKey(), count + 1)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
fun hideUploadVideoGuide() {
|
||||
val animate = mUploadVideoGuideContainer.animate().alpha(0f).setDuration(200)
|
||||
animate.doOnEnd {
|
||||
mUploadVideoGuideContainer.visibility = View.GONE
|
||||
}
|
||||
animate.start()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mKeyboardHeightProvider?.close()
|
||||
val path = mViewModel.currentUploadingVideo?.filePath
|
||||
if (path != null && UploadManager.isUploading(path)) {
|
||||
UploadManager.cancelTask(path)
|
||||
}
|
||||
if (mGuideDisposable != null && !mGuideDisposable!!.isDisposed) {
|
||||
mGuideDisposable!!.dispose()
|
||||
mGuideDisposable = null
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnCursorChangeListener {
|
||||
@JavascriptInterface
|
||||
@ -397,11 +567,12 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
@JavascriptInterface
|
||||
fun onPaste() {
|
||||
val clipboard =
|
||||
HaloApp.getInstance().application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
HaloApp.getInstance().application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipText = clipboard.text.toString()
|
||||
if (!TextUtils.isEmpty(clipText)) {
|
||||
// 替换换行符号否则 插入失败
|
||||
val text = clipText.replace("[ ]".toRegex(), " ").replace("[\r\n]".toRegex(), "<br/>")
|
||||
val text = clipText.replace("[ ]".toRegex(), " ")
|
||||
.replace("[\r\n]".toRegex(), "<br/>")
|
||||
mBaseHandler.post { mRichEditor.insertHtml(text) }
|
||||
}
|
||||
}
|
||||
@ -413,11 +584,103 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
val num = if (count > MAX_INPUT_TEXT_NUM) MAX_INPUT_TEXT_NUM - count else count
|
||||
mEditorTextNumTv.post {
|
||||
mEditorTextNumTv.text = num.toString()
|
||||
mViewModel.quoteCountEntity.textCount = num
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnQuoteCountChangeListener {
|
||||
@JavascriptInterface
|
||||
fun onQuoteCountChange(
|
||||
imageCount: Int,
|
||||
articleCount: Int,
|
||||
answerCount: Int,
|
||||
videoCount: Int,
|
||||
gameCount: Int
|
||||
) {
|
||||
mEditorTextNumTv.post {
|
||||
mViewModel.quoteCountEntity.apply {
|
||||
this.imageCount = imageCount
|
||||
this.articleCount = articleCount
|
||||
this.answerCount = answerCount
|
||||
this.videoCount = videoCount
|
||||
this.gameCount = gameCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnVideoListener {
|
||||
@JavascriptInterface
|
||||
fun showDeleteDialog(id: String) {
|
||||
DialogHelper.showDialog(this@BaseRichEditorActivity, "提示", "确定删除吗?", "确定", "取消", {
|
||||
runOnUiThread {
|
||||
mRichEditor.delPlaceholderVideo(id)
|
||||
mViewModel.deleteVideo(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun updatePoster(id: String, videoId: String, url: String) {
|
||||
mViewModel.id = id
|
||||
mViewModel.videoId = videoId
|
||||
val videoEntity = VideoEntity(url = url)
|
||||
val intent =
|
||||
PosterEditActivity.getIntentByVideo(this@BaseRichEditorActivity, videoEntity)
|
||||
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun deleteUploadingVideo(id: String) {
|
||||
mViewModel.deleteVideo(id)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun reUploadVideo(id: String) {
|
||||
val video = mViewModel.uploadVideoErrorList.find { it.id == id }
|
||||
if (video != null) {
|
||||
mViewModel.localVideoList.add(video)
|
||||
mViewModel.uploadVideoErrorList.remove(video)
|
||||
mViewModel.uploadVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun insertPlaceholderVideo(id: String, poster: String) {
|
||||
mRichEditor.insertPlaceholderVideo(id, poster)
|
||||
}
|
||||
|
||||
override fun updateVideoProgress(id: String, progress: String) {
|
||||
mRichEditor.updateVideoProgress(id, progress)
|
||||
}
|
||||
|
||||
override fun videoUploadFinished(id: String, url: String, msg: JsonObject) {
|
||||
try {
|
||||
val obj = JSONObject()
|
||||
obj.put("poster", msg.get("poster").asString)
|
||||
obj.put("url", msg.get("url").asString)
|
||||
obj.put("duration", RichEditor.formatVideoDuration(msg.get("length").asLong))
|
||||
obj.put("id", msg.get("_id").asString)
|
||||
obj.put("status", "pending")
|
||||
mRichEditor.videoUploadFinished(id, url, obj.toString())
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun changePoster(id: String, poster: String) {
|
||||
mRichEditor.changePoster(id, poster)
|
||||
}
|
||||
|
||||
override fun videoUploadFailed(id: String) {
|
||||
mRichEditor.videoUploadFailed(id)
|
||||
}
|
||||
|
||||
open fun getSelectedLabel(): Int = 0
|
||||
abstract fun mtaEventName(): String
|
||||
abstract fun provideViewModel(): VM
|
||||
abstract fun getVideoGuideKey(): String
|
||||
|
||||
companion object {
|
||||
const val ELEMENT_NAME_BOLD = " b "
|
||||
@ -434,5 +697,9 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
const val INSERT_ARTICLE_CODE = 412
|
||||
const val INSERT_GAME_CODE = 413
|
||||
const val MAX_INPUT_TEXT_NUM = 10000
|
||||
|
||||
const val REQUEST_CODE_IMAGE = 120
|
||||
const val INSERT_VIDEO_CODE = 121
|
||||
const val REQUEST_CODE_IMAGE_CROP = 122
|
||||
}
|
||||
}
|
||||
444
app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt
Normal file
444
app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt
Normal file
@ -0,0 +1,444 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.media.ThumbnailUtils
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.base.fragment.WaitingDialogFragment
|
||||
import com.gh.common.runOnUiThread
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.ErrorEntity
|
||||
import com.gh.gamecenter.entity.LocalVideoEntity
|
||||
import com.gh.gamecenter.entity.QuoteCountEntity
|
||||
import com.gh.gamecenter.qa.BbsType
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.retrofit.service.ApiService
|
||||
import com.gh.gamecenter.video.upload.OnUploadListener
|
||||
import com.gh.gamecenter.video.upload.UploadManager
|
||||
import com.google.gson.JsonObject
|
||||
import com.lightgame.utils.Utils
|
||||
import com.zhihu.matisse.Matisse
|
||||
import com.zhihu.matisse.internal.utils.PathUtils
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.LinkedHashMap
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.Map
|
||||
import kotlin.collections.find
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.set
|
||||
|
||||
abstract class BaseRichEditorViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val mApi: ApiService = RetrofitManager.getInstance(application).api
|
||||
val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
|
||||
val uploadingImage = ArrayList<LinkedHashMap<String, String>>()
|
||||
val chooseImagesUpload = MutableLiveData<LinkedHashMap<String, String>>()
|
||||
val chooseImagesUploadSuccess = MutableLiveData<LinkedHashMap<String, String>>()
|
||||
var uploadImageSubscription: Disposable? = null
|
||||
val mapImages = HashMap<String, String>()
|
||||
val localVideoList = ArrayList<LocalVideoEntity>()
|
||||
val uploadVideoErrorList = ArrayList<LocalVideoEntity>()
|
||||
var currentUploadingVideo: LocalVideoEntity? = null
|
||||
var type: String = "" //游戏论坛:game_bbs 官方论坛:official_bbs
|
||||
private var mUploadVideoListener: UploadVideoListener? = null
|
||||
val TITLE_MIN_LENGTH = 6
|
||||
val MIN_TEXT_LENGTH = 6
|
||||
val MAX_TEXT_LENGTH = 10000
|
||||
val FILE_HOST = "file:///"
|
||||
var id = ""//视频标记
|
||||
var videoId = ""//更改封面视频id
|
||||
val quoteCountEntity = QuoteCountEntity()//数据上报用
|
||||
|
||||
fun setUploadVideoListener(uploadVideoListener: UploadVideoListener) {
|
||||
this.mUploadVideoListener = uploadVideoListener
|
||||
}
|
||||
|
||||
//检查图片是否符合规则并上传图片
|
||||
fun uploadPic(data: Intent) {
|
||||
val uris = Matisse.obtainResult(data)
|
||||
val pictureList = ArrayList<String>()
|
||||
for (uri in uris) {
|
||||
val picturePath = PathUtils.getPath(getApplication(), uri)
|
||||
if (picturePath != null) {
|
||||
if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
|
||||
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
|
||||
val application: Application = getApplication()
|
||||
Utils.toast(
|
||||
getApplication(),
|
||||
application.getString(R.string.pic_max_hint, count)
|
||||
)
|
||||
continue
|
||||
}
|
||||
Utils.log("picturePath = $picturePath")
|
||||
pictureList.add(picturePath)
|
||||
} else {
|
||||
Utils.log("picturePath is null")
|
||||
}
|
||||
}
|
||||
if (pictureList.size == 0) return
|
||||
val imageType = when (getRichType()) {
|
||||
RichType.ARTICLE -> UploadImageUtils.UploadType.community_article
|
||||
RichType.QUESTION -> UploadImageUtils.UploadType.question
|
||||
else -> UploadImageUtils.UploadType.poster
|
||||
}
|
||||
uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(
|
||||
imageType,
|
||||
pictureList,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListListener {
|
||||
override fun onProgress(total: Long, progress: Long) {}
|
||||
|
||||
override fun onCompressSuccess(imageUrls: List<String>) {
|
||||
val chooseImageMd5Map = LinkedHashMap<String, String>()
|
||||
imageUrls.forEach {
|
||||
chooseImageMd5Map[MD5Utils.getUrlMD5(it)] = ""
|
||||
}
|
||||
uploadingImage.add(chooseImageMd5Map)
|
||||
chooseImagesUpload.postValue(chooseImageMd5Map)
|
||||
}
|
||||
|
||||
override fun onSingleSuccess(imageUrl: Map<String, String>) {
|
||||
val map = LinkedHashMap<String, String>()
|
||||
for (key in imageUrl.keys) {
|
||||
map[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI()
|
||||
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrl[key] ?: ""
|
||||
}
|
||||
chooseImagesUploadSuccess.postValue(map)
|
||||
}
|
||||
|
||||
override fun onSuccess(
|
||||
imageUrl: LinkedHashMap<String, String>,
|
||||
errorMap: Map<String, Exception>
|
||||
) {
|
||||
val uploadMap = uploadingImage.find {
|
||||
it.containsKey(
|
||||
MD5Utils.getUrlMD5(
|
||||
imageUrl.entries.iterator().next().key
|
||||
)
|
||||
)
|
||||
}
|
||||
uploadMap?.let {
|
||||
uploadingImage.remove(uploadMap)
|
||||
}
|
||||
|
||||
val errorSize = pictureList.size - imageUrl.size
|
||||
if (errorSize > 0) {
|
||||
val map = LinkedHashMap<String, String>()
|
||||
for (key in errorMap.keys) {
|
||||
map[MD5Utils.getUrlMD5(key)] = ""
|
||||
}
|
||||
//value为空会删除PlaceholderImage
|
||||
chooseImagesUploadSuccess.postValue(map)
|
||||
|
||||
for (error in errorMap.values) {
|
||||
if (error is HttpException && error.code() == 403) {
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(errorMap: Map<String, Exception>) {
|
||||
val errorSize = pictureList.size
|
||||
if (errorSize > 0) {
|
||||
val map = LinkedHashMap<String, String>()
|
||||
for (key in errorMap.keys) {
|
||||
map[MD5Utils.getUrlMD5(key)] = ""
|
||||
}
|
||||
//value为空会删除PlaceholderImage
|
||||
chooseImagesUploadSuccess.postValue(map)
|
||||
}
|
||||
|
||||
for (error in errorMap.values) {
|
||||
if (error is HttpException && error.code() == 403) {
|
||||
val e = error.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
|
||||
if (e != null && e.code == 403017) {
|
||||
Utils.toast(
|
||||
getApplication(),
|
||||
errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传"
|
||||
)
|
||||
} else {
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if (errorSize == 1) {
|
||||
Utils.toast(getApplication(), "图片上传失败")
|
||||
} else {
|
||||
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun uploadPoster(picturePath: String) {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", true))
|
||||
uploadImageSubscription =
|
||||
UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster,
|
||||
picturePath,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListener {
|
||||
override fun onSuccess(imageUrl: String) {
|
||||
patchVideoPoster(imageUrl)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable?) {
|
||||
handleUploadPosterResult(true)
|
||||
}
|
||||
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun patchVideoPoster(poster: String) {
|
||||
if (id.isEmpty() || videoId.isEmpty()) return
|
||||
val map = hashMapOf("poster" to poster, "type" to getVideoType())
|
||||
mApi.patchInsertVideo(videoId, map.toRequestBody())
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
override fun onResponse(response: ResponseBody?) {
|
||||
super.onResponse(response)
|
||||
mUploadVideoListener?.changePoster(id, poster)
|
||||
handleUploadPosterResult(false)
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
super.onFailure(e)
|
||||
handleUploadPosterResult(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleUploadPosterResult(isFailure: Boolean = false) {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", false))
|
||||
if (isFailure) {
|
||||
ToastUtils.showToast("封面更改失败")
|
||||
}
|
||||
id = ""
|
||||
videoId = ""
|
||||
}
|
||||
|
||||
fun deleteVideo(id: String) {
|
||||
if (localVideoList.isNotEmpty()) {
|
||||
val video = localVideoList.find { it.id == id }
|
||||
if (video != null) {
|
||||
if (UploadManager.isUploading(video.filePath)) {
|
||||
UploadManager.cancelTask(video.filePath)
|
||||
}
|
||||
localVideoList.remove(video)
|
||||
}
|
||||
}
|
||||
if (uploadVideoErrorList.isNotEmpty()) {
|
||||
val video = uploadVideoErrorList.find { it.id == id }
|
||||
if (video != null) {
|
||||
uploadVideoErrorList.remove(video)
|
||||
}
|
||||
}
|
||||
if (currentUploadingVideo?.id == id) {
|
||||
currentUploadingVideo = null
|
||||
uploadVideo()
|
||||
}
|
||||
}
|
||||
|
||||
fun uploadVideo() {
|
||||
if (currentUploadingVideo != null) return
|
||||
if (localVideoList.isEmpty()) return
|
||||
currentUploadingVideo = localVideoList[0]
|
||||
UploadManager.createUploadTask(currentUploadingVideo?.filePath
|
||||
?: "", object : OnUploadListener {
|
||||
override fun onProgressChanged(
|
||||
uploadFilePath: String,
|
||||
currentSize: Long,
|
||||
totalSize: Long,
|
||||
speed: Long
|
||||
) {
|
||||
runOnUiThread {
|
||||
val percent = (currentSize * 100 / totalSize.toFloat()).roundTo(1)
|
||||
currentUploadingVideo?.id?.let {
|
||||
mUploadVideoListener?.updateVideoProgress(it, percent.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUploadSuccess(uploadFilePath: String, url: String) {
|
||||
if (currentUploadingVideo != null) {
|
||||
postVideoPosterAndInfo(uploadFilePath, url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUploadFailure(uploadFilePath: String, errorMsg: String) {
|
||||
uploadVideoFailure()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun postVideoPosterAndInfo(uploadFilePath: String, url: String) {
|
||||
val localVideoPoster =
|
||||
getApplication<Application>().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg"
|
||||
try {
|
||||
val bmp = ThumbnailUtils.createVideoThumbnail(
|
||||
uploadFilePath,
|
||||
MediaStore.Images.Thumbnails.MINI_KIND
|
||||
)
|
||||
// bmp 可能为空
|
||||
FileOutputStream(localVideoPoster).use { out ->
|
||||
bmp?.compress(Bitmap.CompressFormat.PNG, 100, out)
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
ToastUtils.showToast("视频封面操作失败")
|
||||
uploadVideoFailure()
|
||||
return
|
||||
}
|
||||
uploadImageSubscription =
|
||||
UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster,
|
||||
localVideoPoster,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListener {
|
||||
override fun onSuccess(imageUrl: String) {
|
||||
postVideoInfo(url, imageUrl)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable?) {
|
||||
uploadVideoFailure()
|
||||
}
|
||||
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun postVideoInfo(url: String, poster: String) {
|
||||
val map = HashMap<String, Any>().apply {
|
||||
put("poster", poster)
|
||||
put("url", url)
|
||||
put("format", currentUploadingVideo?.format ?: "")
|
||||
put("size", currentUploadingVideo?.size ?: 0)
|
||||
put("length", (currentUploadingVideo?.duration ?: 0) / 1000)
|
||||
put("type", getVideoType())
|
||||
}
|
||||
val requestBody = map.toRequestBody()
|
||||
mApi.insertVideo(requestBody)
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<JsonObject>() {
|
||||
override fun onResponse(response: JsonObject?) {
|
||||
super.onResponse(response)
|
||||
if (response != null) {
|
||||
uploadVideoSuccess(poster, url, response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
super.onFailure(e)
|
||||
uploadVideoFailure()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun uploadVideoSuccess(poster: String, url: String, data: JsonObject) {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", false))
|
||||
currentUploadingVideo?.let {
|
||||
mUploadVideoListener?.changePoster(it.id, poster)
|
||||
mUploadVideoListener?.videoUploadFinished(it.id, url, data)
|
||||
UploadManager.cancelTask(it.filePath)
|
||||
localVideoList.remove(it)
|
||||
}
|
||||
currentUploadingVideo = null
|
||||
uploadVideo()
|
||||
}
|
||||
|
||||
private fun uploadVideoFailure() {
|
||||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", false))
|
||||
currentUploadingVideo?.let {
|
||||
runOnUiThread {
|
||||
mUploadVideoListener?.videoUploadFailed(it.id)
|
||||
}
|
||||
uploadVideoErrorList.add(it)
|
||||
localVideoList.remove(it)
|
||||
UploadManager.cancelTask(it.filePath)
|
||||
}
|
||||
currentUploadingVideo = null
|
||||
uploadVideo()
|
||||
}
|
||||
|
||||
fun checkIsAllUploadedAndToast(): Boolean {
|
||||
if (localVideoList.isNotEmpty() || uploadVideoErrorList.isNotEmpty()) {
|
||||
ToastUtils.showToast("视频未上传完成,视频内容保存失败")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getVideoType(): String {
|
||||
return when (type) {
|
||||
BbsType.GAME_BBS.value -> {
|
||||
when (getRichType()) {
|
||||
RichType.ARTICLE -> BbsType.GAME_BBS_ARTICLE_INSERT.value
|
||||
RichType.QUESTION -> BbsType.GAME_BBS_QUESTION_INSERT.value
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
BbsType.OFFICIAL_BBS.value -> {
|
||||
when (getRichType()) {
|
||||
RichType.ARTICLE -> BbsType.OFFICIAL_BBS_ARTICLE_INSERT.value
|
||||
RichType.QUESTION -> BbsType.OFFICIAL_BBS_QUESTION_INSERT.value
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun getRichType(): RichType
|
||||
}
|
||||
|
||||
interface UploadVideoListener {
|
||||
/**
|
||||
* 插入视频占位图
|
||||
*/
|
||||
fun insertPlaceholderVideo(id: String, poster: String)
|
||||
|
||||
/**
|
||||
* 更新视频进度条
|
||||
*/
|
||||
fun updateVideoProgress(id: String, progress: String)
|
||||
|
||||
/**
|
||||
* 上传视频完成
|
||||
*/
|
||||
fun videoUploadFinished(id: String, url: String, msg: JsonObject)
|
||||
|
||||
/**
|
||||
* 更换封面图
|
||||
*/
|
||||
fun changePoster(id: String, poster: String)
|
||||
|
||||
/**
|
||||
* 上传失败
|
||||
*/
|
||||
fun videoUploadFailed(id: String)
|
||||
}
|
||||
|
||||
enum class RichType {
|
||||
ARTICLE,
|
||||
QUESTION,
|
||||
ANSWER
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application.ActivityLifecycleCallbacks;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.gh.common.notifier.Notifier;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.AppManager;
|
||||
|
||||
/**
|
||||
* 1、写点针对生命周期的统计代码
|
||||
* 2、写点通用的逻辑
|
||||
* 3、接口解耦
|
||||
*
|
||||
* @author CsHeng
|
||||
* @Date 09/05/2017
|
||||
* @Time 6:22 PM
|
||||
*/
|
||||
public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks {
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
|
||||
AppManager.getInstance().addActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
CurrentActivityHolder.getActivitySet().add(activity);
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
DataUtils.onResume(activity);
|
||||
//FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
if (!(activity instanceof SplashScreenActivity)) {
|
||||
DownloadManager.getInstance(activity).initGameMap();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
CurrentActivityHolder.getActivitySet().remove(activity);
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
DataUtils.onPause(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
Notifier.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
if (activity.isFinishing()) {
|
||||
AppManager.getInstance().finishActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import com.gh.common.notifier.Notifier
|
||||
import com.gh.common.util.DataUtils
|
||||
import com.gh.common.util.FloatingBackViewManager
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.SplashScreenActivity
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.forum.list.ForumListActivity
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
AppManager.getInstance().addActivity(activity)
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
CurrentActivityHolder.activitySet.add(activity)
|
||||
|
||||
// 判断是否需要显示或隐藏返回小浮窗
|
||||
if (FloatingBackViewManager.getType().isNotEmpty()) {
|
||||
if (activity is EnergyCenterActivity
|
||||
&& FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_TASK
|
||||
) {
|
||||
FloatingBackViewManager.disableBackView()
|
||||
} else if (!shouldShowActivityBackView(activity)
|
||||
&& FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_ACTIVITY
|
||||
) {
|
||||
FloatingBackViewManager.disableBackView()
|
||||
} else {
|
||||
FloatingBackViewManager.showBackView(activity)
|
||||
}
|
||||
}
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
DataUtils.onResume(activity)
|
||||
// FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
if (activity !is SplashScreenActivity) {
|
||||
DownloadManager.getInstance(activity).initGameMap()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldShowActivityBackView(activity: Activity): Boolean {
|
||||
return (activity is MainActivity
|
||||
|| activity is ArticleDetailActivity
|
||||
|| activity is ForumVideoDetailActivity
|
||||
|| activity is ForumDetailActivity
|
||||
|| activity is ForumListActivity
|
||||
|| activity is NewQuestionDetailActivity)
|
||||
}
|
||||
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
CurrentActivityHolder.activitySet.remove(activity)
|
||||
FloatingBackViewManager.dismissBackView(activity)
|
||||
|
||||
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
|
||||
DataUtils.onPause(activity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
Notifier.hide()
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
if (activity.isFinishing) {
|
||||
AppManager.getInstance().finishActivity(activity)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -61,6 +61,8 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
@NonNull
|
||||
protected String mEntrance = "";
|
||||
|
||||
public long startPageTime = 0;
|
||||
|
||||
protected final Handler mBaseHandler = new BaseFragment.BaseHandler(this);
|
||||
|
||||
protected static class BaseHandler extends Handler {
|
||||
@ -225,6 +227,7 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
isEverPause = false;
|
||||
startPageTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.common
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.Base64
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@ -36,11 +37,16 @@ import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class DefaultJsApi(var context: Context) {
|
||||
|
||||
private var mLoginHandler: CompletionHandler<Any>? = null
|
||||
|
||||
@JavascriptInterface
|
||||
fun isGhzs(msg: Any): String {
|
||||
return "true"
|
||||
@ -342,6 +348,50 @@ class DefaultJsApi(var context: Context) {
|
||||
return NetworkUtils.isWifiConnected(context)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun enableBackToActivity(msg: Any) {
|
||||
FloatingBackViewManager.enableBackView(FloatingBackViewManager.TYPE_ACTIVITY, msg.toString())
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun startBBSStayTimeCount(msg: Any) {
|
||||
BbsStayTimeHelper.enableStayTimeCount(msg.toString().toInt())
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun saveBase64ImageToGallery(msg: Any) {
|
||||
val base64StringData = msg.toString()
|
||||
runOnIoThread {
|
||||
val base64String = base64StringData.replace("data:image/png;base64", "")
|
||||
tryWithDefaultCatch {
|
||||
val imageFile = File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png")
|
||||
val decodedString = Base64.decode(base64String, Base64.DEFAULT)
|
||||
val bos = BufferedOutputStream(FileOutputStream(imageFile))
|
||||
bos.write(decodedString)
|
||||
bos.flush()
|
||||
bos.close()
|
||||
|
||||
ImageUtils.saveImageToFile(imageFile, "", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun loginWithCallback(msg: Any, handler: CompletionHandler<Any>) {
|
||||
mLoginHandler = handler
|
||||
login(msg)
|
||||
}
|
||||
|
||||
fun onLogin() {
|
||||
mLoginHandler?.complete(true)
|
||||
mLoginHandler = null
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openInNewFullWebview(url: Any) {
|
||||
runOnUiThread { DirectUtils.directToFullScreenWebPage(context, url.toString(), true) }
|
||||
}
|
||||
|
||||
@Keep
|
||||
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
|
||||
|
||||
|
||||
@ -10,15 +10,16 @@ import com.gh.common.util.DirectUtils.directToFeedback
|
||||
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
|
||||
import com.gh.common.util.DirectUtils.directToGameServerCalendar
|
||||
import com.gh.common.util.DirectUtils.directToGameVideo
|
||||
import com.gh.common.util.DirectUtils.directToLegacyVideoDetail
|
||||
import com.gh.common.util.DirectUtils.directToLinkPage
|
||||
import com.gh.common.util.DirectUtils.directToQa
|
||||
import com.gh.common.util.DirectUtils.directToVideoDetail
|
||||
import com.gh.common.util.GsonUtils.gson
|
||||
import com.gh.gamecenter.LibaoDetailActivity
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.qa.BbsType
|
||||
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.lightgame.utils.Utils
|
||||
@ -63,9 +64,7 @@ object DefaultUrlHandler {
|
||||
}
|
||||
|
||||
"inurl" -> {
|
||||
intent = Intent(context, WebActivity::class.java)
|
||||
intent.putExtra(EntranceUtils.KEY_URL, uri.getQueryParameter("url"))
|
||||
context.startActivity(intent)
|
||||
DirectUtils.directToWebView(context, uri.getQueryParameter("url") ?: "")
|
||||
}
|
||||
|
||||
"outurl" -> {
|
||||
@ -141,7 +140,8 @@ object DefaultUrlHandler {
|
||||
}
|
||||
EntranceUtils.HOST_USERHOME -> {
|
||||
val position = uri.getQueryParameter("position")
|
||||
DirectUtils.directToHomeActivity(context, id, if (position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
|
||||
val subtype = uri.getQueryParameter("sub_type") ?: ""
|
||||
DirectUtils.directToHomeActivity(context, id, subtype, if (position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_MORE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
@ -159,11 +159,14 @@ object DefaultUrlHandler {
|
||||
} else {
|
||||
id
|
||||
}
|
||||
directToVideoDetail(context, id, location, false, gameId, entrance, "", referer, type, act, paginationType, fieldId, sectionName)
|
||||
directToLegacyVideoDetail(context, id, location, false, gameId, entrance, "", referer, type, act, paginationType, fieldId, sectionName)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_DETAIL -> {
|
||||
DirectUtils.directToVideoDetail(context, id, entrance, path)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_SINGLE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
|
||||
DirectUtils.directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
|
||||
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_STREAMING_HOME -> {
|
||||
@ -275,11 +278,39 @@ object DefaultUrlHandler {
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_RATING_DETAIL -> {
|
||||
DirectUtils.directToGameRatingDetail(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), EntranceUtils.ENTRANCE_BROWSER)
|
||||
DirectUtils.directToGameRatingDetail(
|
||||
context,
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
|
||||
uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID),
|
||||
EntranceUtils.ENTRANCE_BROWSER)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_FORUM -> {
|
||||
DirectUtils.directToForum(context)
|
||||
val position = uri.getQueryParameter(EntranceUtils.KEY_POSITION)?.toInt()
|
||||
|
||||
DirectUtils.directToForum(context, position ?: 0)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_UPLOAD_VIDEO_NEW -> {
|
||||
val activityName = uri.getQueryParameter("activity_name") ?: ""
|
||||
val activityId = uri.getQueryParameter("activity_id") ?: ""
|
||||
val forumName = uri.getQueryParameter("forum_name") ?: ""
|
||||
val forumId = uri.getQueryParameter("forum_id") ?: ""
|
||||
val forumIcon = uri.getQueryParameter("forum_icon") ?: ""
|
||||
val forumType = uri.getQueryParameter("forum_type") ?: BbsType.OFFICIAL_BBS.value
|
||||
|
||||
val activityLabelEntity = ActivityLabelEntity(id = activityId, name = activityName)
|
||||
val communityEntity = CommunityEntity(id = forumId, name = forumName, icon = forumIcon)
|
||||
|
||||
context.startActivity(VideoPublishActivity.getIntent(
|
||||
context,
|
||||
communityEntity,
|
||||
activityLabelEntity,
|
||||
forumType,
|
||||
false,
|
||||
entrance,
|
||||
""
|
||||
))
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_SUGGESTION -> {
|
||||
@ -418,10 +449,11 @@ object DefaultUrlHandler {
|
||||
val name = uri.getQueryParameter("communityName") ?: ""
|
||||
DirectUtils.directToCommunityColumn(context, CommunityEntity(id, name), columnsId, entrance, "")
|
||||
}
|
||||
contains("zone") -> {
|
||||
contains("zone") && split("/").size > 2 -> {
|
||||
val gameId = split("/")[2]
|
||||
DirectUtils.directGameZone(context, gameId, url, entrance)
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
@ -62,6 +62,7 @@ public class Config {
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
public static final String DEFAULT_CHANNEL = "GH_TEST2";
|
||||
public static final String DEFAULT_CHANNEL_FOR_RELEASE = "GH_LOST"; // 正式包的缺省渠道,避免因渠道丢失而回落到测试渠道
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
@ -301,7 +302,7 @@ public class Config {
|
||||
});
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel)
|
||||
.getApi().getNewSettings(Build.MANUFACTURER, Build.MODEL, channel, Build.VERSION.SDK_INT, BuildConfig.VERSION_NAME)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NewSettingsEntity>() {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.constant;
|
||||
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.TimeUtils;
|
||||
import com.halo.assistant.HaloApp;
|
||||
|
||||
public class Constants {
|
||||
@ -170,6 +171,9 @@ public class Constants {
|
||||
//首页视频播放进度
|
||||
public static final String SP_HOME_VIDEO_PLAY_RECORD = "home_video_play_record";
|
||||
|
||||
// 论坛内容视频播放进度
|
||||
public static final String SP_CONTENT_VIDEO_PLAY_RECORD = "content_video_play_record";
|
||||
|
||||
// 用户是否曾经永久拒绝过存储权限
|
||||
public static final String SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION = "user_has_permanently_denied_storage_permission";
|
||||
|
||||
@ -182,17 +186,38 @@ public class Constants {
|
||||
// 头像挂件ID
|
||||
public static final String SP_CHOOSE_AVATAR_ID = "choose_avatar_id";
|
||||
|
||||
// 是否显示返回任务悬浮图标
|
||||
public static final String SP_SHOW_TASK_FLOAT = "show_task_float";
|
||||
// 悬浮图标Y值
|
||||
public static final String SP_TASK_FLOAT_LAST_Y = "task_float_last_y";
|
||||
|
||||
// 是否第一次进入新分类2.0
|
||||
public static final String SP_FIRST_ENTER_CATEGORY_V2 = "first_enter_category_v2";
|
||||
|
||||
// 是否成功取过号
|
||||
public static final String SP_HAS_GET_PHONE_INFO = "has_get_phone_info";
|
||||
|
||||
// 是否点击过更换背景按钮
|
||||
public static final String SP_HAS_CLICK_CHANGE_BG = "has_click_change_bg";
|
||||
// 是否显示更换背景提示
|
||||
public static final String SP_SHOW_CHANGE_BG_TIPS = "show_change_bg_tips" + TimeUtils.getStartTimeOfToday();
|
||||
|
||||
// 新分类2.0引导
|
||||
public static final String SP_SHOW_CATEGORY_GUIDE = "show_category_guide";
|
||||
|
||||
|
||||
// 内容视频播放选项
|
||||
public static final String SP_CONTENT_VIDEO_OPTION = "content_video_option";
|
||||
// 首页/游戏详情页视频播放选项
|
||||
public static final String SP_HOME_OR_DETAIL_VIDEO_OPTION = "home_or_detail_video_option";
|
||||
// 是否默认静音播放视频
|
||||
public static final String SP_VIDEO_PLAY_MUTE = "video_play_mute";
|
||||
//帖子发布页上传视频引导
|
||||
public static final String SP_ARTICLE_VIDEO_GUIDE = "article_video_guide";
|
||||
//问题发布页上传视频引导
|
||||
public static final String SP_QUESTION_VIDEO_GUIDE = "question_video_guide";
|
||||
// 社区首页引导
|
||||
public static final String SP_COMMUNITY_HOME_GUIDE = "community_home_guide";
|
||||
// 社区首页发布按钮引导
|
||||
public static final String SP_COMMUNITY_HOME_VIDEO_GUIDE = "community_home_video_guide";
|
||||
// 论坛详情申请版主引导
|
||||
public static final String SP_FORUM_DETAIL_MODERATOR_GUIDE = "forum_detail_moderator_guide";
|
||||
|
||||
//手机号码匹配规则
|
||||
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}$";
|
||||
@ -298,6 +323,10 @@ public class Constants {
|
||||
public static final String WITHDRAW_INFO_ADDRESS_DEV = "https://static-web.ghzs.com/shop-dev/index.html#/cash?from=ghzs";
|
||||
public static final String WITHDRAW_INFO_ADDRESS = "https://static-web.ghzs.com/shop/index.html#/cash?from=ghzs";
|
||||
|
||||
// 活动详情
|
||||
public static final String ACTIVITY_DETAIL_ADDRESS_DEV = "https://static-web.ghzs.com/ghzs_activity_dev/common.html?from=ghzs";
|
||||
public static final String ACTIVITY_DETAIL_ADDRESS = "https://static-web.ghzs.com/ghzs_activity_prod/common.html?from=ghzs";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
|
||||
@ -336,6 +336,13 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("gameIcon")
|
||||
public static void setGameIcon(View view, GameEntity gameEntity) {
|
||||
if (gameEntity != null && view instanceof GameIconView) {
|
||||
((GameIconView) view).displayGameIcon(gameEntity.getIcon(), gameEntity.getIconSubscript());
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("articleType")
|
||||
public static void setArticleType(TextView view, String articleType) {
|
||||
NewsUtils.setNewsType(view, articleType, 0, 0);
|
||||
@ -773,6 +780,34 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("setVideoDetailGameTags")
|
||||
public static void setVideoDetailGameTags(LinearLayout layout, GameEntity gameEntity) {
|
||||
try {
|
||||
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
|
||||
TestEntity test = gameEntity.getTest();
|
||||
if (test != null
|
||||
// 这个判断用于开测表列表
|
||||
&& !"type_tag".equals(test.getGameTag())) {
|
||||
TagStyleEntity typeTag = new TagStyleEntity();
|
||||
typeTag.setName(test.getType() != null ? test.getType() : "");
|
||||
typeTag.setBackground("FFF3E0");
|
||||
typeTag.setColor("FA8500");
|
||||
tagStyle.add(typeTag);
|
||||
|
||||
TagStyleEntity timeTag = new TagStyleEntity();
|
||||
timeTag.setName(GameViewUtils.getGameTestDate(test.getStart()));
|
||||
timeTag.setBackground("E0FFF9");
|
||||
timeTag.setColor("00A887");
|
||||
tagStyle.add(timeTag);
|
||||
} else {
|
||||
tagStyle = gameEntity.getTagStyle();
|
||||
}
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle, 4);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("isRefreshing")
|
||||
public static void isRefreshing(SwipeRefreshLayout layout, LoadStatus status) {
|
||||
if (status != LoadStatus.INIT_LOADING && status != LoadStatus.LIST_LOADING) {
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
package com.gh.common.dialog
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.SpanBuilder
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.view.CustomLinkMovementMethod
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogApplyModeratorBinding
|
||||
|
||||
|
||||
class ApplyModeratorDialogFragment : BaseDialogFragment() {
|
||||
private lateinit var binding: DialogApplyModeratorBinding
|
||||
private var groupNumber = ""
|
||||
private var groupKey = ""
|
||||
private var mCallBack: (() -> Unit)? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = DialogApplyModeratorBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val startText = "版主考核群:"
|
||||
val text = "$startText$groupNumber\n感谢你对论坛建设的支持\n请加入版主考核群并联系群主进行版主资格考核"
|
||||
binding.desTv.text = SpanBuilder(text)
|
||||
.click(startText.length, startText.length + groupNumber.length, R.color.theme_font,true) {
|
||||
DirectUtils.directToQqGroup(
|
||||
requireContext(),
|
||||
groupKey
|
||||
)
|
||||
}
|
||||
.build()
|
||||
binding.desTv.movementMethod = CustomLinkMovementMethod.getInstance()
|
||||
binding.confirmTv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
mCallBack?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val width = requireContext().resources.displayMetrics.widthPixels - 60F.dip2px()
|
||||
val height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
dialog?.window?.setLayout(width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(
|
||||
activity: AppCompatActivity,
|
||||
number: String,
|
||||
key: String,
|
||||
callBack: (() -> Unit)?
|
||||
) {
|
||||
var dialogFragment =
|
||||
activity.supportFragmentManager.findFragmentByTag(ApplyModeratorDialogFragment::class.java.simpleName) as? ApplyModeratorDialogFragment
|
||||
if (dialogFragment != null) {
|
||||
dialogFragment.groupNumber = number
|
||||
dialogFragment.groupKey = key
|
||||
dialogFragment.mCallBack = callBack
|
||||
val transaction: FragmentTransaction =
|
||||
activity.supportFragmentManager.beginTransaction()
|
||||
transaction.show(dialogFragment)
|
||||
transaction.commit()
|
||||
} else {
|
||||
dialogFragment = ApplyModeratorDialogFragment().apply {
|
||||
groupNumber = number
|
||||
groupKey = key
|
||||
mCallBack = callBack
|
||||
}
|
||||
dialogFragment.show(
|
||||
activity.supportFragmentManager,
|
||||
PrivacyDialogFragment::class.java.simpleName
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,13 +17,9 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager
|
||||
import com.gh.common.avoidcallback.Callback
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.GsonUtils
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.UserInfoEditActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.AuthDialogEntity
|
||||
import com.gh.gamecenter.entity.AuthDialogLevel
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
@ -56,7 +52,7 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi
|
||||
detailedDesTv.paint.isAntiAlias = true
|
||||
|
||||
detailedDesTv.setOnClickListener {
|
||||
context.startActivity(WebActivity.getIntentByUrl(context, authDialogEntity.link))
|
||||
DirectUtils.directToWebView(context, authDialogEntity.link)
|
||||
}
|
||||
|
||||
when (authDialogEntity.level) {
|
||||
|
||||
@ -26,7 +26,7 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.DeviceDialogEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.fragment.SettingsFragment.AUTO_INSTALL_SP_KEY
|
||||
import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.AUTO_INSTALL_SP_KEY
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
|
||||
@ -15,7 +15,7 @@ import com.gh.gamecenter.room.converter.*
|
||||
import com.gh.gamecenter.room.dao.*
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 8, exportSchema = false)
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 9, exportSchema = false)
|
||||
@TypeConverters(CountConverter::class,
|
||||
CommunityConverter::class,
|
||||
TimeConverter::class,
|
||||
@ -26,7 +26,9 @@ import com.halo.assistant.HaloApp
|
||||
ListStringConverter::class,
|
||||
CommunityVideoConverter::class,
|
||||
UserConverter::class,
|
||||
ImageInfoConverter::class)
|
||||
ImageInfoConverter::class,
|
||||
VideoInfoConverter::class,
|
||||
QuestionsConverter::class)
|
||||
|
||||
abstract class HistoryDatabase : RoomDatabase() {
|
||||
|
||||
@ -79,6 +81,26 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_8_9: Migration = object : Migration(8, 9) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE ArticleEntity add des TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add url TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add videoInfo TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add poster TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add length INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("Alter TABLE ArticleEntity add status TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add content TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE ArticleEntity add questions TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add des TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add url TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add videoInfo TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add poster TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add length INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("Alter TABLE AnswerEntity add status TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE AnswerEntity add content TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val instance by lazy {
|
||||
Room.databaseBuilder(HaloApp.getInstance().application, HistoryDatabase::class.java, "USER_TRACK_HISTORY_DATABASE")
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
@ -87,6 +109,7 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
.addMigrations(MIGRATION_5_6)
|
||||
.addMigrations(MIGRATION_6_7)
|
||||
.addMigrations(MIGRATION_7_8)
|
||||
.addMigrations(MIGRATION_8_9)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
32
app/src/main/java/com/gh/common/json/JsonBuilder.kt
Normal file
32
app/src/main/java/com/gh/common/json/JsonBuilder.kt
Normal file
@ -0,0 +1,32 @@
|
||||
package com.gh.common.json
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
//Source: https://stackoverflow.com/questions/41861449/kotlin-dsl-for-creating-json-objects-without-creating-garbage
|
||||
|
||||
fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
|
||||
return JsonObjectBuilder().json(build)
|
||||
}
|
||||
|
||||
class JsonObjectBuilder {
|
||||
private val deque: Deque<JSONObject> = ArrayDeque()
|
||||
|
||||
fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
|
||||
deque.push(JSONObject())
|
||||
this.build()
|
||||
return deque.pop()
|
||||
}
|
||||
|
||||
infix fun <T> String.to(value: T) {
|
||||
// wrap value into json block if it is a lambda
|
||||
val wrapped = when (value) {
|
||||
is Function0<*> -> json { value.invoke() }
|
||||
is Array<*> -> JSONArray().apply { value.forEach { put(it) } }
|
||||
else -> value
|
||||
}
|
||||
|
||||
deque.peek().put(this, wrapped)
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,7 @@ object LoghubHelper {
|
||||
// 每次发送前会把日志保存到本地的binlog文件,只有发送成功才会删除,保证日志上传At Least Once
|
||||
setPersistent(1)
|
||||
// 持久化的文件名,需要保证文件所在的文件夹已创建。配置多个客户端时,不应设置相同文件
|
||||
setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/log.dat")
|
||||
setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/${logStore}.dat")
|
||||
// 是否每次AddLog强制刷新,高可靠性场景建议打开
|
||||
setPersistentForceFlush(1)
|
||||
// 持久化文件滚动个数,建议设置成10。
|
||||
|
||||
@ -5,13 +5,14 @@ import android.database.ContentObserver
|
||||
import android.media.AudioManager
|
||||
import android.os.Handler
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class VolumeObserver(var context: Context, handler: Handler, var callback: MuteCallback? = null)
|
||||
: ContentObserver(handler) {
|
||||
class VolumeObserver(var callback: MuteCallback? = null)
|
||||
: ContentObserver(Handler()) {
|
||||
var previousVolume: Int = 0
|
||||
|
||||
init {
|
||||
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
val audio = HaloApp.getInstance().application.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
// 部分设备的 audioManager getStreamVolume 内部会触发空指针 :(
|
||||
tryCatchInRelease { previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC) }
|
||||
}
|
||||
@ -19,7 +20,7 @@ class VolumeObserver(var context: Context, handler: Handler, var callback: MuteC
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
super.onChange(selfChange)
|
||||
|
||||
val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
val audio = HaloApp.getInstance().application.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
var currentVolume = 0
|
||||
|
||||
tryCatchInRelease {
|
||||
|
||||
@ -7,6 +7,7 @@ import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.g00fy2.versioncompare.Version
|
||||
import com.gh.common.json.json
|
||||
import com.gh.common.util.*
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
@ -14,6 +15,7 @@ import com.gh.gamecenter.entity.SimulatorGameRecordEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.EmptyResponse
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -25,6 +27,7 @@ import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
||||
@ -84,6 +87,8 @@ object SimulatorGameManager {
|
||||
fun launchSimulatorGame(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
|
||||
val versionFromInstalledApp = PackageUtils.getVersionByPackage(gameEntity.simulator?.apk?.packageName)
|
||||
val shouldShowUpdate = Version(gameEntity.simulator?.apk?.version).isHigherThan(versionFromInstalledApp)
|
||||
|
||||
updateSimulatorConfigFile(gameId = gameEntity.id)
|
||||
if (shouldShowUpdate) {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().recentActiveActivity, gameEntity.simulator,
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
|
||||
@ -159,7 +164,7 @@ object SimulatorGameManager {
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun recordDownloadSimulatorGames(gameId: String, type: String) {
|
||||
fun recordDownloadSimulatorGame(gameId: String, type: String) {
|
||||
val requestMap = hashMapOf<String, Any>()
|
||||
requestMap["game_id"] = gameId
|
||||
requestMap["package"] = "-"
|
||||
@ -174,6 +179,31 @@ object SimulatorGameManager {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量记录设备下载的模拟器游戏
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun recordDownloadSimulatorGames() {
|
||||
val gameArray = JSONArray()
|
||||
val allGameList = AppDatabase.getInstance(HaloApp.getInstance()).simulatorGameDao().getAllSimulatorGame()
|
||||
for (game in allGameList) {
|
||||
if (!game.isDeleted) {
|
||||
gameArray.put(json {
|
||||
"game_id" to game.id
|
||||
"package" to "-"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (gameArray.length() == 0) return
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
.putDownloadSimulatorGames(HaloApp.getInstance().gid, gameArray.toRequestBody())
|
||||
.compose(singleToMain())
|
||||
.subscribe(EmptyResponse())
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun refreshSimulatorGame(gameId: String, type: String) {
|
||||
val simulatorGameDao = AppDatabase.getInstance(HaloApp.getInstance()).simulatorGameDao()
|
||||
@ -278,4 +308,22 @@ object SimulatorGameManager {
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(EmptyResponse())
|
||||
}
|
||||
|
||||
private fun updateSimulatorConfigFile(gameId: String) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api
|
||||
.getGameDigest(gameId)
|
||||
.map(ApkActiveUtils.filterMapper)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<GameEntity>() {
|
||||
override fun onResponse(game: GameEntity?) {
|
||||
game?.let {
|
||||
if (!TextUtils.isEmpty(game.simulatorGameConfig)) {
|
||||
val configFilePath = getPathByType(game.simulatorType + "/cheat/" + game.getApk().firstOrNull()?.packageName + ".ini")
|
||||
FileUtils.downloadAndUpdateFile(game.simulatorGameConfig, configFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -16,8 +16,12 @@ object SyncFieldConstants {
|
||||
const val ANSWER_COMMENT_COUNT = "ANSWER_COMMENT_COUNT"
|
||||
const val ARTICLE_COMMENT_COUNT = "ARTICLE_COMMENT_COUNT"
|
||||
const val ARTICLE_COMMENT_REPLY_COUNT = "ARTICLE_COMMENT_REPLY_COUNT"
|
||||
const val ANSWER_COMMENT_REPLY_COUNT = "ANSWER_COMMENT_REPLY_COUNT"
|
||||
|
||||
// 回答数量
|
||||
const val ANSWER_COUNT = "ANSWER_COUNT"
|
||||
|
||||
// 是否关注
|
||||
const val IS_FOLLOWER = "IS_FOLLOWER"
|
||||
|
||||
}
|
||||
@ -4,7 +4,7 @@ import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
|
||||
// TODO SplashActivity 没有回调 onStart 和 onStop
|
||||
// FYI 快速启动并且不设置 contentView 马上结束的 SplashActivity 没有 onStart 和 onStop 回调
|
||||
class ActivityLifecycleWatcher(private val mTrack: ITrack) : Application.ActivityLifecycleCallbacks {
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
|
||||
@ -8,7 +8,7 @@ import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
/**
|
||||
* 应用声明周期观察者
|
||||
* 应用生命周期观察者
|
||||
*/
|
||||
class AppLifecycleWatcher(private val mTrack: ITrack) : DefaultLifecycleObserver {
|
||||
|
||||
|
||||
@ -5,6 +5,10 @@ import android.app.Application
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* launch_id 当前启动的唯一 id (每次应用冷启动或被内存回收时变更)
|
||||
* session_id 当前会话的唯一 id (应用切换至后台超30秒时变更)
|
||||
*/
|
||||
object Tracker : ITrack {
|
||||
|
||||
private var mSessionId: String = ""
|
||||
@ -33,8 +37,6 @@ object Tracker : ITrack {
|
||||
val businessId = if (activity is IBusiness) activity.getBusinessId() else null
|
||||
|
||||
TrackerLogger.logActivityStart(
|
||||
mLaunchId,
|
||||
mSessionId,
|
||||
System.identityHashCode(activity).toString(),
|
||||
activity::class.java.simpleName,
|
||||
businessId)
|
||||
@ -44,23 +46,21 @@ object Tracker : ITrack {
|
||||
val businessId = if (activity is IBusiness) activity.getBusinessId() else null
|
||||
|
||||
TrackerLogger.logActivityStop(
|
||||
mLaunchId,
|
||||
mSessionId,
|
||||
System.identityHashCode(activity).toString(),
|
||||
activity::class.java.simpleName,
|
||||
businessId)
|
||||
}
|
||||
|
||||
override fun onAppStarted() {
|
||||
TrackerLogger.logAppStart(mLaunchId, mSessionId)
|
||||
TrackerLogger.logAppStart()
|
||||
}
|
||||
|
||||
override fun onAppVisible(interval: Long) {
|
||||
TrackerLogger.logAppVisible(mLaunchId, mSessionId, interval)
|
||||
TrackerLogger.logAppVisible(interval)
|
||||
}
|
||||
|
||||
override fun onAppStopped() {
|
||||
TrackerLogger.logAppStop(mLaunchId, mSessionId)
|
||||
TrackerLogger.logAppStop()
|
||||
}
|
||||
|
||||
override fun onSessionChanged(sessionId: String) {
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
package com.gh.common.tracker
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.meta.MetaUtil.getBase64EncodedAndroidId
|
||||
import com.gh.common.exposure.meta.MetaUtil.getBase64EncodedIMEI
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
import com.gh.gamecenter.R
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
@ -13,16 +16,16 @@ object TrackerLogger {
|
||||
|
||||
private const val LOG_STORE = "launch_activity"
|
||||
|
||||
fun logAppStart(launchId: String, sessionId: String) {
|
||||
logAppVisible(launchId, sessionId, 0)
|
||||
fun logAppStart() {
|
||||
logAppVisible(0)
|
||||
}
|
||||
|
||||
fun logAppVisible(launchId: String, sessionId: String, interval: Long) {
|
||||
fun logAppVisible(interval: Long) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
payloadObject.put("interval", interval)
|
||||
|
||||
jsonObject.put("event", "app_visible")
|
||||
@ -32,12 +35,12 @@ object TrackerLogger {
|
||||
uploadToLoghub(jsonObject, true)
|
||||
}
|
||||
|
||||
fun logAppStop(launchId: String, sessionId: String) {
|
||||
fun logAppStop() {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
|
||||
jsonObject.put("event", "app_invisible")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
@ -46,16 +49,14 @@ object TrackerLogger {
|
||||
uploadToLoghub(jsonObject, true)
|
||||
}
|
||||
|
||||
fun logActivityStart(launchId: String,
|
||||
sessionId: String,
|
||||
activityId: String,
|
||||
fun logActivityStart(activityId: String,
|
||||
activityName: String,
|
||||
activityBusinessId: Pair<String, String>? = null) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
payloadObject.put("activity_id", activityId)
|
||||
payloadObject.put("activity_name", activityName)
|
||||
if (activityBusinessId != null) {
|
||||
@ -72,16 +73,14 @@ object TrackerLogger {
|
||||
uploadToLoghub(jsonObject, false)
|
||||
}
|
||||
|
||||
fun logActivityStop(launchId: String,
|
||||
sessionId: String,
|
||||
activityId: String,
|
||||
fun logActivityStop(activityId: String,
|
||||
activityName: String,
|
||||
activityBusinessId: Pair<String, String>? = null) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
payloadObject.put("activity_id", activityId)
|
||||
payloadObject.put("activity_name", activityName)
|
||||
if (activityBusinessId != null) {
|
||||
@ -99,15 +98,13 @@ object TrackerLogger {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logHomeTabSelected(launchId: String,
|
||||
sessionId: String,
|
||||
tabPosition: Int,
|
||||
fun logHomeTabSelected(tabPosition: Int,
|
||||
tabContent: String) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
payloadObject.put("tab_position", tabPosition)
|
||||
payloadObject.put("tab_content", tabContent)
|
||||
|
||||
@ -119,12 +116,25 @@ object TrackerLogger {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logAppLaunch(launchId: String, sessionId: String) {
|
||||
fun logAppLaunch(context: Context) {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
val signatureHash = PackageUtils.getApkSignatureByPackageName(context, context.packageName)
|
||||
val sideLoadInfo = PackageUtils.getSideLoadedInfo()
|
||||
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
payloadObject.put("signature", signatureHash)
|
||||
payloadObject.put("package_name", context.packageName)
|
||||
payloadObject.put("app_name", context.getString(R.string.app_name))
|
||||
|
||||
sideLoadInfo?.let {
|
||||
payloadObject.put("is_side_loaded", sideLoadInfo["is_side_loaded"])
|
||||
sideLoadInfo["installer_store"]?.let {
|
||||
payloadObject.put("installer_store", it)
|
||||
}
|
||||
}
|
||||
|
||||
jsonObject.put("event", "app_launch")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
@ -134,12 +144,12 @@ object TrackerLogger {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logAppLaunchSuccessful(launchId: String, sessionId: String) {
|
||||
fun logAppLaunchSuccessful() {
|
||||
val jsonObject = JSONObject()
|
||||
val payloadObject = JSONObject()
|
||||
tryCatchInRelease {
|
||||
payloadObject.put("launch_id", launchId)
|
||||
payloadObject.put("session_id", sessionId)
|
||||
payloadObject.put("launch_id", Tracker.launchId)
|
||||
payloadObject.put("session_id", Tracker.sessionId)
|
||||
|
||||
jsonObject.put("event", "app_launch_successful")
|
||||
jsonObject.put("payload", payloadObject)
|
||||
|
||||
134
app/src/main/java/com/gh/common/util/BbsReportHelper.kt
Normal file
134
app/src/main/java/com/gh/common/util/BbsReportHelper.kt
Normal file
@ -0,0 +1,134 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.json.json
|
||||
import com.gh.common.util.ToastUtils.showToast
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.SuggestionActivity
|
||||
import com.gh.gamecenter.entity.SettingsEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
|
||||
object BbsReportHelper {
|
||||
|
||||
fun showReportDialog(contentId: String) {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance())
|
||||
val suggestion: SettingsEntity.Suggestion? = sp.getString(SuggestionActivity.SUGGESTION_HINT_TYPE, null)?.toObject()
|
||||
val reportList = suggestion?.report ?: return
|
||||
|
||||
CurrentActivityHolder.getCurrentActivity()?.apply {
|
||||
if (this.isFinishing) return@apply
|
||||
|
||||
val dialog = Dialog(this)
|
||||
|
||||
val view = LayoutInflater.from(this).inflate(R.layout.dialog_video_complaint, null, false)
|
||||
val complaintContainer = view.findViewById<LinearLayout>(R.id.complaintContainer)
|
||||
val otherComplaintContainer: ConstraintLayout = view.findViewById(R.id.otherComplaintContainer)
|
||||
val complaintCommentEt = view.findViewById<EditText>(R.id.complaintCommentEt)
|
||||
val backTv = view.findViewById<TextView>(R.id.backTv)
|
||||
val commitTv = view.findViewById<TextView>(R.id.commitTv)
|
||||
val finalContext: Context = this
|
||||
//添加透明阴影,实现类似 clipPadding=false 效果
|
||||
complaintCommentEt.setShadowLayer(complaintCommentEt.extendedPaddingBottom.toFloat(), 0f, 0f, Color.TRANSPARENT)
|
||||
|
||||
complaintCommentEt.setTextChangedListener { s: CharSequence, _: Int?, _: Int?, _: Int? ->
|
||||
commitTv.setTextColor(ContextCompat.getColor(finalContext, if (s.toString().trim { it <= ' ' }.isEmpty()) R.color.text_999999 else R.color.theme_font))
|
||||
}
|
||||
|
||||
for (option in reportList) {
|
||||
val reportTv = TextView(this)
|
||||
reportTv.text = option
|
||||
reportTv.textSize = 16F
|
||||
reportTv.setTextColor(R.color.title.toColor())
|
||||
reportTv.setBackgroundResource(R.drawable.textview_white_style)
|
||||
reportTv.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
reportTv.setPadding(20F.dip2px(), 17F.dip2px(), 20F.dip2px(), 17F.dip2px())
|
||||
if (option.contains("其它")) {
|
||||
val drawable = R.drawable.ic_complaint_arrow_right.toDrawable()
|
||||
drawable!!.setBounds(0, 0, 6F.dip2px(), 10F.dip2px())
|
||||
reportTv.setCompoundDrawables(null, null, drawable, null)
|
||||
}
|
||||
complaintContainer.addView(reportTv)
|
||||
reportTv.setOnClickListener {
|
||||
if (option.contains("其它")) {
|
||||
complaintContainer.visibility = View.GONE
|
||||
otherComplaintContainer.visibility = View.VISIBLE
|
||||
complaintCommentEt.requestFocus()
|
||||
Util_System_Keyboard.showSoftKeyboard(finalContext, complaintCommentEt)
|
||||
} else {
|
||||
postReport(contentId, json {
|
||||
"reason" to reportTv.text.toString()
|
||||
})
|
||||
dialog.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backTv.setOnClickListener {
|
||||
Util_System_Keyboard.hideSoftKeyboard(finalContext, complaintCommentEt)
|
||||
complaintContainer.visibility = View.VISIBLE
|
||||
otherComplaintContainer.visibility = View.GONE
|
||||
}
|
||||
commitTv.setOnClickListener {
|
||||
if (complaintCommentEt.text.toString().isEmpty()) {
|
||||
showToast("请先输入说明~")
|
||||
return@setOnClickListener
|
||||
}
|
||||
postReport(contentId, json {
|
||||
"reason" to "其它"
|
||||
"description" to complaintCommentEt.text.toString()
|
||||
})
|
||||
|
||||
dialog.cancel()
|
||||
}
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog.setContentView(view)
|
||||
dialog.show()
|
||||
val window = dialog.window
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
val params = window.attributes
|
||||
params.width = resources.displayMetrics.widthPixels - 40F.dip2px()
|
||||
window.attributes = params
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun postReport(contentId: String, reportContent: JSONObject) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance())
|
||||
.api
|
||||
.postBbsReport(contentId, reportContent.toRequestBody())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
Utils.toast(HaloApp.getInstance(), "举报成功")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
128
app/src/main/java/com/gh/common/util/BbsStayTimeHelper.kt
Normal file
128
app/src/main/java/com/gh/common/util/BbsStayTimeHelper.kt
Normal file
@ -0,0 +1,128 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.base.GHThreadFactory
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object BbsStayTimeHelper {
|
||||
|
||||
private var mStayTimeCount = 0
|
||||
private var mIsStayTimeCountEnabled = false // 论坛停留时间统计是否开启
|
||||
private var mStayTimeTimeout = 30
|
||||
private var mIsStayTimeCountValid = false // 论坛停留时间统计是否有效
|
||||
|
||||
const val IS_BBS_CONTENT_VISIBLE = "is_bbs_content_visible"
|
||||
|
||||
private val mThreadService: ExecutorService by lazy {
|
||||
Executors.newSingleThreadExecutor(GHThreadFactory("STAY_TIME_THREAD"))
|
||||
}
|
||||
|
||||
private val mActivityLifecycleCallbacks by lazy {
|
||||
object : Application.ActivityLifecycleCallbacks {
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
|
||||
override fun onActivityStopped(activity: Activity) {}
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
|
||||
override fun onActivityDestroyed(activity: Activity) {}
|
||||
override fun onActivityStarted(activity: Activity) {}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
if (isTopActivityBbsRelated(activity) && mIsStayTimeCountEnabled) {
|
||||
resumeTimeCount()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
if (isTopActivityBbsRelated(activity) && mIsStayTimeCountEnabled) {
|
||||
pauseTimeCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun enableStayTimeCount(timeout: Int) {
|
||||
mIsStayTimeCountEnabled = true
|
||||
mStayTimeTimeout = timeout
|
||||
|
||||
resumeTimeCount()
|
||||
|
||||
HaloApp.getInstance().registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks)
|
||||
}
|
||||
|
||||
fun disableStayTimeCount() {
|
||||
mIsStayTimeCountEnabled = false
|
||||
mStayTimeCount = 0
|
||||
|
||||
HaloApp.getInstance().unregisterActivityLifecycleCallbacks(mActivityLifecycleCallbacks)
|
||||
}
|
||||
|
||||
fun resumeTimeCount() {
|
||||
if (!mIsStayTimeCountEnabled) return
|
||||
|
||||
mIsStayTimeCountValid = true
|
||||
|
||||
mThreadService.execute {
|
||||
while (mIsStayTimeCountEnabled && mIsStayTimeCountValid) {
|
||||
val topActivity = CurrentActivityHolder.getCurrentActivity() ?: continue
|
||||
if (isTopActivityBbsRelated(topActivity)) {
|
||||
tryWithDefaultCatch {
|
||||
mStayTimeCount++
|
||||
if (mStayTimeCount >= mStayTimeTimeout) {
|
||||
postExploreFinish()
|
||||
}
|
||||
}
|
||||
}
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pauseTimeCount() {
|
||||
if (!mIsStayTimeCountEnabled) return
|
||||
|
||||
mIsStayTimeCountValid = false
|
||||
}
|
||||
|
||||
private fun isTopActivityBbsRelated(activity: Activity): Boolean {
|
||||
return (activity is MainActivity && activity.intent.extras?.getBoolean(IS_BBS_CONTENT_VISIBLE) == true)
|
||||
|| activity is ForumDetailActivity
|
||||
|| activity is ArticleDetailActivity
|
||||
|| activity is ForumVideoDetailActivity
|
||||
|| activity is CommentActivity
|
||||
|| activity is NewQuestionDetailActivity
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun postExploreFinish() {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance())
|
||||
.api
|
||||
.postExplorerFinish()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
if (!isPublishEnv()) {
|
||||
ToastUtils.toast("完成了论坛停留任务(仅测试环境有这个 toast 不要慌)")
|
||||
}
|
||||
disableStayTimeCount()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ import android.graphics.Matrix;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.os.Build;
|
||||
|
||||
import com.halo.assistant.HaloApp;
|
||||
@ -307,6 +308,218 @@ public class BitmapUtils {
|
||||
return outputBitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模糊Bitmap
|
||||
*
|
||||
* @param sentBitmap
|
||||
* @param radius
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap doBlur(Bitmap sentBitmap, int radius) {
|
||||
Bitmap.Config config = sentBitmap.getConfig();
|
||||
if (config == null) {
|
||||
config = Bitmap.Config.ARGB_8888;
|
||||
}
|
||||
Bitmap bitmap = sentBitmap.copy(config, true);
|
||||
|
||||
if (radius < 1) {
|
||||
return (null);
|
||||
}
|
||||
|
||||
int w = bitmap.getWidth();
|
||||
int h = bitmap.getHeight();
|
||||
|
||||
int[] pix = new int[w * h];
|
||||
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
|
||||
|
||||
int wm = w - 1;
|
||||
int hm = h - 1;
|
||||
int wh = w * h;
|
||||
int div = radius + radius + 1;
|
||||
|
||||
int r[] = new int[wh];
|
||||
int g[] = new int[wh];
|
||||
int b[] = new int[wh];
|
||||
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
|
||||
int vmin[] = new int[Math.max(w, h)];
|
||||
|
||||
int divsum = (div + 1) >> 1;
|
||||
divsum *= divsum;
|
||||
int dv[] = new int[256 * divsum];
|
||||
for (i = 0; i < 256 * divsum; i++) {
|
||||
dv[i] = (i / divsum);
|
||||
}
|
||||
|
||||
yw = yi = 0;
|
||||
|
||||
int[][] stack = new int[div][3];
|
||||
int stackpointer;
|
||||
int stackstart;
|
||||
int[] sir;
|
||||
int rbs;
|
||||
int r1 = radius + 1;
|
||||
int routsum, goutsum, boutsum;
|
||||
int rinsum, ginsum, binsum;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
for (i = -radius; i <= radius; i++) {
|
||||
p = pix[yi + Math.min(wm, Math.max(i, 0))];
|
||||
sir = stack[i + radius];
|
||||
sir[0] = (p & 0xff0000) >> 16;
|
||||
sir[1] = (p & 0x00ff00) >> 8;
|
||||
sir[2] = (p & 0x0000ff);
|
||||
rbs = r1 - Math.abs(i);
|
||||
rsum += sir[0] * rbs;
|
||||
gsum += sir[1] * rbs;
|
||||
bsum += sir[2] * rbs;
|
||||
if (i > 0) {
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
} else {
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
}
|
||||
}
|
||||
stackpointer = radius;
|
||||
|
||||
for (x = 0; x < w; x++) {
|
||||
|
||||
r[yi] = dv[rsum];
|
||||
g[yi] = dv[gsum];
|
||||
b[yi] = dv[bsum];
|
||||
|
||||
rsum -= routsum;
|
||||
gsum -= goutsum;
|
||||
bsum -= boutsum;
|
||||
|
||||
stackstart = stackpointer - radius + div;
|
||||
sir = stack[stackstart % div];
|
||||
|
||||
routsum -= sir[0];
|
||||
goutsum -= sir[1];
|
||||
boutsum -= sir[2];
|
||||
|
||||
if (y == 0) {
|
||||
vmin[x] = Math.min(x + radius + 1, wm);
|
||||
}
|
||||
p = pix[yw + vmin[x]];
|
||||
|
||||
sir[0] = (p & 0xff0000) >> 16;
|
||||
sir[1] = (p & 0x00ff00) >> 8;
|
||||
sir[2] = (p & 0x0000ff);
|
||||
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
|
||||
rsum += rinsum;
|
||||
gsum += ginsum;
|
||||
bsum += binsum;
|
||||
|
||||
stackpointer = (stackpointer + 1) % div;
|
||||
sir = stack[(stackpointer) % div];
|
||||
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
|
||||
rinsum -= sir[0];
|
||||
ginsum -= sir[1];
|
||||
binsum -= sir[2];
|
||||
|
||||
yi++;
|
||||
}
|
||||
yw += w;
|
||||
}
|
||||
for (x = 0; x < w; x++) {
|
||||
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
yp = -radius * w;
|
||||
for (i = -radius; i <= radius; i++) {
|
||||
yi = Math.max(0, yp) + x;
|
||||
|
||||
sir = stack[i + radius];
|
||||
|
||||
sir[0] = r[yi];
|
||||
sir[1] = g[yi];
|
||||
sir[2] = b[yi];
|
||||
|
||||
rbs = r1 - Math.abs(i);
|
||||
|
||||
rsum += r[yi] * rbs;
|
||||
gsum += g[yi] * rbs;
|
||||
bsum += b[yi] * rbs;
|
||||
|
||||
if (i > 0) {
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
} else {
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
}
|
||||
|
||||
if (i < hm) {
|
||||
yp += w;
|
||||
}
|
||||
}
|
||||
yi = x;
|
||||
stackpointer = radius;
|
||||
for (y = 0; y < h; y++) {
|
||||
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
|
||||
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
|
||||
|
||||
rsum -= routsum;
|
||||
gsum -= goutsum;
|
||||
bsum -= boutsum;
|
||||
|
||||
stackstart = stackpointer - radius + div;
|
||||
sir = stack[stackstart % div];
|
||||
|
||||
routsum -= sir[0];
|
||||
goutsum -= sir[1];
|
||||
boutsum -= sir[2];
|
||||
|
||||
if (x == 0) {
|
||||
vmin[y] = Math.min(y + r1, hm) * w;
|
||||
}
|
||||
p = x + vmin[y];
|
||||
|
||||
sir[0] = r[p];
|
||||
sir[1] = g[p];
|
||||
sir[2] = b[p];
|
||||
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
|
||||
rsum += rinsum;
|
||||
gsum += ginsum;
|
||||
bsum += binsum;
|
||||
|
||||
stackpointer = (stackpointer + 1) % div;
|
||||
sir = stack[stackpointer];
|
||||
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
|
||||
rinsum -= sir[0];
|
||||
ginsum -= sir[1];
|
||||
binsum -= sir[2];
|
||||
|
||||
yi += w;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
|
||||
|
||||
return (bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片
|
||||
*
|
||||
@ -354,4 +567,25 @@ public class BitmapUtils {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取视频缩略图(比较耗时,建议在子线程中调用)
|
||||
public static Bitmap getVideoThumbnail(String filePath) {
|
||||
Bitmap bitmap = null;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
try {
|
||||
retriever.setDataSource(filePath);
|
||||
bitmap = retriever.getFrameAtTime();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
retriever.release();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.base.CurrentActivityHolder;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
@ -16,14 +18,21 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
public class CheckLoginUtils {
|
||||
|
||||
public static void checkLogin(final Context context, String entrance, OnLoginListener listener) {
|
||||
public static void checkLogin(Context context, String entrance, OnLoginListener listener) {
|
||||
if (!isLogin()) {
|
||||
if (listener != null) Utils.toast(context, "需要登录");
|
||||
LogUtils.login("dialog", null, entrance);
|
||||
LogUtils.login("activity", null, entrance);
|
||||
|
||||
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
|
||||
QuickLoginHelper.startLogin(context, entrance);
|
||||
// 需要确保传入的 context 不为 application
|
||||
if (!(context instanceof Activity)) {
|
||||
context = CurrentActivityHolder.getCurrentActivity();
|
||||
}
|
||||
|
||||
if (context != null) {
|
||||
QuickLoginHelper.startLogin(context, entrance);
|
||||
}
|
||||
} else {
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
|
||||
@ -21,97 +21,140 @@ import com.lightgame.utils.Utils
|
||||
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 {
|
||||
|
||||
@JvmStatic
|
||||
fun showCommunityArticleCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
articleId: String,
|
||||
communityId: String,
|
||||
isShowTop: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
articleId = articleId,
|
||||
communityId = communityId,
|
||||
isShowTop = isShowTop,
|
||||
ignoreModerator = ignoreModerator,
|
||||
listener = listener)
|
||||
fun showCommunityArticleCommentOptions(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
articleId: String,
|
||||
communityId: String,
|
||||
isShowTop: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?
|
||||
) {
|
||||
showCommentOptions(
|
||||
view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
articleId = articleId,
|
||||
communityId = communityId,
|
||||
isShowTop = isShowTop,
|
||||
ignoreModerator = ignoreModerator,
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showAnswerCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
answerId: String,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
answerId = answerId,
|
||||
listener = listener)
|
||||
fun showAnswerCommentOptions(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
answerId: String,
|
||||
listener: OnCommentOptionClickListener?
|
||||
) {
|
||||
showCommentOptions(
|
||||
view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
answerId = answerId,
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showVideoCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
videoId: String,
|
||||
isVideoAuthor: Boolean,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
videoId = videoId,
|
||||
isVideoAuthor = isVideoAuthor,
|
||||
listener = listener)
|
||||
fun showVideoCommentOptions(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
videoId: String,
|
||||
isVideoAuthor: Boolean,
|
||||
isShowTop: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?
|
||||
) {
|
||||
showCommentOptions(
|
||||
view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
videoId = videoId,
|
||||
isVideoAuthor = isVideoAuthor,
|
||||
isShowTop = isShowTop,
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
private fun showCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
articleId: String? = null,
|
||||
communityId: String? = null,
|
||||
answerId: String? = null,
|
||||
videoId: String? = null,
|
||||
isShowTop: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
isVideoAuthor: Boolean = false,
|
||||
listener: OnCommentOptionClickListener? = null) {
|
||||
fun showQuestionCommentOption(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
questionId: String,
|
||||
isShowTop: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?
|
||||
) {
|
||||
showCommentOptions(
|
||||
view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = false,
|
||||
questionId = questionId,
|
||||
isShowTop = isShowTop,
|
||||
ignoreModerator = true,
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
private fun showCommentOptions(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
articleId: String? = null,
|
||||
communityId: String? = null,
|
||||
answerId: String? = null,
|
||||
questionId: String? = null,
|
||||
videoId: String? = null,
|
||||
isShowTop: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
isVideoAuthor: Boolean = false,
|
||||
listener: OnCommentOptionClickListener? = null
|
||||
) {
|
||||
val context = view.context
|
||||
val dialogOptions = ArrayList<String>()
|
||||
if (isShowTop && articleId != null && commentEntity.me?.isArticleOrAnswerAuthor == true) {
|
||||
|
||||
if (isShowTop && (articleId != null || questionId != null) && commentEntity.me?.isContentAuthor == true) {
|
||||
dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶")
|
||||
}
|
||||
if (questionId != null && commentEntity.me?.isContentAuthor == true) {
|
||||
if (commentEntity.accept) {
|
||||
dialogOptions.add("取消采纳")
|
||||
} else {
|
||||
dialogOptions.add("采纳")
|
||||
}
|
||||
}
|
||||
|
||||
dialogOptions.add("复制")
|
||||
if (commentEntity.user.id != UserManager.getInstance().userId) {
|
||||
dialogOptions.add("投诉")
|
||||
}
|
||||
if (isVideoAuthor || (videoId != null && commentEntity.user.id == UserManager.getInstance().userId)) {
|
||||
dialogOptions.add("删除评论")
|
||||
} else if (articleId != null && (commentEntity.user.id == UserManager.getInstance().userId ||
|
||||
commentEntity.me?.isModerator == true || commentEntity.me?.isArticleOrAnswerAuthor == true)) {
|
||||
if (questionId != null && commentEntity.me?.isModerator == true && !commentEntity.choiceness) {
|
||||
dialogOptions.add("加精选")
|
||||
}
|
||||
if (commentEntity.user.id == UserManager.getInstance().userId || commentEntity.me?.isModerator == true || commentEntity.me?.isContentAuthor == true) {
|
||||
dialogOptions.add("删除评论")
|
||||
}
|
||||
|
||||
commentEntity.me?.let {
|
||||
/*commentEntity.me?.let {
|
||||
if (ignoreModerator) return@let
|
||||
|
||||
if (it.isModerator || (it.moderatorPermissions.hideAnswerComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.topAnswerComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST)) {
|
||||
|| it.moderatorPermissions.topAnswerComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST)
|
||||
) {
|
||||
dialogOptions.add("管理")
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (commentEntity.parentUser != null && showConversation) {
|
||||
dialogOptions.add("查看对话")
|
||||
@ -119,9 +162,11 @@ object CommentHelper {
|
||||
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val layout = inflater.inflate(R.layout.layout_popup_container, null)
|
||||
val popupWindow = BugFixedPopupWindow(layout,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
val popupWindow = BugFixedPopupWindow(
|
||||
layout,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val container = layout.findViewById<LinearLayout>(R.id.container)
|
||||
for (text in dialogOptions) {
|
||||
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
|
||||
@ -134,34 +179,73 @@ object CommentHelper {
|
||||
popupWindow.dismiss()
|
||||
listener?.onCommentOptionClick(commentEntity, text)
|
||||
when (text) {
|
||||
"管理" -> showControlDialog(context, answerId, articleId, communityId, commentEntity, commentEntity.me!!)
|
||||
"管理" -> showControlDialog(
|
||||
context,
|
||||
answerId,
|
||||
articleId,
|
||||
communityId,
|
||||
commentEntity,
|
||||
commentEntity.me!!
|
||||
)
|
||||
|
||||
"复制" -> copyText(commentEntity.content, context)
|
||||
|
||||
"投诉" -> {
|
||||
context.ifLogin("回答详情-评论-投诉") {
|
||||
showReportTypeDialog(context, !videoId.isNullOrEmpty()) { reportType ->
|
||||
showReportTypeDialog(context) { reportType ->
|
||||
val commentListener =
|
||||
object : PostCommentUtils.PostCommentListener {
|
||||
override fun postSuccess(response: JSONObject?) {
|
||||
Utils.toast(context, "感谢您的投诉")
|
||||
}
|
||||
|
||||
val commentListener = 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}")
|
||||
override fun postFailed(error: Throwable?) {
|
||||
if (error == null) {
|
||||
Utils.toast(context, "投诉失败,请稍后重试")
|
||||
} else {
|
||||
Utils.toast(context, "投诉失败,${error.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (answerId != null) {
|
||||
PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType, commentListener)
|
||||
} else if (articleId != null) {
|
||||
PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType, commentListener)
|
||||
} else {
|
||||
PostCommentUtils.reportVideoComment(context, videoId, commentEntity.id, reportType, commentListener)
|
||||
when {
|
||||
answerId != null -> {
|
||||
PostCommentUtils.postAnswerReportData(
|
||||
context,
|
||||
commentEntity.id,
|
||||
answerId,
|
||||
reportType,
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
articleId != null -> {
|
||||
PostCommentUtils.reportCommunityArticleComment(
|
||||
context,
|
||||
communityId,
|
||||
articleId,
|
||||
commentEntity.id,
|
||||
reportType,
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
questionId != null -> {
|
||||
PostCommentUtils.reportQuestionComment(
|
||||
context,
|
||||
questionId,
|
||||
commentEntity.id,
|
||||
reportType,
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
PostCommentUtils.reportVideoComment(
|
||||
context,
|
||||
videoId,
|
||||
commentEntity.id,
|
||||
reportType,
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,14 +253,37 @@ object CommentHelper {
|
||||
|
||||
"查看对话" -> {
|
||||
if (answerId != null) {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getAnswerCommentIntent(context, commentEntity.id, answerId, null))
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
.getAnswerCommentIntent(
|
||||
context,
|
||||
commentEntity.id,
|
||||
answerId,
|
||||
null
|
||||
)
|
||||
)
|
||||
} else if (articleId != null) {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null))
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
.getCommunityArticleCommentIntent(
|
||||
context,
|
||||
articleId,
|
||||
commentEntity.id,
|
||||
communityId,
|
||||
null
|
||||
)
|
||||
)
|
||||
} else {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getVideoCommentIntent(context, commentEntity.id, videoId, isVideoAuthor, null))
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
.getVideoCommentIntent(
|
||||
context,
|
||||
commentEntity.id,
|
||||
videoId,
|
||||
isVideoAuthor,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,12 +295,14 @@ object CommentHelper {
|
||||
popupWindow.showAutoOrientation(view)
|
||||
}
|
||||
|
||||
private fun showControlDialog(context: Context,
|
||||
answerId: String? = null,
|
||||
articleId: String? = null,
|
||||
communityId: String? = null,
|
||||
comment: CommentEntity,
|
||||
me: MeEntity) {
|
||||
private fun showControlDialog(
|
||||
context: Context,
|
||||
answerId: String? = null,
|
||||
articleId: String? = null,
|
||||
communityId: String? = null,
|
||||
comment: CommentEntity,
|
||||
me: MeEntity
|
||||
) {
|
||||
val dialogOptions = arrayListOf<String>()
|
||||
val highlight = "置顶评论"
|
||||
val hide = "隐藏评论"
|
||||
@ -202,19 +311,23 @@ object CommentHelper {
|
||||
var canHideCommentDirectly = false
|
||||
|
||||
if (me.isModerator || me.moderatorPermissions.topAnswerComment > Permissions.GUEST
|
||||
|| me.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST) {
|
||||
|| me.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST
|
||||
) {
|
||||
dialogOptions.add(highlight)
|
||||
if (me.moderatorPermissions.topAnswerComment > Permissions.REPORTER
|
||||
|| me.moderatorPermissions.topCommunityArticleComment > Permissions.REPORTER) {
|
||||
|| me.moderatorPermissions.topCommunityArticleComment > Permissions.REPORTER
|
||||
) {
|
||||
canHighlightCommentDirectly = true
|
||||
}
|
||||
}
|
||||
|
||||
if (me.isModerator || me.moderatorPermissions.hideAnswerComment > Permissions.GUEST
|
||||
|| me.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST) {
|
||||
|| me.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST
|
||||
) {
|
||||
dialogOptions.add(hide)
|
||||
if (me.moderatorPermissions.hideAnswerComment > Permissions.REPORTER
|
||||
|| me.moderatorPermissions.hideCommunityArticleComment > Permissions.REPORTER) {
|
||||
|| me.moderatorPermissions.hideCommunityArticleComment > Permissions.REPORTER
|
||||
) {
|
||||
canHideCommentDirectly = true
|
||||
}
|
||||
}
|
||||
@ -275,7 +388,10 @@ object CommentHelper {
|
||||
val errorJson = JSONObject(string)
|
||||
val errorCode = errorJson.getInt("code")
|
||||
if (errorCode == 403059) {
|
||||
Utils.toast(HaloApp.getInstance().application, "权限错误,请刷新后重试")
|
||||
Utils.toast(
|
||||
HaloApp.getInstance().application,
|
||||
"权限错误,请刷新后重试"
|
||||
)
|
||||
return
|
||||
} else {
|
||||
Utils.toast(HaloApp.getInstance().application, e.message())
|
||||
@ -286,23 +402,31 @@ object CommentHelper {
|
||||
}
|
||||
|
||||
if (answerId != null) {
|
||||
DialogUtils.showAlertDialog(context, highlight, highlightDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
DialogUtils.showAlertDialog(
|
||||
context, highlight, highlightDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
.highlightAnswerComment(answerId, comment.id)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(highlightObserver)
|
||||
}, null)
|
||||
}, null
|
||||
)
|
||||
} else {
|
||||
DialogUtils.showAlertDialog(context, highlight, highlightDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
.highlightCommunityArticleComment(communityId, articleId, comment.id)
|
||||
DialogUtils.showAlertDialog(
|
||||
context, highlight, highlightDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
.highlightCommunityArticleComment(
|
||||
communityId,
|
||||
articleId,
|
||||
comment.id
|
||||
)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(highlightObserver)
|
||||
}, null)
|
||||
}, null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,7 +448,10 @@ object CommentHelper {
|
||||
val errorJson = JSONObject(string)
|
||||
val errorCode = errorJson.getInt("code")
|
||||
if (errorCode == 403059) {
|
||||
Utils.toast(HaloApp.getInstance().application, "权限错误,请刷新后重试")
|
||||
Utils.toast(
|
||||
HaloApp.getInstance().application,
|
||||
"权限错误,请刷新后重试"
|
||||
)
|
||||
return
|
||||
} else {
|
||||
Utils.toast(HaloApp.getInstance().application, e.message())
|
||||
@ -335,46 +462,40 @@ object CommentHelper {
|
||||
}
|
||||
|
||||
if (answerId != null) {
|
||||
DialogUtils.showAlertDialog(context, hide, hideDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
DialogUtils.showAlertDialog(
|
||||
context, hide, hideDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
.hideAnswerComment(answerId, comment.id)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(hideObserver)
|
||||
}, null)
|
||||
}, null
|
||||
)
|
||||
} else {
|
||||
DialogUtils.showAlertDialog(context, hide, hideDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
DialogUtils.showAlertDialog(
|
||||
context, hide, hideDialogHintContent,
|
||||
"确定", "取消", {
|
||||
RetrofitManager.getInstance(context).api
|
||||
.hideCommunityArticleComment(communityId, articleId, comment.id)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(hideObserver)
|
||||
}, null)
|
||||
}, null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showReportTypeDialog(context: Context, isVideoComment: Boolean, reportCallback: (reportType: String) -> Unit) {
|
||||
private fun showReportTypeDialog(
|
||||
context: Context,
|
||||
reportCallback: (reportType: String) -> Unit
|
||||
) {
|
||||
val reportTypes = arrayListOf("垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它")
|
||||
|
||||
if (!isVideoComment) {
|
||||
DialogUtils.showListDialog(context, reportTypes, null) { text ->
|
||||
val jsonObject = JSONObject()
|
||||
try {
|
||||
jsonObject.put("reason", text)
|
||||
reportCallback.invoke(jsonObject.toString())
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DialogUtils.showVideoComplaintDialog(context, reportTypes, null) { text ->
|
||||
reportCallback.invoke(text)
|
||||
}
|
||||
DialogUtils.showVideoComplaintDialog(context, reportTypes, null) { text ->
|
||||
reportCallback.invoke(text)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -271,6 +271,7 @@ public class CommentUtils {
|
||||
String articleId,
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
@ -294,7 +295,7 @@ public class CommentUtils {
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
|
||||
PostCommentUtils.likeComment(context, answerId, articleId, articleCommunityId, videoId, commentEntity.getId(),
|
||||
PostCommentUtils.likeComment(context, answerId, articleId, articleCommunityId, videoId, questionId, commentEntity.getId(),
|
||||
new PostCommentUtils.PostCommentListener() {
|
||||
@Override
|
||||
public void postSuccess(JSONObject response) {
|
||||
@ -348,7 +349,7 @@ public class CommentUtils {
|
||||
String entrance = "视频流-评论-点赞";
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
|
||||
PostCommentUtils.likeComment(context, answerId, articleId, articleCommunityId, videoId, commentEntity.getId(),
|
||||
PostCommentUtils.likeComment(context, answerId, articleId, articleCommunityId, videoId, "", commentEntity.getId(),
|
||||
new PostCommentUtils.PostCommentListener() {
|
||||
@Override
|
||||
public void postSuccess(JSONObject response) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
@ -35,9 +36,11 @@ object DialogHelper {
|
||||
uiModificationCallback: ((binding: DialogAlertDefaultBinding) -> Unit)? = null,
|
||||
trackMtaEvent: Boolean = false,
|
||||
mtaEvent: String = "",
|
||||
mtaKey: String = ""): Dialog {
|
||||
mtaKey: String = "") {
|
||||
val solidContext = checkDialogContext(context)
|
||||
|
||||
if (solidContext is Activity && solidContext.isFinishing) return
|
||||
|
||||
val dialog = if (trackMtaEvent) {
|
||||
TrackableDialog(solidContext, R.style.GhAlertDialog, mtaEvent, mtaKey)
|
||||
} else {
|
||||
@ -97,7 +100,6 @@ object DialogHelper {
|
||||
dialog.setContentView(contentView)
|
||||
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
dialog.show()
|
||||
return dialog
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,8 +116,8 @@ object DialogHelper {
|
||||
negativeClickCallback: EmptyCallback,
|
||||
trackMtaEvent: Boolean = false,
|
||||
mtaEvent: String = "",
|
||||
mtaKey: String = ""): Dialog {
|
||||
return showDialog(
|
||||
mtaKey: String = "") {
|
||||
showDialog(
|
||||
context = context,
|
||||
title = title,
|
||||
content = content,
|
||||
|
||||
@ -65,6 +65,7 @@ import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
|
||||
import com.gh.gamecenter.databinding.DialogBindPhoneBinding;
|
||||
import com.gh.gamecenter.databinding.DialogEnergySignBinding;
|
||||
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
|
||||
import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding;
|
||||
import com.gh.gamecenter.databinding.DialogQuickLoginPermissionBinding;
|
||||
@ -80,6 +81,7 @@ import com.gh.gamecenter.entity.PrivacyPolicyEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.entity.SimpleGameEntity;
|
||||
import com.gh.gamecenter.entity.TrackableEntity;
|
||||
import com.gh.gamecenter.setting.GameDownloadSettingFragment;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.halo.assistant.fragment.SettingsFragment;
|
||||
@ -221,7 +223,7 @@ public class DialogUtils {
|
||||
} else if (NetworkUtils.isWifiConnected(context)
|
||||
|| filter4GorSize(context, size)) {
|
||||
callBack.onResponse(false);
|
||||
} else if (!preferences.getBoolean(SettingsFragment.getTrafficDownloadHintKey(), true)) {
|
||||
} else if (!preferences.getBoolean(GameDownloadSettingFragment.getTrafficDownloadHintKey(), true)) {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> Utils.toast(context, "当前使用移动网络下载,请注意流量消耗"), 500);
|
||||
callBack.onResponse(false);
|
||||
} else {
|
||||
@ -296,7 +298,7 @@ public class DialogUtils {
|
||||
PreferenceManager
|
||||
.getDefaultSharedPreferences(finalContext)
|
||||
.edit()
|
||||
.putBoolean(SettingsFragment.getTrafficDownloadHintKey(), false)
|
||||
.putBoolean(GameDownloadSettingFragment.getTrafficDownloadHintKey(), false)
|
||||
.apply();
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> {
|
||||
// 显示了弹窗以后,即便下面这个 toast 放在 listener.onConfirm 后调用也是显示 listener.onConfirm 里的 toast
|
||||
@ -1926,7 +1928,7 @@ public class DialogUtils {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static void showEnergyDialog(Context context, String userName, int energy) {
|
||||
public static void showEnergyDialog(Context context, String userName, long energy) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
@ -2182,6 +2184,38 @@ public class DialogUtils {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showEnergySignDialog(Context context, int sevenDaySerialSign) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
DialogEnergySignBinding binding = DialogEnergySignBinding.inflate(LayoutInflater.from(context));
|
||||
|
||||
if (sevenDaySerialSign > 7) sevenDaySerialSign = 7;
|
||||
|
||||
for (int i = 1; i <= sevenDaySerialSign; i++) {
|
||||
int index = (i - 1) * 2;
|
||||
LinearLayout dayContainer = (LinearLayout) binding.signDaysContainer.getChildAt(index);
|
||||
ImageView dayIv = (ImageView) dayContainer.getChildAt(1);
|
||||
dayIv.setImageResource(R.drawable.ic_energy_center_signed);
|
||||
|
||||
if (i != 7) {
|
||||
int rIndex = (i - 1) * 2 + 1;
|
||||
LinearLayout lineContainer = (LinearLayout) binding.signDaysContainer.getChildAt(rIndex);
|
||||
View straightLine = lineContainer.getChildAt(0);
|
||||
View dottedLine = lineContainer.getChildAt(1);
|
||||
if (i != sevenDaySerialSign) {
|
||||
straightLine.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
dottedLine.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(binding.getRoot());
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context may be is application context
|
||||
* @return activity context
|
||||
|
||||
@ -28,9 +28,9 @@ import com.gh.gamecenter.category.CategoryDirectoryActivity
|
||||
import com.gh.gamecenter.category2.CategoryV2Activity
|
||||
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.eventbus.EBReuse
|
||||
import com.gh.gamecenter.eventbus.EBSkip
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment
|
||||
import com.gh.gamecenter.fragment.MainWrapperFragment
|
||||
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
|
||||
import com.gh.gamecenter.game.upload.GameSubmissionActivity
|
||||
@ -43,13 +43,14 @@ import com.gh.gamecenter.mygame.PlayedGameActivity
|
||||
import com.gh.gamecenter.personalhome.UserHomeActivity
|
||||
import com.gh.gamecenter.personalhome.background.PersonalityBackgroundActivity
|
||||
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
|
||||
import com.gh.gamecenter.qa.CommunityFragment
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
|
||||
import com.gh.gamecenter.personalhome.home.UserHistoryViewModel
|
||||
import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity
|
||||
import com.gh.gamecenter.qa.article.SimpleArticleListActivity
|
||||
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.questions.newdetail.NewQuestionDetailActivity
|
||||
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
|
||||
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.security.BindPhoneActivity
|
||||
@ -455,20 +456,42 @@ object DirectUtils {
|
||||
|
||||
/**
|
||||
* 跳转至个人主页
|
||||
* @param position 定位到某个tab 0游戏评论 1问答 2视频
|
||||
* @param position 定位到某个tab 0游戏 1发布
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToHomeActivity(context: Context, userId: String?, position: Int, entrance: String? = null, path: String? = null) {
|
||||
fun directToHomeActivity(context: Context,
|
||||
userId: String?,
|
||||
position: Int,
|
||||
entrance: String? = null,
|
||||
path: String? = null) {
|
||||
directToHomeActivity(context, userId, "", position, entrance, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至个人主页
|
||||
* @param position 定位到某个tab 0游戏 1发布
|
||||
* @param type 类型
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToHomeActivity(context: Context,
|
||||
userId: String?,
|
||||
type: String = "",
|
||||
position: Int,
|
||||
entrance: String? = null,
|
||||
path: String? = null) {
|
||||
|
||||
IntegralLogHelper.log("view_homepage", "个人主页")
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_USER_ID, userId)
|
||||
bundle.putString(KEY_TO, UserHomeActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_TYPE, UserHistoryViewModel.TYPE.fromValue(type).value)
|
||||
bundle.putInt(KEY_POSITION, position)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 回到首页
|
||||
*/
|
||||
@ -635,7 +658,7 @@ object DirectUtils {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, AnswerDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_TO, SimpleAnswerDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_ANSWER_ID, id)
|
||||
jumpActivity(context, bundle)
|
||||
@ -646,7 +669,7 @@ object DirectUtils {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, QuestionsDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_TO, NewQuestionDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_QUESTIONS_ID, id)
|
||||
jumpActivity(context, bundle)
|
||||
@ -657,7 +680,11 @@ object DirectUtils {
|
||||
if (url.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, WebActivity::class.java.simpleName)
|
||||
if (url.contains("android_page_type=singleton")) {
|
||||
bundle.putString(KEY_TO, SingletonWebActivity::class.java.simpleName)
|
||||
} else {
|
||||
bundle.putString(KEY_TO, WebActivity::class.java.simpleName)
|
||||
}
|
||||
bundle.putString(EntranceUtils.KEY_URL, url)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
@ -753,37 +780,25 @@ object DirectUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到社区页面
|
||||
* 切换到社区页面(旧社区页面已经没有了,处理为跳转到论坛详情)
|
||||
*/
|
||||
@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_MAIN, MainWrapperFragment.INDEX_ASK))
|
||||
EventBus.getDefault().post(EBReuse(CommunityFragment.EB_RETRY_PAGE))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToCommunity(context: Context) {
|
||||
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)
|
||||
}
|
||||
|
||||
// 这里换个线程操作是为了做一点延时
|
||||
AppExecutor.ioExecutor.execute {
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_ASK))
|
||||
EventBus.getDefault().post(EBReuse(CommunityFragment.EB_RETRY_PAGE))
|
||||
}
|
||||
// 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_MAIN, MainWrapperFragment.INDEX_BBS))
|
||||
// EventBus.getDefault().post(EBReuse(CommunityFragment.EB_RETRY_PAGE))
|
||||
// }
|
||||
// } else {
|
||||
directForumDetail(context, community?.id)
|
||||
// }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -824,16 +839,45 @@ object DirectUtils {
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToVideoDetail(context: Context, videoId: String,
|
||||
entrance: String? = null,
|
||||
path: String? = "") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, ForumVideoDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_VIDEO_ID, videoId);
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
} else {
|
||||
DialogUtils.showLowSystemVersionDialog(context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到旧视频页面
|
||||
* @param fromLocation 可见 [VideoDetailContainerViewModel.Location]
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToVideoDetail(context: Context, videoId: String, fromLocation: String, showComment: Boolean = false, gameId: String = "", entrance: String? = null,
|
||||
path: String? = "", referer: String = "", type: String = "", act: String = "", paginationType: String = "", fieldId: String = "", sectionName: String = "") {
|
||||
fun directToLegacyVideoDetail(context: Context,
|
||||
videoId: String,
|
||||
fromLocation: String,
|
||||
showComment: Boolean = false,
|
||||
gameId: String = "",
|
||||
entrance: String? = null,
|
||||
path: String? = "",
|
||||
referer: String = "",
|
||||
type: String = "",
|
||||
act: String = "",
|
||||
paginationType: String = "",
|
||||
fieldId: String = "",
|
||||
sectionName: String = "") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, VideoDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_VIDEO_ID, videoId);
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_ID, videoId)
|
||||
bundle.putString(KEY_GAMEID, gameId)
|
||||
@ -853,7 +897,7 @@ object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToVideoDetail(context: Context, videoId: String, fromLocation: String, showComment: Boolean = false, gameId: String = "", entrance: String? = null, path: String? = "", referer: String = "") {
|
||||
directToVideoDetail(context, videoId, fromLocation, showComment, gameId, entrance, path, referer, "", "")
|
||||
directToVideoDetail(context, videoId, entrance, path)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1166,9 +1210,10 @@ object DirectUtils {
|
||||
|
||||
/**
|
||||
* 到首页-论坛 tab
|
||||
* @param position 论坛的子 tab 位置
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToForum(context: Context) {
|
||||
fun directToForum(context: Context, position: Int = 0) {
|
||||
if (RunningUtils.isRunning(context)
|
||||
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
@ -1177,10 +1222,14 @@ object DirectUtils {
|
||||
|
||||
// 这里换个线程操作是为了做一点延时
|
||||
AppExecutor.ioExecutor.execute {
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_ASK))
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_BBS))
|
||||
EventBus.getDefault().post(EBSkip(CommunityHomeFragment.EB_TAB, position))
|
||||
}
|
||||
} else {
|
||||
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_ASK) })
|
||||
jumpActivity(context, Bundle().apply {
|
||||
putInt(KEY_POSITION, MainWrapperFragment.INDEX_BBS)
|
||||
putInt(KEY_SUB_POSITION, position)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1461,4 +1510,19 @@ object DirectUtils {
|
||||
url = String.format(Locale.CHINA, "%s×tamp=%d", url, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至活动详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToActivityDetail(context: Context, activityId: String, categoryId: String, entrance: String) {
|
||||
var url: String = if (isPublishEnv()) {
|
||||
Constants.ACTIVITY_DETAIL_ADDRESS
|
||||
} else {
|
||||
Constants.ACTIVITY_DETAIL_ADDRESS_DEV
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s&id=%s&category_id=%s×tamp=%d", url, activityId, categoryId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
|
||||
directToWebView(context, url, entrance)
|
||||
}
|
||||
}
|
||||
@ -240,6 +240,18 @@ public class DisplayUtils {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static void hideNavigationBar(Activity activity) {
|
||||
Window window = activity.getWindow();
|
||||
View decorView = window.getDecorView();
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { // lower api
|
||||
decorView.setSystemUiVisibility(View.GONE);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public static int retrieveNavigationHeight(Context context) {
|
||||
Resources resources = context.getResources();
|
||||
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
|
||||
|
||||
@ -138,7 +138,7 @@ public class DownloadItemUtils {
|
||||
holder.gameDownloadBtn.setText("已预约");
|
||||
holder.gameDownloadBtn.setTextColor(ContextCompat.getColor(holder.gameDes.getContext(), R.color.aaaaaa));
|
||||
holder.gameDownloadBtn.setBackgroundResource(R.drawable.button_round_f5f5f5);
|
||||
updateItemViewStatus(holder, false, null);
|
||||
updateItemViewStatus(holder, false, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ public class DownloadItemUtils {
|
||||
|
||||
// 显示预约
|
||||
if (gameEntity.isReservable()) {
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
holder.gameDownloadBtn.setText("预约");
|
||||
holder.gameDownloadBtn.setTextColor(Color.WHITE);
|
||||
@ -189,7 +189,7 @@ public class DownloadItemUtils {
|
||||
LinkEntity h5LinkEntity = gameEntity.getH5Link();
|
||||
String offStatus = gameEntity.getDownloadOffStatus();
|
||||
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
|
||||
if (h5LinkEntity != null) {
|
||||
if ("play".equals(h5LinkEntity.getType())) {
|
||||
@ -252,7 +252,7 @@ public class DownloadItemUtils {
|
||||
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
|
||||
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
}
|
||||
|
||||
// 更新插件的条目,有多个apk包
|
||||
@ -276,14 +276,14 @@ public class DownloadItemUtils {
|
||||
return;
|
||||
}
|
||||
}
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
updateItemViewStatus(holder, false, briefStyle, gameEntity.getColumnRecommend());
|
||||
}
|
||||
|
||||
// 更改进度条和提示文本的状态
|
||||
public static void changeStatus(Context context, GameViewHolder holder, DownloadEntity downloadEntity,
|
||||
boolean isShowPlatform, boolean isNormal) {
|
||||
|
||||
updateItemViewStatus(holder, true, null);
|
||||
updateItemViewStatus(holder, true, null, null);
|
||||
holder.gameProgressbar.setProgressDrawable(context.getResources().getDrawable(R.drawable.progressbar_bg_style));
|
||||
|
||||
String platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
|
||||
@ -377,22 +377,59 @@ public class DownloadItemUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateItemViewStatus(GameViewHolder holder, boolean hasDownload, @Nullable String briefStyle) {
|
||||
private static void updateItemViewStatus(GameViewHolder holder,
|
||||
boolean hasDownload,
|
||||
@Nullable String briefStyle,
|
||||
@Nullable LinkEntity recommendStyle) {
|
||||
if (hasDownload) {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
holder.gameProgressbar.setVisibility(View.VISIBLE);
|
||||
holder.gameInfo.setVisibility(View.VISIBLE);
|
||||
if (holder.recommendContainer != null) {
|
||||
holder.recommendContainer.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
|
||||
// 推荐优先,有推荐内容时不执行下面的 star 和 brief 代码块
|
||||
if (briefStyle != null
|
||||
&& recommendStyle != null
|
||||
&& briefStyle.contains("recommend")) {
|
||||
if (holder.recommendContainer != null) {
|
||||
holder.recommendContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
|
||||
holder.recommendTv.setText(recommendStyle.getText());
|
||||
if ("none".equals(recommendStyle.getType())) {
|
||||
holder.recommendIv.setVisibility(View.GONE);
|
||||
} else {
|
||||
Context context = holder.recommendContainer.getContext();
|
||||
int drawableId = context.getResources().getIdentifier(
|
||||
"ic_recommend_" + recommendStyle.getType(),
|
||||
"drawable",
|
||||
context.getPackageName());
|
||||
holder.recommendIv.setVisibility(View.VISIBLE);
|
||||
holder.recommendIv.setImageResource(drawableId);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (holder.recommendContainer != null) {
|
||||
holder.recommendContainer.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (briefStyle != null && briefStyle.contains("star")) {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(briefStyle) || briefStyle.contains("brief")) {
|
||||
// 缺省情况下回落到游戏简介
|
||||
if (TextUtils.isEmpty(briefStyle) || briefStyle.contains("brief") || briefStyle.contains("recommend")) {
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
@ -436,7 +473,7 @@ public class DownloadItemUtils {
|
||||
final ExposureEvent traceEvent,
|
||||
@Nullable final EmptyCallback clickCallback) {
|
||||
|
||||
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, clickCallback, null);
|
||||
setOnClickListener(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, clickCallback, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -451,6 +488,7 @@ public class DownloadItemUtils {
|
||||
final String location,
|
||||
final ExposureEvent traceEvent,
|
||||
@Nullable final EmptyCallback clickCallback,
|
||||
@Nullable final EmptyCallback refreshCallback,
|
||||
@Nullable final EmptyCallback allStateClickCallback) {
|
||||
|
||||
if (gameEntity.isReservable()) {
|
||||
@ -468,7 +506,12 @@ public class DownloadItemUtils {
|
||||
gameEntity,
|
||||
() -> {
|
||||
LogUtils.logReservation(gameEntity, traceEvent);
|
||||
adapter.notifyItemChanged(position);
|
||||
if (adapter != null) {
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
if (refreshCallback != null) {
|
||||
refreshCallback.onCallback();
|
||||
}
|
||||
}
|
||||
);
|
||||
dialogFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "reserve");
|
||||
@ -486,13 +529,23 @@ public class DownloadItemUtils {
|
||||
if ("download".equals(gameEntity.getReserveStatus())) {
|
||||
ReservationHelper.showDeleteReservationDialog(context, () -> {
|
||||
ReservationHelper.deleteReservation(gameEntity, () -> {
|
||||
adapter.notifyItemChanged(position);
|
||||
if (adapter != null) {
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
if (refreshCallback != null) {
|
||||
refreshCallback.onCallback();
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ReservationHelper.showCancelReservationDialog(context, () -> {
|
||||
ReservationHelper.cancelReservation(gameEntity, () -> {
|
||||
adapter.notifyItemChanged(position);
|
||||
if (adapter != null) {
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
if (refreshCallback != null) {
|
||||
refreshCallback.onCallback();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -529,7 +582,7 @@ public class DownloadItemUtils {
|
||||
if (clickCallback != null) {
|
||||
clickCallback.onCallback();
|
||||
}
|
||||
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent);
|
||||
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, traceEvent, refreshCallback);
|
||||
};
|
||||
|
||||
// 启动不需要请求存储权限
|
||||
@ -575,7 +628,7 @@ public class DownloadItemUtils {
|
||||
final RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter,
|
||||
final String entrance,
|
||||
final String location) {
|
||||
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, null);
|
||||
onNormalClick(context, downloadBtn, gameEntity, position, adapter, entrance, location, null, null);
|
||||
}
|
||||
|
||||
public static void onNormalClick(final Context context,
|
||||
@ -585,7 +638,8 @@ public class DownloadItemUtils {
|
||||
final RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter,
|
||||
final String entrance,
|
||||
final String location,
|
||||
@Nullable final ExposureEvent traceEvent) {
|
||||
@Nullable final ExposureEvent traceEvent,
|
||||
@Nullable final EmptyCallback refreshCallback) {
|
||||
String str = downloadBtn.getText().toString();
|
||||
if (gameEntity.getApk().isEmpty()) return;
|
||||
ApkEntity apk = ExtensionsKt.safelyGetInRelease(gameEntity.getApk(), 0);
|
||||
@ -656,7 +710,7 @@ public class DownloadItemUtils {
|
||||
return;
|
||||
}
|
||||
}
|
||||
install(context, gameEntity, position, adapter);
|
||||
install(context, gameEntity, position, adapter, refreshCallback);
|
||||
} else if (str.equals(context.getString(R.string.launch))) {
|
||||
//启动模拟器游戏
|
||||
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
@ -737,7 +791,7 @@ public class DownloadItemUtils {
|
||||
|
||||
//安装
|
||||
private static void install(final Context context, GameEntity gameEntity, int position,
|
||||
RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter) {
|
||||
RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter, @Nullable final EmptyCallback refreshCallback) {
|
||||
ApkEntity apkEntity = gameEntity.getApk().get(0);
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByUrl(apkEntity.getUrl());
|
||||
if (downloadEntity != null) {
|
||||
@ -748,7 +802,12 @@ public class DownloadItemUtils {
|
||||
if (gameEntity.getEntryMap() != null) {
|
||||
gameEntity.getEntryMap().remove(apkEntity.getPlatform());
|
||||
}
|
||||
adapter.notifyItemChanged(position);
|
||||
if (adapter != null) {
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
if (refreshCallback != null) {
|
||||
refreshCallback.onCallback();
|
||||
}
|
||||
} else if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
DialogHelper.showPluginDialog(context, () -> {
|
||||
PackageInstaller.uninstall(context, path);
|
||||
|
||||
@ -22,9 +22,9 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.AUTO_INSTALL_SP_KEY
|
||||
import com.gh.gamecenter.suggest.SuggestType
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.halo.assistant.fragment.SettingsFragment
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
@ -155,12 +155,12 @@ object DownloadObserver {
|
||||
SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator,
|
||||
SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null)
|
||||
}
|
||||
SimulatorGameManager.recordDownloadSimulatorGames(downloadEntity.gameId, simulator.type)
|
||||
SimulatorGameManager.recordDownloadSimulatorGame(downloadEntity.gameId, simulator.type)
|
||||
SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName)
|
||||
} else {
|
||||
val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
|
||||
// 是否是自动安装
|
||||
val isAutoInstall = PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(SettingsFragment.AUTO_INSTALL_SP_KEY, true)
|
||||
val isAutoInstall = PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(AUTO_INSTALL_SP_KEY, true)
|
||||
if (downloadType == Constants.SIMULATOR_DOWNLOAD || isAutoInstall) {
|
||||
if (FileUtils.isEmptyFile(downloadEntity.path)) {
|
||||
Utils.toast(mApplication, R.string.install_failure_hint)
|
||||
|
||||
@ -130,27 +130,39 @@ object EnergyTaskHelper {
|
||||
// 完成弹窗
|
||||
@JvmStatic
|
||||
fun showCompletePopup(entity: EnergyTaskCompleteEntity) {
|
||||
val currentActivity = AppManager.getInstance().recentActiveActivity
|
||||
currentActivity?.run {
|
||||
val contentView = View.inflate(this, R.layout.popup_energy_task, null)
|
||||
contentView.run {
|
||||
findViewById<TextView>(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}"
|
||||
findViewById<TextView>(R.id.taskEnergy).text = "+${entity.energy}光能"
|
||||
isFocusable = true
|
||||
isFocusableInTouchMode = true
|
||||
setOnClickListener {
|
||||
if (currentActivity::class.java.simpleName != EnergyCenterActivity::class.java.simpleName) {
|
||||
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
|
||||
tryWithDefaultCatch {
|
||||
val currentActivity = AppManager.getInstance().recentActiveActivity
|
||||
val popWindow = PopupWindow(LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
|
||||
|
||||
currentActivity?.run {
|
||||
val contentView = View.inflate(this, R.layout.popup_energy_task, null)
|
||||
contentView.run {
|
||||
findViewById<TextView>(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}"
|
||||
findViewById<TextView>(R.id.taskEnergy).text = "+${entity.energy}光能"
|
||||
isFocusable = true
|
||||
isFocusableInTouchMode = true
|
||||
setOnClickListener {
|
||||
if (popWindow != null && popWindow.isShowing) {
|
||||
popWindow.dismiss()
|
||||
}
|
||||
if (currentActivity !is EnergyCenterActivity) {
|
||||
currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px())
|
||||
popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0)
|
||||
|
||||
countDownTimer(3) { finish, _ ->
|
||||
if (finish && popWindow != null && popWindow.isShowing) {
|
||||
popWindow.dismiss()
|
||||
popWindow.contentView = contentView
|
||||
currentActivity.window.decorView.post {
|
||||
popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0)
|
||||
}
|
||||
|
||||
contentView.postDelayed({
|
||||
tryCatchInRelease {
|
||||
if (popWindow != null && popWindow.isShowing) {
|
||||
popWindow.dismiss()
|
||||
}
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,11 +47,13 @@ public class EntranceUtils {
|
||||
public static final String KEY_PACKAGE_MD5 = "package_md5";
|
||||
public static final String HOST_ARTICLE = "article";
|
||||
public static final String HOST_UPLOAD_VIDEO = "upload_video";//上传视频
|
||||
public static final String HOST_UPLOAD_VIDEO_NEW = "upload_video_new"; // 上传视频新(AKA 发视频)
|
||||
public static final String HOST_VIDEO_SINGLE = "video_single";//指定视频-不能划动
|
||||
public static final String HOST_VIDEO_MORE = "video_more";//指定视频-能划动
|
||||
public static final String HOST_VIDEO_STREAMING_HOME = "video_streaming_home";//视频流-首页
|
||||
public static final String HOST_VIDEO_STREAMING_DESC = "video_streaming_desc";//视频流-游戏介绍进入
|
||||
public static final String HOST_VIDEO_COLLECTION = "video_collection";//视频合集
|
||||
public static final String HOST_VIDEO_DETAIL = "video_detail";
|
||||
public static final String HOST_USERHOME = "userhome";//个人主页
|
||||
public static final String HOST_VIDEO = "video";
|
||||
public static final String HOST_FORUM = "forum";
|
||||
@ -98,6 +100,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_LINK = "link";
|
||||
public static final String KEY_NAME = "name";
|
||||
public static final String KEY_POSITION = "position";
|
||||
public static final String KEY_SUB_POSITION = "sub_position";
|
||||
public static final String KEY_ENTRANCE = "entrance";
|
||||
public static final String KEY_ENTRANCE_LINK = "entrance_link";
|
||||
public static final String KEY_TARGET = "target";
|
||||
@ -236,6 +239,11 @@ public class EntranceUtils {
|
||||
public static final String KEY_IS_QA_FEEDBACK = "is_qa_feedback";
|
||||
public static final String KEY_IS_CLICK_RECEIVE_BTN = "is_click_receive_btn";
|
||||
public static final String KEY_SHOW_QUICK_LOGIN = "show_quick_login";
|
||||
public static final String KEY_VIDEO_LIST = "video_list";
|
||||
public static final String KEY_CHOOSE_FORUM_TYPE = "choose_forum_type";
|
||||
public static final String KEY_CHOOSE_MAX_COUNT = "choose_max_count";
|
||||
public static final String KEY_COMMENT_COUNT = "comment_count";
|
||||
public static final String KEY_IS_COMMENT_CONVERSATION = "is_comment_conversation";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
@ -252,6 +260,10 @@ public class EntranceUtils {
|
||||
} else {
|
||||
Intent intent1 = new Intent(context, clazz);
|
||||
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// 如果 activity 名称有 singleton 的就添加 reorder_to_front 标签 (有点粗暴有点蠢,但暂时就先这样吧 :C )
|
||||
if (clazz.getSimpleName().toLowerCase().contains("singleton")) {
|
||||
intent1.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
}
|
||||
intent1.putExtras(bundle);
|
||||
context.startActivity(intent1);
|
||||
}
|
||||
|
||||
@ -19,10 +19,12 @@ object ErrorHelper {
|
||||
* [customizedHandler] 返回 true 为已处理该错误码,false 则交由 [handleError] 处理
|
||||
*/
|
||||
@JvmStatic
|
||||
fun handleErrorWithCustomizedHandler(context: Context,
|
||||
errorString: String?,
|
||||
showHighPriorityHint: Boolean = false,
|
||||
customizedHandler: (code: Int) -> Boolean) {
|
||||
fun handleErrorWithCustomizedHandler(
|
||||
context: Context,
|
||||
errorString: String?,
|
||||
showHighPriorityHint: Boolean = false,
|
||||
customizedHandler: (code: Int) -> Boolean
|
||||
) {
|
||||
val errorEntity = errorString?.toObject<ErrorEntity>()
|
||||
|
||||
if (customizedHandler(errorEntity?.code ?: 0)) {
|
||||
@ -75,8 +77,15 @@ object ErrorHelper {
|
||||
*403057: 游戏评论
|
||||
*403054: 更新社区文章
|
||||
*403047: 回答点赞
|
||||
*403112: 发布视频贴
|
||||
*403113: 修改视频贴
|
||||
*403114: 点赞视频贴
|
||||
*/
|
||||
private fun handleError(context: Context, showHighPriorityHint: Boolean = false, errorEntity: ErrorEntity) {
|
||||
private fun handleError(
|
||||
context: Context,
|
||||
showHighPriorityHint: Boolean = false,
|
||||
errorEntity: ErrorEntity
|
||||
) {
|
||||
when (errorEntity.code) {
|
||||
403050,
|
||||
403051,
|
||||
@ -89,7 +98,10 @@ object ErrorHelper {
|
||||
403054,
|
||||
403069,
|
||||
403071,
|
||||
403047 -> handleErrorWithCommunityBannedDialog(context, errorEntity)
|
||||
403047,
|
||||
403112,
|
||||
403113,
|
||||
403114 -> handleErrorWithCommunityBannedDialog(context, errorEntity)
|
||||
|
||||
403057,
|
||||
403068 -> handleErrorWithCommentBannedDialog(context, errorEntity)
|
||||
@ -120,12 +132,15 @@ object ErrorHelper {
|
||||
403082 -> Utils.toast(context, "作者已关闭评论")
|
||||
403022 -> Utils.toast(context, "不能回复自己")
|
||||
403056 -> Utils.toast(context, "发布失败,字数已达上限")
|
||||
403111 -> Utils.toast(context, "提交失败,评论违规")
|
||||
|
||||
403020 -> if (showHighPriorityHint) {
|
||||
DialogUtils.showAlertDialog(context,
|
||||
"提醒",
|
||||
"提问过于频繁,请先休息一下哦",
|
||||
"知道了", null, null, null)
|
||||
DialogUtils.showAlertDialog(
|
||||
context,
|
||||
"提醒",
|
||||
"提问过于频繁,请先休息一下哦",
|
||||
"知道了", null, null, null
|
||||
)
|
||||
} else {
|
||||
Utils.toast(context, R.string.comment_failed_toofrequent)
|
||||
}
|
||||
@ -148,12 +163,14 @@ object ErrorHelper {
|
||||
"(非永久)"
|
||||
}
|
||||
val dialogContext = DialogUtils.checkDialogContext(context)
|
||||
DialogUtils.showAlertDialog(dialogContext,
|
||||
"提示",
|
||||
"你因违反《光环助手评论规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:${Config.getSettings()?.support?.qq})",
|
||||
"去看看", "关闭", {
|
||||
dialogContext.startActivity(WebActivity.getCommentRulesIntent(dialogContext))
|
||||
}, null)
|
||||
DialogUtils.showAlertDialog(
|
||||
dialogContext,
|
||||
"提示",
|
||||
"你因违反《光环助手评论规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:${Config.getSettings()?.support?.qq})",
|
||||
"去看看", "关闭", {
|
||||
dialogContext.startActivity(WebActivity.getCommentRulesIntent(dialogContext))
|
||||
}, null
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleErrorWithCommunityBannedDialog(context: Context, errorEntity: ErrorEntity) {
|
||||
@ -163,18 +180,21 @@ object ErrorHelper {
|
||||
"(非永久)"
|
||||
}
|
||||
val dialogContext = DialogUtils.checkDialogContext(context)
|
||||
DialogUtils.showAlertDialog(dialogContext,
|
||||
"提示",
|
||||
"你因违反《问答版块规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:1562479331)",
|
||||
"去看看", "关闭", {
|
||||
dialogContext.startActivity(WebActivity.getCommunityRuleIntent(dialogContext))
|
||||
}, null)
|
||||
DialogUtils.showAlertDialog(
|
||||
dialogContext,
|
||||
"提示",
|
||||
"你因违反《问答版块规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:1562479331)",
|
||||
"去看看", "关闭", {
|
||||
dialogContext.startActivity(WebActivity.getCommunityRuleIntent(dialogContext))
|
||||
}, null
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun handleLoginError(context: Context, httpException: HttpException?) {
|
||||
try {
|
||||
val errorEntity: ErrorEntity? = httpException?.response()?.errorBody()?.string()?.toObject()
|
||||
val errorEntity: ErrorEntity? =
|
||||
httpException?.response()?.errorBody()?.string()?.toObject()
|
||||
when {
|
||||
errorEntity?.code == 403099 -> {
|
||||
Utils.toast(context, "当前账号正在注销,禁止登录")
|
||||
|
||||
@ -6,6 +6,7 @@ import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
@ -13,9 +14,9 @@ import android.text.*
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.ImageSpan
|
||||
import android.text.style.URLSpan
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.*
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import android.widget.PopupWindow
|
||||
@ -29,6 +30,7 @@ import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.*
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
@ -54,27 +56,32 @@ import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 创建以 activity 为观察者上下文的 viewModel
|
||||
*/
|
||||
inline fun <reified VM : ViewModel> FragmentActivity.viewModelProvider(
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
) =
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
|
||||
/**
|
||||
* 创建以 activity 为观察者上下文的 viewModel
|
||||
* 额外的 key: 用于区分单 activity 多 viewModel 的情况 (如首页tab)
|
||||
*/
|
||||
inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
|
||||
provider: ViewModelProvider.Factory? = null,
|
||||
key: String = ""
|
||||
provider: ViewModelProvider.Factory? = null,
|
||||
key: String = ""
|
||||
) = if (key.isEmpty()) {
|
||||
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
|
||||
} else {
|
||||
@ -85,28 +92,33 @@ inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
|
||||
* 创建以 activity 为观察者上下文的 viewModel
|
||||
*/
|
||||
inline fun <reified VM : ViewModel> FragmentActivity.viewModelProviderFromParent(
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
) =
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
|
||||
/**
|
||||
* 创建以 fragment 为观察者上下文的 viewModel
|
||||
*/
|
||||
inline fun <reified VM : ViewModel> Fragment.viewModelProvider(
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
) =
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
|
||||
/**
|
||||
*
|
||||
* ViewPager Extensions
|
||||
*
|
||||
*/
|
||||
fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = addOnPageChangeListener(onSelected = action)
|
||||
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) {
|
||||
override fun onPageScrolled(
|
||||
position: Int,
|
||||
positionOffset: Float,
|
||||
positionOffsetPixels: Int
|
||||
) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@ -121,11 +133,17 @@ fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = n
|
||||
addOnPageChangeListener(listener)
|
||||
}
|
||||
|
||||
fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null,
|
||||
onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null,
|
||||
onPageSelected: ((position: Int) -> Unit)? = null) {
|
||||
fun ViewPager.doOnScroll(
|
||||
onStateChanged: ((state: Int) -> Unit)? = null,
|
||||
onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null,
|
||||
onPageSelected: ((position: Int) -> Unit)? = null
|
||||
) {
|
||||
val listener = object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
override fun onPageScrolled(
|
||||
position: Int,
|
||||
positionOffset: Float,
|
||||
positionOffsetPixels: Int
|
||||
) {
|
||||
onPageScrolled?.invoke(position, positionOffset, positionOffsetPixels)
|
||||
}
|
||||
|
||||
@ -145,13 +163,19 @@ fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null,
|
||||
* Fragment related
|
||||
*/
|
||||
inline fun <reified T : Fragment> Fragment.fragmentFromActivity() =
|
||||
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
|
||||
?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
|
||||
parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
|
||||
?: parentFragmentManager.fragmentFactory.instantiate(
|
||||
requireContext().classLoader,
|
||||
T::class.java.canonicalName
|
||||
) as T
|
||||
|
||||
|
||||
inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
|
||||
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
|
||||
?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T
|
||||
childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T
|
||||
?: childFragmentManager.fragmentFactory.instantiate(
|
||||
requireContext().classLoader,
|
||||
T::class.java.canonicalName
|
||||
) as T
|
||||
|
||||
|
||||
/**
|
||||
@ -159,7 +183,12 @@ inline fun <reified T : Fragment> Fragment.fragmentFromParentFragment() =
|
||||
*/
|
||||
|
||||
// 监听滚动距离
|
||||
fun RecyclerView.doOnScrolledSpecificDistance(distanceX: Int = 0, distanceY: Int = 0, singleTimeEvent: Boolean = false, action: () -> Unit) {
|
||||
fun RecyclerView.doOnScrolledSpecificDistance(
|
||||
distanceX: Int = 0,
|
||||
distanceY: Int = 0,
|
||||
singleTimeEvent: Boolean = false,
|
||||
action: () -> Unit
|
||||
) {
|
||||
val listener = object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
@ -176,6 +205,18 @@ fun RecyclerView.doOnScrolledSpecificDistance(distanceX: Int = 0, distanceY: Int
|
||||
addOnScrollListener(listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewBinding related Extensions
|
||||
*/
|
||||
inline fun <reified T : ViewBinding> ViewGroup.toBinding(): T {
|
||||
return T::class.java.getMethod(
|
||||
"inflate",
|
||||
LayoutInflater::class.java,
|
||||
ViewGroup::class.java,
|
||||
Boolean::class.java
|
||||
).invoke(null, layoutInflater, this, false) as T
|
||||
}
|
||||
|
||||
/**
|
||||
* View Extensions
|
||||
*/
|
||||
@ -216,6 +257,46 @@ fun View.setDebouncedClickListener(action: () -> Unit) {
|
||||
setOnClickListener { debounceActionWithInterval(interval = 300L) { action.invoke() } }
|
||||
}
|
||||
|
||||
val View.layoutInflater: LayoutInflater
|
||||
get() = LayoutInflater.from(this.context)
|
||||
|
||||
fun View.removeFromParent() {
|
||||
postDelayed(object : Runnable {
|
||||
override fun run() {
|
||||
try {
|
||||
if (parent == null) {
|
||||
Utils.log(javaClass.simpleName, "getParent() returning Null")
|
||||
} else {
|
||||
try {
|
||||
(parent as ViewGroup).removeView(this@removeFromParent)
|
||||
} catch (ex: Exception) {
|
||||
Utils.log(javaClass.simpleName, "Cannot remove from parent layout")
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Utils.log(javaClass.simpleName, Log.getStackTraceString(ex))
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩大 View 的点击区域
|
||||
*/
|
||||
fun View.enlargeTouchArea(enlargedSizeInPx: Int = 4F.dip2px()) {
|
||||
val parent = parent as View
|
||||
|
||||
parent.post {
|
||||
val rect = Rect()
|
||||
getHitRect(rect)
|
||||
rect.top -= enlargedSizeInPx
|
||||
rect.left -= enlargedSizeInPx
|
||||
rect.bottom += enlargedSizeInPx
|
||||
rect.right += enlargedSizeInPx
|
||||
parent.touchDelegate = TouchDelegate(rect, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun isPublishEnv(): Boolean {
|
||||
return BuildConfig.FLAVOR != "internal"
|
||||
}
|
||||
@ -268,11 +349,11 @@ fun String.insert(index: Int, string: String): String {
|
||||
*/
|
||||
fun String.replaceUnsupportedHtmlTag(): String {
|
||||
return this.replace("<ul", "<hul")
|
||||
.replace("</ul>", "</hul>")
|
||||
.replace("<li", "<hli")
|
||||
.replace("</li>", "</hli>")
|
||||
.replace("<ol", "<hol")
|
||||
.replace("</ol>", "</hol>")
|
||||
.replace("</ul>", "</hul>")
|
||||
.replace("<li", "<hli")
|
||||
.replace("</li>", "</hli>")
|
||||
.replace("<ol", "<hol")
|
||||
.replace("</ol>", "</hol>")
|
||||
}
|
||||
|
||||
fun String.containHtmlTag(): Boolean {
|
||||
@ -287,8 +368,8 @@ fun String.containHtmlTag(): Boolean {
|
||||
fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
|
||||
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
|
||||
DialogUtils.showRegulationTestDialog(requireContext(),
|
||||
{ DirectUtils.directToRegulationTestPage(requireContext()) },
|
||||
{ action.invoke() })
|
||||
{ DirectUtils.directToRegulationTestPage(requireContext()) },
|
||||
{ action.invoke() })
|
||||
} else {
|
||||
action()
|
||||
}
|
||||
@ -297,8 +378,8 @@ fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
|
||||
fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
|
||||
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
|
||||
DialogUtils.showRegulationTestDialog(this,
|
||||
{ DirectUtils.directToRegulationTestPage(this) },
|
||||
{ action.invoke() })
|
||||
{ DirectUtils.directToRegulationTestPage(this) },
|
||||
{ action.invoke() })
|
||||
} else {
|
||||
action()
|
||||
}
|
||||
@ -397,14 +478,15 @@ fun String.removeInsertedContent(): String {
|
||||
|
||||
// 去除视频相关文本
|
||||
fun String.removeVideoContent(): String {
|
||||
val videoRegex = "(?s)<div class=\"insert-video-container\".*?</div>"
|
||||
val videoRegex =
|
||||
"(?s)<div data-id.*?class=\"placeholder-video-container\".*? class=\"video-poster-btn\".*?</div>"
|
||||
return this.replace(videoRegex.toRegex(), "")
|
||||
}
|
||||
|
||||
// 完全地清除所有 Html 格式
|
||||
fun String.clearHtmlFormatCompletely(): String {
|
||||
return Html.fromHtml(this).toString().replace('\n', 32.toChar())
|
||||
.replace(160.toChar(), 32.toChar()).replace(65532.toChar(), 32.toChar()).trim { it <= ' ' }
|
||||
.replace(160.toChar(), 32.toChar()).replace(65532.toChar(), 32.toChar()).trim { it <= ' ' }
|
||||
}
|
||||
|
||||
// 如果该字符串长度超过固定长度的话,从头开始截取固定长度并返回
|
||||
@ -463,6 +545,14 @@ fun Any.toRequestBody(): RequestBody {
|
||||
return RequestBody.create(MediaType.parse("application/json"), json)
|
||||
}
|
||||
|
||||
fun JSONObject.toRequestBody(): RequestBody {
|
||||
return RequestBody.create(MediaType.parse("application/json"), this.toString())
|
||||
}
|
||||
|
||||
fun JSONArray.toRequestBody(): RequestBody {
|
||||
return RequestBody.create(MediaType.parse("application/json"), this.toString())
|
||||
}
|
||||
|
||||
// 对在浏览器(WebView)显示的路径进行转码
|
||||
fun String.decodeURI(): String {
|
||||
return URI(null, null, this, null).rawPath
|
||||
@ -526,19 +616,23 @@ fun PopupWindow.showAutoOrientation(anchorView: View, distanceY: Int = 0, distan
|
||||
* 权限相关
|
||||
*/
|
||||
fun Fragment.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(requireContext(), object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(
|
||||
requireContext(),
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun Fragment.checkReadPhoneStatePermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(requireContext(), object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
PermissionHelper.checkReadPhoneStatePermissionBeforeAction(
|
||||
requireContext(),
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
@ -550,11 +644,13 @@ fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
}
|
||||
|
||||
fun FragmentActivity.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(
|
||||
this,
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
action.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun FragmentActivity.checkReadPhoneStatePermissionBeforeAction(action: (() -> Unit)) {
|
||||
@ -585,20 +681,27 @@ fun <T> List<T>.secondOrNull(): T? {
|
||||
/**
|
||||
* TextView related.
|
||||
*/
|
||||
fun TextView.setTextWithHighlightedTextWrappedInsideWrapper(text: CharSequence,
|
||||
wrapper: String = Constants.DEFAULT_TEXT_WRAPPER,
|
||||
@ColorRes
|
||||
highlightColorId: Int = R.color.theme_font,
|
||||
copyClickedText: Boolean = false,
|
||||
highlightedTextClickListener: (() -> Unit)? = null) {
|
||||
TextHelper.highlightTextThatIsWrappedInsideWrapper(this, text, wrapper, highlightColorId, object : SimpleCallback<String> {
|
||||
override fun onCallback(arg: String) {
|
||||
if (copyClickedText) {
|
||||
arg.copyTextAndToast("已复制:$arg")
|
||||
fun TextView.setTextWithHighlightedTextWrappedInsideWrapper(
|
||||
text: CharSequence,
|
||||
wrapper: String = Constants.DEFAULT_TEXT_WRAPPER,
|
||||
@ColorRes
|
||||
highlightColorId: Int = R.color.theme_font,
|
||||
copyClickedText: Boolean = false,
|
||||
highlightedTextClickListener: (() -> Unit)? = null
|
||||
) {
|
||||
TextHelper.highlightTextThatIsWrappedInsideWrapper(
|
||||
this,
|
||||
text,
|
||||
wrapper,
|
||||
highlightColorId,
|
||||
object : SimpleCallback<String> {
|
||||
override fun onCallback(arg: String) {
|
||||
if (copyClickedText) {
|
||||
arg.copyTextAndToast("已复制:$arg")
|
||||
}
|
||||
highlightedTextClickListener?.invoke()
|
||||
}
|
||||
highlightedTextClickListener?.invoke()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before: Int, count: Int) -> Unit) {
|
||||
@ -639,7 +742,10 @@ fun <T> List<T>.safelyGetInRelease(index: Int): T? {
|
||||
* @param shrankText 未展开时的文字
|
||||
* @param expandedText 展开后的文字
|
||||
*/
|
||||
fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence, expandedText: CharSequence) {
|
||||
fun ExpandTextView.setTextWithInterceptingInternalUrl(
|
||||
shrankText: CharSequence,
|
||||
expandedText: CharSequence
|
||||
) {
|
||||
var shrankSsb = shrankText.interceptUrlSpanAndRoundImageSpan()
|
||||
var expandedSsb = expandedText.interceptUrlSpanAndRoundImageSpan()
|
||||
|
||||
@ -647,23 +753,42 @@ fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence,
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
while (shrankSsb.contains("\n\n")) {
|
||||
val index = shrankSsb.indexOf("\n\n", 0, true)
|
||||
shrankSsb = SpannableStringBuilder(shrankSsb.subSequence(0, index)).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length))
|
||||
shrankSsb = SpannableStringBuilder(
|
||||
shrankSsb.subSequence(
|
||||
0,
|
||||
index
|
||||
)
|
||||
).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length))
|
||||
}
|
||||
while (expandedSsb.contains("\n\n")) {
|
||||
val index = expandedSsb.indexOf("\n\n", 0, true)
|
||||
expandedSsb = SpannableStringBuilder(expandedSsb.subSequence(0, index)).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length))
|
||||
expandedSsb = SpannableStringBuilder(
|
||||
expandedSsb.subSequence(
|
||||
0,
|
||||
index
|
||||
)
|
||||
).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length))
|
||||
}
|
||||
}
|
||||
|
||||
// 去掉多余的 P 标签换行
|
||||
if (expandedSsb.endsWith("\n", true)) {
|
||||
expandedSsb = SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length)))
|
||||
expandedSsb =
|
||||
SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length)))
|
||||
}
|
||||
|
||||
movementMethod = CustomLinkMovementMethod.getInstance()
|
||||
|
||||
shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, shrankSsb, highlightedTextClickListener = null)
|
||||
expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, expandedSsb, highlightedTextClickListener = null)
|
||||
shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(
|
||||
context,
|
||||
shrankSsb,
|
||||
highlightedTextClickListener = null
|
||||
)
|
||||
expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(
|
||||
context,
|
||||
expandedSsb,
|
||||
highlightedTextClickListener = null
|
||||
)
|
||||
setShrankTextAndExpandedText(shrankSsb, expandedSsb)
|
||||
}
|
||||
|
||||
@ -671,32 +796,41 @@ fun CharSequence.interceptUrlSpanAndRoundImageSpan(): SpannableStringBuilder {
|
||||
return SpannableStringBuilder.valueOf(this).apply {
|
||||
getSpans(0, length, URLSpan::class.java).forEach {
|
||||
setSpan(
|
||||
object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(
|
||||
HaloApp.getInstance().application,
|
||||
R.color.theme_font
|
||||
)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) {
|
||||
widget.context.startActivity(WebActivity.getIntent(widget.context, it.url, true))
|
||||
}
|
||||
override fun onClick(widget: View) {
|
||||
if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) {
|
||||
widget.context.startActivity(
|
||||
WebActivity.getIntent(
|
||||
widget.context,
|
||||
it.url,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
getSpanStart(it),
|
||||
getSpanEnd(it),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
}
|
||||
},
|
||||
getSpanStart(it),
|
||||
getSpanEnd(it),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
removeSpan(it)
|
||||
}
|
||||
|
||||
getSpans(0, length, ImageSpan::class.java).forEach {
|
||||
setSpan(
|
||||
CenterImageSpan(it.drawable),
|
||||
getSpanStart(it),
|
||||
getSpanEnd(it),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
CenterImageSpan(it.drawable),
|
||||
getSpanStart(it),
|
||||
getSpanEnd(it),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
removeSpan(it)
|
||||
}
|
||||
@ -805,22 +939,22 @@ inline fun testChannelOnly(f: () -> Unit) {
|
||||
* 倒计时,单位s
|
||||
*/
|
||||
inline fun countDownTimer(
|
||||
timeInSeconds: Long,
|
||||
crossinline block: (finish: Boolean, remainingTime: Long) -> Unit
|
||||
timeInSeconds: Long,
|
||||
crossinline block: (finish: Boolean, remainingTime: Long) -> Unit
|
||||
): Disposable {
|
||||
var subscribe: Disposable? = null
|
||||
subscribe = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it < timeInSeconds) {
|
||||
block.invoke(false, timeInSeconds - it)
|
||||
} else {
|
||||
block.invoke(true, 0)
|
||||
if (subscribe != null && !subscribe!!.isDisposed) {
|
||||
subscribe?.dispose()
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it < timeInSeconds) {
|
||||
block.invoke(false, timeInSeconds - it)
|
||||
} else {
|
||||
block.invoke(true, 0)
|
||||
if (subscribe != null && !subscribe!!.isDisposed) {
|
||||
subscribe?.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
return subscribe
|
||||
}
|
||||
|
||||
@ -829,17 +963,17 @@ inline fun countDownTimer(
|
||||
* @start 起始时间
|
||||
*/
|
||||
inline fun countUpTimer(
|
||||
start: Long,
|
||||
period: Long = 1000,
|
||||
crossinline block: (millisUntilFinished: Long) -> Unit
|
||||
start: Long,
|
||||
period: Long = 1000,
|
||||
crossinline block: (millisUntilFinished: Long) -> Unit
|
||||
): Disposable {
|
||||
var startTime = start
|
||||
return Observable.interval(0, period, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
startTime += period
|
||||
block.invoke(startTime)
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
startTime += period
|
||||
block.invoke(startTime)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -847,10 +981,10 @@ inline fun countUpTimer(
|
||||
*/
|
||||
inline fun rxTimer(interval: Long, crossinline block: (times: Long) -> Unit): Disposable {
|
||||
return Observable.interval(0, interval, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
block.invoke(it)
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
block.invoke(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun LottieAnimationView.doOnAnimationEnd(action: () -> Unit) {
|
||||
@ -916,13 +1050,17 @@ fun List<String>?.checkSameFromStringArray(check2: List<String>?): Boolean {
|
||||
fun EditText.showKeyBoard() {
|
||||
this.postDelayed({
|
||||
this.requestFocus()
|
||||
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
val inputMethodManager =
|
||||
context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.showSoftInput(this, 0)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
|
||||
fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)? = null, onStopTrackingTouch: (() -> Unit)? = null) {
|
||||
fun SeekBar.doOnSeekBarChangeListener(
|
||||
progressChange: ((progress: Int) -> Unit)? = null,
|
||||
onStopTrackingTouch: (() -> Unit)? = null
|
||||
) {
|
||||
this.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
progressChange?.invoke(progress)
|
||||
@ -941,14 +1079,22 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)?
|
||||
fun <T> observableToMain(): ObservableTransformer<T, T> {
|
||||
return ObservableTransformer { upstream ->
|
||||
upstream.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> singleToMain(): SingleTransformer<T, T> {
|
||||
return SingleTransformer { upstream ->
|
||||
upstream.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
}
|
||||
|
||||
fun clickToastByStatus(status: String, action: () -> Unit) {
|
||||
when (status) {
|
||||
"pending" -> ToastUtils.showToast("内容审核中")
|
||||
"fail" -> ToastUtils.showToast("内容审核不通过")
|
||||
else -> action.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
130
app/src/main/java/com/gh/common/util/FloatingBackViewManager.kt
Normal file
130
app/src/main/java/com/gh/common/util/FloatingBackViewManager.kt
Normal file
@ -0,0 +1,130 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import android.view.Gravity
|
||||
import android.widget.TextView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.energy.EnergyCenterActivity
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
import com.lzf.easyfloat.EasyFloat
|
||||
import com.lzf.easyfloat.enums.ShowPattern
|
||||
import com.lzf.easyfloat.enums.SidePattern
|
||||
|
||||
/**
|
||||
* 返回小浮窗管理类
|
||||
* 支持两种类型,网页活动(type_activity) 和 积分任务(type_task)
|
||||
*
|
||||
* 两种浮窗冲突,显示其中一个的时候就会把另一个判定为隐藏
|
||||
*/
|
||||
object FloatingBackViewManager {
|
||||
|
||||
const val TYPE_ACTIVITY = "type_activity"
|
||||
const val TYPE_TASK = "type_task"
|
||||
|
||||
private const val FLOATING_BACK_VIEW = "floating_back_view"
|
||||
|
||||
private var mType = ""
|
||||
private var mActivityUrl = ""
|
||||
private var mLastPositionY = 114F.dip2px()
|
||||
|
||||
/**
|
||||
* 显示返回小浮窗
|
||||
*/
|
||||
fun showBackView(activity: Activity) {
|
||||
// 不支持 Android 4.1 的设备
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) return
|
||||
|
||||
EasyFloat.with(activity)
|
||||
.setLayout(R.layout.layout_task_back)
|
||||
.setTag(FLOATING_BACK_VIEW)
|
||||
.setAnimator(null)
|
||||
.setGravity(Gravity.TOP.xor(Gravity.START), 0, mLastPositionY)
|
||||
.setSidePattern(SidePattern.LEFT)
|
||||
.setShowPattern(ShowPattern.CURRENT_ACTIVITY)
|
||||
.registerCallback {
|
||||
createResult { _, _, view ->
|
||||
val titleView = view?.findViewById<TextView>(R.id.titleTv)
|
||||
|
||||
view?.setOnClickListener {
|
||||
// 先收起键盘
|
||||
Util_System_Keyboard.hideSoftKeyboard(activity)
|
||||
|
||||
if (mType == TYPE_ACTIVITY) {
|
||||
titleView?.text = "返回活动"
|
||||
|
||||
DirectUtils.directToWebView(activity, mActivityUrl, ("返回活动浮窗"))
|
||||
} else if (mType == TYPE_TASK) {
|
||||
titleView?.text = "返回任务"
|
||||
|
||||
activity.startActivity(EnergyCenterActivity.getIntent(activity))
|
||||
}
|
||||
|
||||
disableBackView()
|
||||
}
|
||||
}
|
||||
|
||||
dragEnd { view ->
|
||||
val statusBarHeight = DisplayUtils.getStatusBarHeight(activity.resources)
|
||||
|
||||
// 记录停止拖动的最后位置
|
||||
val outLocation = IntArray(2)
|
||||
view.getLocationInWindow(outLocation)
|
||||
val yOffset = outLocation[1]
|
||||
|
||||
if (yOffset <= statusBarHeight) {
|
||||
// 判断状态栏是否被消费
|
||||
if (yOffset == view.y.toInt()) {
|
||||
view.y = statusBarHeight.toFloat()
|
||||
} else {
|
||||
view.y = 0F
|
||||
}
|
||||
}
|
||||
|
||||
mLastPositionY = yOffset
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏返回小浮窗
|
||||
*/
|
||||
@JvmStatic
|
||||
fun dismissBackView(activity: Activity) {
|
||||
EasyFloat.dismiss(activity, FLOATING_BACK_VIEW)
|
||||
}
|
||||
|
||||
fun getType(): String {
|
||||
return mType
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用返回小浮窗
|
||||
* @param type 类型
|
||||
* @param activityUrl 类型为活动的时候用的地址
|
||||
*/
|
||||
fun enableBackView(type: String, activityUrl: String = "") {
|
||||
mType = type
|
||||
mActivityUrl = activityUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用返回小浮窗
|
||||
* @param type 类型
|
||||
* @param activityUrl 类型为活动的时候用的地址
|
||||
*/
|
||||
@JvmStatic
|
||||
fun disableBackView() {
|
||||
mType = ""
|
||||
mActivityUrl = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回小浮窗类型是否为活动
|
||||
*/
|
||||
fun isTypeActivity() : Boolean {
|
||||
return mType == TYPE_ACTIVITY
|
||||
}
|
||||
|
||||
}
|
||||
@ -93,6 +93,13 @@ object GameSubstituteRepositoryHelper {
|
||||
val game = collection.data?.find { game -> isThisGameUnique(game, gameIdList) }
|
||||
game?.let {
|
||||
collection.data?.remove(game)
|
||||
|
||||
collection.data?.size?.let { remainingSize ->
|
||||
// 记录被替换游戏的数量,10个以上的时候触发
|
||||
if (remainingSize % 10 == 0) {
|
||||
SentryHelper.onEvent("game_substitute", "substituted_size", "${50 - remainingSize}")
|
||||
}
|
||||
}
|
||||
// 产品说要记录补充专题的曝光数,所以这个游戏附带了所在专题的名字
|
||||
game.subjectName = collection.name
|
||||
return game
|
||||
|
||||
@ -34,6 +34,10 @@ import java.util.TimeZone;
|
||||
public class GameViewUtils {
|
||||
|
||||
public static void setLabelList(Context context, LinearLayout labelLayout, List<TagStyleEntity> tagStyle) {
|
||||
setLabelList(context, labelLayout, tagStyle, 8);
|
||||
}
|
||||
|
||||
public static void setLabelList(Context context, LinearLayout labelLayout, List<TagStyleEntity> tagStyle, int margin) {
|
||||
labelLayout.removeAllViews();
|
||||
if (tagStyle == null || tagStyle.isEmpty()) {
|
||||
// 没有数据的话默认不显示
|
||||
@ -42,7 +46,7 @@ public class GameViewUtils {
|
||||
// labelLayout.addView(getNewGameTagView(context, tagEntity, 0));
|
||||
} else {
|
||||
for (int i = 0, size = tagStyle.size(); i < size; i++) {
|
||||
View view = getNewGameTagView(context, tagStyle.get(i), i == size - 1 ? 0 : DisplayUtils.dip2px(context, 8));
|
||||
View view = getNewGameTagView(context, tagStyle.get(i), i == size - 1 ? 0 : DisplayUtils.dip2px(context, margin));
|
||||
labelLayout.addView(view);
|
||||
if (labelLayout.getChildCount() == 3) {
|
||||
break;
|
||||
|
||||
@ -8,6 +8,7 @@ import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.facebook.common.executors.CallerThreadExecutor
|
||||
@ -19,6 +20,7 @@ import com.facebook.drawee.controller.ControllerListener
|
||||
import com.facebook.drawee.drawable.ScalingUtils
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.facebook.imagepipeline.common.ResizeOptions
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
@ -26,14 +28,16 @@ import com.facebook.imagepipeline.request.ImageRequest
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import com.facebook.imagepipeline.request.Postprocessor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.runOnUiThread
|
||||
import com.gh.common.structure.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.R
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import com.squareup.picasso.Picasso
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.*
|
||||
|
||||
object ImageUtils {
|
||||
|
||||
@ -90,7 +94,7 @@ object ImageUtils {
|
||||
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
|
||||
val webpConfig = Config.getSettings()?.image?.oss?.webp
|
||||
?: Config.getSettings()?.image?.oss?.gif
|
||||
if (jpegConfig != null) {
|
||||
if (imageUrl?.contains("?x-oss-process") == false && jpegConfig != null) {
|
||||
return if (width == 0 || width == null) {
|
||||
"$imageUrl$webpConfig"
|
||||
} else {
|
||||
@ -308,7 +312,7 @@ object ImageUtils {
|
||||
if (url == null) return
|
||||
|
||||
// 部分自适应宽高图片需要一个 TARGET_WIDTH 来避免加载过小图片
|
||||
val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.layoutParams?.width
|
||||
val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.width?.coerceAtLeast(view.layoutParams?.width ?: 0)
|
||||
val height = view?.layoutParams?.height
|
||||
|
||||
var lowResUrl = ""
|
||||
@ -452,6 +456,19 @@ object ImageUtils {
|
||||
draweeView.setImageURI("res:///" + res)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun displayResizeMedia(draweeView: SimpleDraweeView, url: String, resizeWidthDp: Int, resizeHeightDp: Int) {
|
||||
val request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
|
||||
.setResizeOptions(ResizeOptions(resizeWidthDp, resizeHeightDp))
|
||||
.build()
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(request)
|
||||
.setOldController(draweeView.controller)
|
||||
.setControllerListener(BaseControllerListener<ImageInfo>())
|
||||
.build()
|
||||
draweeView.controller = controller
|
||||
}
|
||||
|
||||
//预加载图片
|
||||
@JvmStatic
|
||||
fun prefetchToDiskCache(url: String) {
|
||||
@ -482,7 +499,7 @@ object ImageUtils {
|
||||
}
|
||||
|
||||
fun getVideoSnapshot(videoUrl: String, progress: Long): String {
|
||||
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0"
|
||||
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0,ar_auto"
|
||||
}
|
||||
|
||||
/**
|
||||
@ -494,7 +511,7 @@ object ImageUtils {
|
||||
val clazz = SimpleDraweeView::class.java
|
||||
return try {
|
||||
val field =
|
||||
clazz.getDeclaredField("sDraweecontrollerbuildersupplier")
|
||||
clazz.getDeclaredField("sDraweecontrollerbuildersupplier")
|
||||
field.isAccessible = true
|
||||
val obj = field[SimpleDraweeView::class.java]
|
||||
obj != null
|
||||
@ -502,4 +519,50 @@ object ImageUtils {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将图片保存到外部存储空间
|
||||
* @param imageFile 内部存储的文件
|
||||
* @param url 图片原地址,用来截取当图片名称用的
|
||||
* @param useRandomName 是否使用随机名称
|
||||
*/
|
||||
fun saveImageToFile(imageFile: File, url: String?, useRandomName: Boolean = false) {
|
||||
var `in`: InputStream? = null
|
||||
var out: OutputStream? = null
|
||||
try {
|
||||
val fileName: String = if (useRandomName) {
|
||||
MD5Utils.getContentMD5(System.currentTimeMillis().toString()) + ".png"
|
||||
} else {
|
||||
Uri.parse(url).lastPathSegment.toString()
|
||||
}
|
||||
val savePath = Environment.getExternalStorageDirectory().absolutePath + "/Pictures/ghzhushou/"
|
||||
val file = File(savePath)
|
||||
if (!file.exists()) {
|
||||
file.mkdirs()
|
||||
}
|
||||
val dst = File(savePath, fileName)
|
||||
if (dst.exists()) {
|
||||
dst.delete()
|
||||
}
|
||||
`in` = FileInputStream(imageFile)
|
||||
out = FileOutputStream(dst)
|
||||
val buf = ByteArray(1024)
|
||||
var len: Int
|
||||
while (`in`.read(buf).also { len = it } > 0) {
|
||||
out.write(buf, 0, len)
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
ToastUtils.toast("图片已保存到/Pictures/ghzhushou/")
|
||||
}
|
||||
MessageShareUtils.refreshImage(HaloApp.getInstance(), dst)
|
||||
} catch (e: Exception) {
|
||||
Utils.log("图片保存失败:$e")
|
||||
} finally {
|
||||
tryWithDefaultCatch {
|
||||
out?.close()
|
||||
`in`?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,16 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.gh.gamecenter.NormalActivity;
|
||||
import com.gh.gamecenter.SingletonWebActivity;
|
||||
import com.gh.gamecenter.WebActivity;
|
||||
import com.gh.gamecenter.category.CategoryListActivity;
|
||||
import com.gh.gamecenter.entity.CategoryEntity;
|
||||
import com.halo.assistant.fragment.WebFragment;
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
@ -17,7 +23,6 @@ import com.gh.gamecenter.entity.CategoryEntity;
|
||||
|
||||
public class IntentUtils {
|
||||
|
||||
|
||||
public static Intent getWifiIntent() {
|
||||
return new Intent("android.settings.WIFI_SETTINGS");
|
||||
}
|
||||
@ -61,4 +66,19 @@ public class IntentUtils {
|
||||
DataUtils.onMtaEvent(context, "分类大全", categoryTitle, category.getName());
|
||||
context.startActivity(CategoryListActivity.Companion.getIntent(context, categoryTitle, category, "全部"));
|
||||
}
|
||||
|
||||
public static Intent getWebTargetIntent(Context context, Bundle bundle, String url) {
|
||||
Class<? extends NormalActivity> cls;
|
||||
|
||||
if (url.contains("android_page_type=singleton")) {
|
||||
cls = SingletonWebActivity.class;
|
||||
} else {
|
||||
cls = WebActivity.class;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, cls);
|
||||
intent.putExtra(NormalActivity.NORMAL_FRAGMENT_NAME, WebFragment.class.getCanonicalName());
|
||||
intent.putExtra(NormalActivity.NORMAL_FRAGMENT_BUNDLE, bundle);
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,8 +91,10 @@ public class KeyboardHeightProvider extends PopupWindow {
|
||||
* of the Activity.
|
||||
*/
|
||||
public void start() {
|
||||
|
||||
if (!isShowing() && parentView.getWindowToken() != null) {
|
||||
if (!isShowing()
|
||||
&& parentView.getWindowToken() != null
|
||||
&& activity != null
|
||||
&& !activity.isFinishing()) {
|
||||
setBackgroundDrawable(new ColorDrawable(0));
|
||||
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
|
||||
}
|
||||
|
||||
1131
app/src/main/java/com/gh/common/util/NewLogUtils.kt
Normal file
1131
app/src/main/java/com/gh/common/util/NewLogUtils.kt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
@ -46,7 +45,7 @@ object PackageInstaller {
|
||||
|
||||
// TODO 此处可能遇到 activity 是 WXEntryActivity
|
||||
// TODO 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装!
|
||||
if (currentActivity is AppCompatActivity) {
|
||||
if (currentActivity is AppCompatActivity && !currentActivity.isFinishing) {
|
||||
InstallPermissionDialogFragment.show(currentActivity, downloadEntity) {
|
||||
// 取消状态栏下载完成的通知,若存在
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
@ -125,7 +124,7 @@ object PackageInstaller {
|
||||
// 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现
|
||||
// Application 上下文就更不用说了
|
||||
val pkgName = PackageUtils.getPackageNameByPath(context, path)
|
||||
if (pkgName == context.packageName || context is Application) {
|
||||
if (pkgName == context.packageName || context !is Activity) {
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
|
||||
@ -45,7 +45,9 @@ import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
@ -158,6 +160,42 @@ public class PackageUtils {
|
||||
return getMetaData(HaloApp.getInstance().getApplication(), packageName, "gh_id");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Map<String, String> getSideLoadedInfo() {
|
||||
Context context = HaloApp.getInstance().getApplicationContext();
|
||||
|
||||
String packageName = null;
|
||||
try {
|
||||
final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
|
||||
if (packageInfo != null && packageManager != null) {
|
||||
packageName = packageInfo.packageName;
|
||||
|
||||
// getInstallSourceInfo requires INSTALL_PACKAGES permission which is only given to system
|
||||
// apps.
|
||||
final String installerPackageName = packageManager.getInstallerPackageName(packageName);
|
||||
|
||||
final Map<String, String> sideLoadedInfo = new HashMap<>();
|
||||
|
||||
if (installerPackageName != null) {
|
||||
sideLoadedInfo.put("is_side_loaded", "false");
|
||||
// could be amazon, google play etc
|
||||
sideLoadedInfo.put("installer_store", installerPackageName);
|
||||
} else {
|
||||
// if it's installed via adb, system apps or untrusted sources
|
||||
sideLoadedInfo.put("is_side_loaded", "true");
|
||||
}
|
||||
|
||||
return sideLoadedInfo;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Utils.log(e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 判断是否是插件包
|
||||
@ -668,29 +706,34 @@ public class PackageUtils {
|
||||
* 应用是否在前台运行
|
||||
*/
|
||||
public static boolean isAppOnForeground(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getApplicationContext()
|
||||
.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (activityManager == null) return false;
|
||||
try {
|
||||
ActivityManager activityManager = (ActivityManager) context.getApplicationContext()
|
||||
.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (activityManager == null) return false;
|
||||
|
||||
List<ActivityManager.RunningAppProcessInfo> appProcesses =
|
||||
activityManager.getRunningAppProcesses();
|
||||
if (appProcesses == null) return false;
|
||||
List<ActivityManager.RunningAppProcessInfo> appProcesses =
|
||||
activityManager.getRunningAppProcesses();
|
||||
if (appProcesses == null) return false;
|
||||
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
if (pm == null) return false;
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
|
||||
if (!pm.isInteractive()) return false;
|
||||
} else {
|
||||
if (!pm.isScreenOn()) return false;
|
||||
}
|
||||
|
||||
String packageName = context.getApplicationContext().getPackageName();
|
||||
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
|
||||
// The name of the process that this object is associated with.
|
||||
if (appProcess.processName.equals(packageName) && appProcess.importance
|
||||
== ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
|
||||
return true;
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
if (pm == null) return false;
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
|
||||
if (!pm.isInteractive()) return false;
|
||||
} else {
|
||||
if (!pm.isScreenOn()) return false;
|
||||
}
|
||||
|
||||
String packageName = context.getApplicationContext().getPackageName();
|
||||
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
|
||||
// The name of the process that this object is associated with.
|
||||
if (appProcess.processName.equals(packageName) && appProcess.importance
|
||||
== ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -117,6 +117,7 @@ public class PostCommentUtils {
|
||||
String articleId,
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
final String commentId,
|
||||
final PostCommentListener listener) {
|
||||
|
||||
@ -126,6 +127,8 @@ public class PostCommentUtils {
|
||||
observable = RetrofitManager.getInstance(context).getApi().postVoteAnswerComment(answerId, commentId);
|
||||
} else if (!TextUtils.isEmpty(articleId)) {
|
||||
observable = RetrofitManager.getInstance(context).getApi().postVoteCommunityArticleComment(articleCommunityId, articleId, commentId);
|
||||
} else if (!TextUtils.isEmpty(questionId)) {
|
||||
observable = RetrofitManager.getInstance(context).getApi().postVoteQuestionComment(questionId, commentId);
|
||||
} else {
|
||||
observable = RetrofitManager.getInstance(context).getApi().postVoteToVideo(videoId, commentId);
|
||||
}
|
||||
@ -258,6 +261,28 @@ public class PostCommentUtils {
|
||||
}
|
||||
});
|
||||
}
|
||||
public static void reportQuestionComment(final Context context,
|
||||
final String questionId,
|
||||
final String commentId,
|
||||
final String reportData,
|
||||
final PostCommentListener listener) {
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), reportData);
|
||||
RetrofitManager.getInstance(context).getApi()
|
||||
.postQuestionCommentReport(questionId, 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);
|
||||
|
||||
@ -52,6 +52,31 @@ object QuickLoginHelper {
|
||||
private const val ENTRANCE_PERMISSION_DIALOG = "一键登录权限弹窗"
|
||||
private const val AUTH_ACTIVITY_NAME = "com.cmic.sso.sdk.activity.LoginAuthActivity"
|
||||
|
||||
// 1.取号请求(可提前进行)
|
||||
@JvmStatic
|
||||
fun getPhoneInfo(context: Context) {
|
||||
if (isPublishEnv()) {
|
||||
AuthnHelper.setDebugMode(false)
|
||||
} else {
|
||||
AuthnHelper.setDebugMode(true)
|
||||
}
|
||||
|
||||
AuthnHelper.getInstance(context.applicationContext).getPhoneInfo(
|
||||
Config.QUICK_LOGIN_APPID,
|
||||
Config.QUICK_LOGIN_APPKEY,
|
||||
{ requestCode: Int, jsonObject: JSONObject ->
|
||||
val code = jsonObject.optString("resultCode")
|
||||
// “103000”为成功
|
||||
if (code == "103000") {
|
||||
if (requestCode == REQUEST_GET_PHONE_INFO_CODE) {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_GET_PHONE_INFO, true)
|
||||
}
|
||||
}
|
||||
},
|
||||
REQUEST_GET_PHONE_INFO_CODE
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startLogin(context: Context, entrance: String) {
|
||||
// 防止短时间多次调用
|
||||
@ -64,8 +89,45 @@ object QuickLoginHelper {
|
||||
} else {
|
||||
AuthnHelper.setDebugMode(true)
|
||||
}
|
||||
|
||||
if (mAuthnHelper == null) {
|
||||
initSDK(context, entrance)
|
||||
}
|
||||
|
||||
if (mTokenListener == null) {
|
||||
initTokenListener(context)
|
||||
}
|
||||
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
loginAuth(context)
|
||||
} else {
|
||||
DialogUtils.showQuickLoginPermissionDialog(
|
||||
context,
|
||||
{
|
||||
checkReadPhoneStatePermissionBeforeAction(context, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
loginAuth(context)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
startCodeLoginPage(
|
||||
context,
|
||||
entrance = ENTRANCE_PERMISSION_DIALOG,
|
||||
isFinishAuth = false,
|
||||
isFromPermission = true
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSDK(context: Context, entrance: String) {
|
||||
mAuthnHelper = AuthnHelper.getInstance(context.applicationContext)
|
||||
mAuthnHelper?.run {
|
||||
// 设置超时时间
|
||||
overTime = 3000
|
||||
|
||||
authThemeConfig = getConfig(context, entrance)
|
||||
// 授权页面的回调方法
|
||||
setPageInListener { code, _ ->
|
||||
@ -80,56 +142,27 @@ object QuickLoginHelper {
|
||||
startCodeLoginPage(context, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// token回调
|
||||
mTokenListener = TokenListener { requestCode: Int, jsonObject: JSONObject ->
|
||||
val code = jsonObject.optString("resultCode")
|
||||
// “103000”为成功
|
||||
if (code == "103000") {
|
||||
when (requestCode) {
|
||||
REQUEST_GET_PHONE_INFO_CODE -> {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_GET_PHONE_INFO, true)
|
||||
// 2.授权请求
|
||||
mAuthnHelper!!.loginAuth(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_LOGIN_AUTH_CODE)
|
||||
}
|
||||
|
||||
REQUEST_LOGIN_AUTH_CODE -> {
|
||||
// 3.获取token
|
||||
mToken = jsonObject.optString("token")
|
||||
}
|
||||
}
|
||||
} else if (code != "200020") { // 不成功就调起验证码登录页(200020代表授权页关闭)
|
||||
toastCode(code)
|
||||
startCodeLoginPage(context, true)
|
||||
private fun initTokenListener(context: Context) {
|
||||
// token回调
|
||||
mTokenListener = TokenListener { requestCode: Int, jsonObject: JSONObject ->
|
||||
val code = jsonObject.optString("resultCode")
|
||||
// “103000”为成功
|
||||
if (code == "103000") {
|
||||
if (requestCode == REQUEST_LOGIN_AUTH_CODE) {
|
||||
// 3.获取token
|
||||
mToken = jsonObject.optString("token")
|
||||
}
|
||||
}
|
||||
|
||||
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
getPhoneInfo(context)
|
||||
} else {
|
||||
DialogUtils.showQuickLoginPermissionDialog(
|
||||
context,
|
||||
{
|
||||
checkReadPhoneStatePermissionBeforeAction(context, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
getPhoneInfo(context)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
startCodeLoginPage(
|
||||
context,
|
||||
entrance = ENTRANCE_PERMISSION_DIALOG,
|
||||
isFinishAuth = false,
|
||||
isFromPermission = true
|
||||
)
|
||||
}
|
||||
)
|
||||
} else if (code != "200020") { // 不成功就调起验证码登录页(200020代表授权页关闭)
|
||||
toastCode(code)
|
||||
startCodeLoginPage(context, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPhoneInfo(context: Context) {
|
||||
private fun loginAuth(context: Context) {
|
||||
mPreDialog = Dialog(context, R.style.DialogWindowTransparent).apply {
|
||||
val binding = SetWaitDialogBinding.inflate(LayoutInflater.from(context)).apply {
|
||||
setWaitMessage.text = "请求登录中"
|
||||
@ -139,8 +172,8 @@ object QuickLoginHelper {
|
||||
setCanceledOnTouchOutside(false)
|
||||
show()
|
||||
}
|
||||
// 1.取号请求
|
||||
mAuthnHelper!!.getPhoneInfo(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_GET_PHONE_INFO_CODE)
|
||||
// 2.授权请求
|
||||
mAuthnHelper?.loginAuth(Config.QUICK_LOGIN_APPID, Config.QUICK_LOGIN_APPKEY, mTokenListener, REQUEST_LOGIN_AUTH_CODE)
|
||||
}
|
||||
|
||||
private fun getConfig(context: Context, entrance: String): AuthThemeConfig{
|
||||
|
||||
@ -148,6 +148,11 @@ public class ShareUtils {
|
||||
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("成功", mShareType.getName());
|
||||
}
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal ||
|
||||
ShareUtils.shareEntrance == ShareEntrance.communityArticle ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
|
||||
NewLogUtils.logShareResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,6 +163,11 @@ public class ShareUtils {
|
||||
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("失败", mShareType.getName());
|
||||
}
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal ||
|
||||
ShareUtils.shareEntrance == ShareEntrance.communityArticle ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
|
||||
NewLogUtils.logShareResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,6 +178,11 @@ public class ShareUtils {
|
||||
if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("取消", mShareType.getName());
|
||||
}
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal ||
|
||||
ShareUtils.shareEntrance == ShareEntrance.communityArticle ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
|
||||
NewLogUtils.logShareResult(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -215,23 +230,23 @@ public class ShareUtils {
|
||||
|
||||
// 分享
|
||||
switch (way) {
|
||||
case "qq" :
|
||||
case "qq":
|
||||
mShareType = ShareType.qq;
|
||||
qqShare();
|
||||
break;
|
||||
case "qq_zone" :
|
||||
case "qq_zone":
|
||||
mShareType = ShareType.qqZone;
|
||||
qZoneShare();
|
||||
break;
|
||||
case "wechat" :
|
||||
case "wechat":
|
||||
mShareType = ShareType.wechat;
|
||||
wechatShare();
|
||||
break;
|
||||
case "wechat_moments" :
|
||||
case "wechat_moments":
|
||||
mShareType = ShareType.wechatMoments;
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case "weibo" :
|
||||
case "weibo":
|
||||
mShareType = ShareType.weibo;
|
||||
sinaWeiboShare();
|
||||
break;
|
||||
@ -409,6 +424,11 @@ public class ShareUtils {
|
||||
//QQ分享
|
||||
public void qqShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
|
||||
mShareType = ShareType.qq;
|
||||
shareType = "qq_friend";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
Bundle params = new Bundle();
|
||||
|
||||
switch (mShareEntrance) {
|
||||
@ -445,6 +465,10 @@ public class ShareUtils {
|
||||
public void wechatShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
|
||||
shareType = "wechat_friend";
|
||||
mShareType = ShareType.wechat;
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
|
||||
Utils.toast(mContext, "没安装微信,分享失败");
|
||||
return;
|
||||
@ -561,6 +585,12 @@ public class ShareUtils {
|
||||
//QQ空间分享
|
||||
public void qZoneShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
|
||||
mShareType = ShareType.qqZone;
|
||||
shareType = "qq_zone";
|
||||
MtaHelper.onEvent("内容分享", "QQ空间", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
Bundle params = new Bundle();
|
||||
|
||||
switch (mShareEntrance) {
|
||||
@ -601,6 +631,10 @@ public class ShareUtils {
|
||||
public void wechatMomentsShare() {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
|
||||
mShareType = ShareType.wechatMoments;
|
||||
shareType = "wechat_moment";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
if (!PackageHelper.INSTANCE.getLocalPackageNameSet().contains("com.tencent.mm")) {
|
||||
Utils.toast(mContext, "没安装微信,分享失败");
|
||||
return;
|
||||
@ -642,6 +676,10 @@ public class ShareUtils {
|
||||
|
||||
//新浪微博分享
|
||||
public void sinaWeiboShare() {
|
||||
mShareType = ShareType.weibo;
|
||||
shareType = "sina_weibo";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
|
||||
|
||||
if (mShareEntrance == ShareEntrance.qaDetail) {
|
||||
@ -668,6 +706,10 @@ public class ShareUtils {
|
||||
|
||||
//短信分享
|
||||
public void shortMessageShare() {
|
||||
mShareType = ShareType.weibo;
|
||||
shareType = "sms";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
String smsBody;
|
||||
switch (mShareEntrance) {
|
||||
case news:
|
||||
@ -714,6 +756,7 @@ public class ShareUtils {
|
||||
public void copyLink(String copyContent) {
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
LogUtils.uploadShareResult(shareType, shareEntrance.getName(), "success", shareUrl, mTitle, mSummary, resourceId);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
ExtensionsKt.copyTextAndToast(copyContent, "复制成功");
|
||||
safelyDismiss();
|
||||
@ -749,50 +792,34 @@ public class ShareUtils {
|
||||
holder.shareLogo.setImageResource(arrLogo[position]);
|
||||
holder.shareLabel.setText(arrLabel[position]);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mShareEntrance == ShareEntrance.shareGh) {
|
||||
MtaHelper.onEvent("我的光环_新", "分享光环", arrLabel[position]);
|
||||
}
|
||||
if (listener != null) {
|
||||
listener.onItemClick(holder.getAdapterPosition());
|
||||
}
|
||||
|
||||
switch (holder.getPosition()) {
|
||||
case 0:
|
||||
shareType = "wechat_friend";
|
||||
MtaHelper.onEvent("内容分享", "微信好友", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
wechatShare();
|
||||
break;
|
||||
case 1:
|
||||
shareType = "wechat_moment";
|
||||
MtaHelper.onEvent("内容分享", "微信朋友圈", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case 2:
|
||||
shareType = "qq_friend";
|
||||
MtaHelper.onEvent("内容分享", "QQ好友", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
qqShare();
|
||||
break;
|
||||
case 3:
|
||||
shareType = "qq_zone";
|
||||
MtaHelper.onEvent("内容分享", "QQ空间", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
qZoneShare();
|
||||
break;
|
||||
case 4:
|
||||
shareType = "sina_weibo";
|
||||
MtaHelper.onEvent("内容分享", "新浪微博", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
sinaWeiboShare();
|
||||
break;
|
||||
case 5:
|
||||
MtaHelper.onEvent("内容分享", "短信", mTitle);
|
||||
shortMessageShare();
|
||||
break;
|
||||
case 6:
|
||||
MtaHelper.onEvent("内容分享", "复制链接", mTitle);
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
LogUtils.uploadShareResult(shareType, shareEntrance.getName(), "success", shareUrl, mTitle, mSummary, resourceId);
|
||||
|
||||
if (mShareEntrance == ShareEntrance.askInvite) {
|
||||
copyLink(mTitle + " - 光环助手" + shareUrl);
|
||||
} else if (mShareEntrance == ShareEntrance.askNormal || mShareEntrance == ShareEntrance.answerNormal) {
|
||||
@ -815,6 +842,7 @@ public class ShareUtils {
|
||||
} else {
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
LogUtils.uploadShareResult(shareType, shareEntrance.getName(), "success", shareUrl, mTitle, mSummary, resourceId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.common.util
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
@ -70,6 +71,13 @@ class SpanBuilder(content: CharSequence) {
|
||||
return this
|
||||
}
|
||||
|
||||
//添加图标
|
||||
fun image(start: Int, end: Int, drawable: Drawable): SpanBuilder {
|
||||
val imageSpan = CenterImageSpan(drawable)
|
||||
spannableString.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return this
|
||||
}
|
||||
|
||||
fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder {
|
||||
val clickSpan = object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
|
||||
@ -27,6 +27,7 @@ import java.lang.Exception
|
||||
object UploadImageUtils {
|
||||
|
||||
enum class UploadType {
|
||||
community_article,
|
||||
question,
|
||||
answer,
|
||||
suggestion,
|
||||
@ -179,7 +180,10 @@ object UploadImageUtils {
|
||||
}
|
||||
|
||||
override fun onNext(t: Map<String, String>) {
|
||||
if (t.isNotEmpty()) postImageList.putAll(t)
|
||||
if (t.isNotEmpty()){
|
||||
listener.onSingleSuccess(t)
|
||||
postImageList.putAll(t)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(ignore: Throwable) {
|
||||
@ -293,6 +297,7 @@ object UploadImageUtils {
|
||||
|
||||
interface OnUploadImageListListener {
|
||||
fun onSuccess(imageUrl: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) // key:sourceImage value:compressImage
|
||||
fun onSingleSuccess(imageUrl: Map<String, String>)
|
||||
fun onCompressSuccess(imageUrls: List<String>) {}
|
||||
fun onError(errorMap: Map<String, Exception>) // 全部上传失败时回调
|
||||
fun onProgress(total: Long, progress: Long)
|
||||
|
||||
@ -148,7 +148,7 @@ class AvatarBorderView : ConstraintLayout {
|
||||
}
|
||||
}
|
||||
|
||||
fun displayUserBadge(badgeUrl: String? = "") {
|
||||
private fun displayUserBadge(badgeUrl: String? = "") {
|
||||
if (badgeUrl.isNullOrEmpty()) {
|
||||
badgeView?.setImageURI("")
|
||||
badgeView?.visibility = View.GONE
|
||||
|
||||
@ -30,6 +30,7 @@ class CategoryFilterView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
private var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
|
||||
private var mOnCategoryFilterSetupListener: OnCategoryFilterSetupListener? = null
|
||||
private var mOnFilterClickListener: OnFilterClickListener? = null
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.layout_category_filter, this)
|
||||
@ -43,14 +44,17 @@ class CategoryFilterView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
mTypeTv.text = mTypeFilterArray[0].value
|
||||
|
||||
mTypeContainer.setOnClickListener {
|
||||
mOnFilterClickListener?.onTypeClick()
|
||||
showSelectTypePopupWindow(this, mTypeTv, mTypeTv.text.toString())
|
||||
}
|
||||
|
||||
mCatalogContainer.setOnClickListener {
|
||||
mOnFilterClickListener?.onCategoryClick()
|
||||
mOnCategoryFilterSetupListener?.onSetupSortCategory()
|
||||
}
|
||||
|
||||
mSizeContainer.setOnClickListener {
|
||||
mOnFilterClickListener?.onSizeClick()
|
||||
showSelectSizePopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
}
|
||||
}
|
||||
@ -59,6 +63,14 @@ class CategoryFilterView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
mOnCategoryFilterSetupListener = onCategoryFilterSetupListener
|
||||
}
|
||||
|
||||
fun setOnFilterClickListener(onFilterClickListener: OnFilterClickListener) {
|
||||
mOnFilterClickListener = onFilterClickListener
|
||||
}
|
||||
|
||||
fun resetSortSize() {
|
||||
mSizeTv.text = "全部大小"
|
||||
}
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.bg_tag_text)
|
||||
@ -218,6 +230,12 @@ class CategoryFilterView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
fun onSetupSortCategory()
|
||||
}
|
||||
|
||||
interface OnFilterClickListener {
|
||||
fun onCategoryClick()
|
||||
fun onTypeClick()
|
||||
fun onSizeClick()
|
||||
}
|
||||
|
||||
enum class SortType(val value: String) {
|
||||
RECOMMENDED("热门推荐"),
|
||||
NEWEST("最新上线"),
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CustomDividerItemDecoration(
|
||||
context: Context,
|
||||
@ -13,6 +15,7 @@ class CustomDividerItemDecoration(
|
||||
var notDecorateTheFirstItem: Boolean = false,
|
||||
var notDecorateTheLastItem: Boolean = false,
|
||||
var notDecorateTheFirstTwoItems: Boolean = false) : DividerItemDecoration(context, LinearLayout.VERTICAL) {
|
||||
private val mBounds = Rect()
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
if (onlyDecorateTheFirstItem) {
|
||||
@ -31,4 +34,42 @@ class CustomDividerItemDecoration(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
if (parent.layoutManager == null || drawable == null) {
|
||||
return
|
||||
}
|
||||
drawVertical(c, parent)
|
||||
}
|
||||
|
||||
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
|
||||
canvas.save()
|
||||
val left: Int
|
||||
val right: Int
|
||||
if (parent.clipToPadding) {
|
||||
left = parent.paddingLeft
|
||||
right = parent.width - parent.paddingRight
|
||||
canvas.clipRect(left, parent.paddingTop, right,
|
||||
parent.height - parent.paddingBottom)
|
||||
} else {
|
||||
left = 0
|
||||
right = parent.width
|
||||
}
|
||||
val childCount = parent.childCount
|
||||
for (i in 0 until childCount) {
|
||||
val child = parent.getChildAt(i)
|
||||
parent.getDecoratedBoundsWithMargins(child, mBounds)
|
||||
var bottom = mBounds.bottom + child.translationY.roundToInt()
|
||||
val rect = Rect()
|
||||
getItemOffsets(rect, child, parent, RecyclerView.State())
|
||||
val top = if (rect.bottom > 0) {
|
||||
bottom - (drawable?.intrinsicHeight ?: 0)
|
||||
} else {
|
||||
bottom = 0
|
||||
0
|
||||
}
|
||||
drawable?.setBounds(left, top, right, bottom)
|
||||
drawable?.draw(canvas)
|
||||
}
|
||||
canvas.restore()
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,8 @@ import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.sp2px
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.TagStyleEntity
|
||||
import kotlin.math.ceil
|
||||
@ -23,16 +25,27 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
|
||||
private var mTotalCount = 0
|
||||
private var mTags = ArrayList<TagStyleEntity>()
|
||||
private var mItemHeight = DisplayUtils.dip2px(20F)
|
||||
private var mPadding = DisplayUtils.dip2px(5F)
|
||||
private var mMargin = DisplayUtils.dip2px(4F)
|
||||
private var mItemHeight = 0
|
||||
private var mPadding = 0
|
||||
private var mMargin = 0
|
||||
private var mTextSize = 10F
|
||||
private var mLastItemWidth = DisplayUtils.dip2px(18F)//最后更多按钮宽度
|
||||
private var mLastItemWidth = 0//最后更多按钮宽度
|
||||
private var mTotalWidth = 0
|
||||
private var mStrokeWidth = 0
|
||||
var onClickListener: OnItemClickListener? = null
|
||||
|
||||
init {
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
|
||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.FlexLinearLayout)
|
||||
mItemHeight = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_itemHeight, 20f.dip2px())
|
||||
mPadding = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_itemPadding, 5f.dip2px())
|
||||
mMargin = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_itemMargin, 4f.dip2px())
|
||||
mTextSize = ta.getDimension(R.styleable.FlexLinearLayout_itemTextSize, 10f.sp2px().toFloat())
|
||||
mLastItemWidth = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_lastItemWidth, 18f.dip2px())
|
||||
mStrokeWidth = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_strokeWidth, 1f.dip2px())
|
||||
|
||||
ta.recycle()
|
||||
}
|
||||
|
||||
fun setTags(tags: ArrayList<TagStyleEntity>) {
|
||||
@ -40,7 +53,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
mTotalCount = tags.size
|
||||
mTotalWidth = measuredWidth
|
||||
val paint = Paint()
|
||||
paint.textSize = DisplayUtils.sp2px(context, mTextSize).toFloat()
|
||||
paint.textSize = mTextSize
|
||||
|
||||
var currentWidth = mLastItemWidth.toFloat()
|
||||
tags.forEach {
|
||||
@ -79,7 +92,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
layoutParams = params
|
||||
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_game_detail_label_more))
|
||||
background = createBackgroundDrawable()
|
||||
scaleType=ImageView.ScaleType.CENTER
|
||||
scaleType = ImageView.ScaleType.CENTER
|
||||
}
|
||||
imageView.setOnClickListener {
|
||||
onClickListener?.onMoreClickListener()
|
||||
@ -92,7 +105,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
return TextView(context).apply {
|
||||
text = tag.name
|
||||
includeFontPadding = false
|
||||
textSize = mTextSize
|
||||
textSize = DisplayUtils.px2sp(context, mTextSize).toFloat()
|
||||
gravity = Gravity.CENTER
|
||||
setTextColor(Color.parseColor("#333333"))
|
||||
|
||||
@ -112,7 +125,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
private fun createBackgroundDrawable(): GradientDrawable {
|
||||
val gradientDrawable = GradientDrawable()
|
||||
gradientDrawable.setColor(Color.TRANSPARENT)
|
||||
gradientDrawable.setStroke(DisplayUtils.dip2px(context, 1f), Color.parseColor("#C2C6CC"))
|
||||
gradientDrawable.setStroke(mStrokeWidth, Color.parseColor("#C2C6CC"))
|
||||
gradientDrawable.cornerRadius = DisplayUtils.dip2px(2f).toFloat()
|
||||
return gradientDrawable
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import com.gh.common.util.*
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.ItemCommunityImageBinding
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.CommunityVideoEntity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
@ -72,7 +73,9 @@ class ImageContainerView : LinearLayout {
|
||||
mPath = path
|
||||
index = 0
|
||||
removeAllViews()
|
||||
if (entity.getPassVideos().isNullOrEmpty() && entity.images.isNullOrEmpty()) {
|
||||
if ((entity.user.id == UserManager.getInstance().userId && entity.videos.isNotEmpty())
|
||||
|| (entity.user.id != UserManager.getInstance().userId && entity.getPassVideos().isNotEmpty())
|
||||
|| entity.images.isNullOrEmpty()) {
|
||||
visibility = View.GONE
|
||||
return
|
||||
}
|
||||
@ -155,6 +158,8 @@ class ImageContainerView : LinearLayout {
|
||||
binding.videoPlay.visibility = View.GONE
|
||||
displayImage(binding, url, width.toFloat(), height.toFloat(), isChangeRatio)
|
||||
binding.root.setOnClickListener {
|
||||
if (mAnswerEntity?.status == "pending" || mAnswerEntity?.status == "fail") return@setOnClickListener
|
||||
|
||||
debounceActionWithInterval(it.id, 1000) {
|
||||
if (mAnswerEntity == null) return@debounceActionWithInterval
|
||||
val position = if (mAnswerEntity?.type == "community_article") {
|
||||
@ -162,6 +167,9 @@ class ImageContainerView : LinearLayout {
|
||||
} else {
|
||||
if (mAnswerEntity!!.getPassVideos().isNullOrEmpty()) binding.root.tag as Int else (binding.root.tag as Int) - 1
|
||||
}
|
||||
if (mAnswerEntity?.communityId.isNullOrEmpty()) {
|
||||
mAnswerEntity?.communityId = mAnswerEntity?.bbs?.id
|
||||
}
|
||||
val intent = ImageViewerActivity.getIntent(context, mAnswerEntity!!.images as ArrayList<String>, position, binding.root,
|
||||
if (mAnswerEntity?.type == "community_article") mAnswerEntity else null, mEntrance)
|
||||
context.startActivity(intent)
|
||||
@ -209,19 +217,35 @@ class ImageContainerView : LinearLayout {
|
||||
}
|
||||
|
||||
if (url.endsWith(".gif")) {
|
||||
binding.gifBorder.visibility = View.VISIBLE
|
||||
binding.labelIcon.visibility = View.VISIBLE
|
||||
binding.labelIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_gif_label))
|
||||
}
|
||||
|
||||
val mediaCount = if (mAnswerEntity?.type == "community_article") {
|
||||
mAnswerEntity?.images?.size ?: 0
|
||||
} else {
|
||||
(mAnswerEntity?.images?.size ?: 0) + (mAnswerEntity?.getPassVideos()?.size ?: 0)
|
||||
binding.pendingView.run {
|
||||
when (mAnswerEntity?.status) {
|
||||
"pending" -> {
|
||||
visibility = View.VISIBLE
|
||||
text = R.string.pending_status.toResString()
|
||||
}
|
||||
|
||||
"fail" -> {
|
||||
visibility = View.VISIBLE
|
||||
text = R.string.fail_status.toResString()
|
||||
}
|
||||
|
||||
else -> {
|
||||
visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isVideo && index == 2 && mediaCount > 3) {
|
||||
|
||||
|
||||
val imageCount = mAnswerEntity?.images?.size ?: 0
|
||||
if (!isVideo && index == 2 && imageCount > 3) {
|
||||
binding.labelIcon.visibility = View.GONE
|
||||
binding.durationOrNumTv.visibility = View.VISIBLE
|
||||
binding.durationOrNumTv.text = "+${mAnswerEntity?.images?.size}"
|
||||
binding.durationOrNumTv.text = "+${imageCount - 3}"
|
||||
}
|
||||
|
||||
hierarchy.actualImageScaleType = ScalingUtils.ScaleType.CENTER_CROP
|
||||
|
||||
@ -20,7 +20,8 @@ class LikeView : RelativeLayout {
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
fun runLikeAnimation(event: MotionEvent) {
|
||||
fun runLikeAnimation(event: MotionEvent?) {
|
||||
if (event == null) return
|
||||
val iv = ImageView(context)
|
||||
val lp = LayoutParams(168, 150)
|
||||
val widthPixels = context.resources.displayMetrics.widthPixels
|
||||
|
||||
@ -11,6 +11,7 @@ import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
@ -463,6 +464,49 @@ public class RichEditor extends WebView {
|
||||
exec("javascript:RE.replacePlaceholderImage('" + list + "');");
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入视频占位图
|
||||
*/
|
||||
public void insertPlaceholderVideo(String id, String poster) {
|
||||
exec("javascript:RE.insertPlaceholderVideo('" + id + "','" + poster + "');");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新视频进度条
|
||||
*/
|
||||
public void updateVideoProgress(String id, String progress) {
|
||||
exec("javascript:RE.updateVideoProgress('" + id + "','" + progress + "');");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 上传视频完成
|
||||
*/
|
||||
public void videoUploadFinished(String id, String url, String msg) {
|
||||
exec("javascript:RE.videoUploadFinished('" + id + "','" + url + "','" + msg + "');");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更换封面图
|
||||
*/
|
||||
public void changePoster(String id, String poster) {
|
||||
exec("javascript:RE.changePoster('" + id + "','" + poster + "');");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除视频
|
||||
*/
|
||||
public void delPlaceholderVideo(String id) {
|
||||
exec("javascript:RE.delPlaceholderVideo('" + id + "');");
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传失败
|
||||
*/
|
||||
public void videoUploadFailed(String id) {
|
||||
exec("javascript:RE.videoUploadFailed('" + id + "');");
|
||||
}
|
||||
|
||||
public void removeFormat() {
|
||||
exec("javascript:RE.removeFormat();");
|
||||
}
|
||||
|
||||
@ -112,10 +112,10 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
this.mIndicatorSpace = DisplayUtils.dip2px(getContext(), space);
|
||||
}
|
||||
|
||||
private int getIndicatorSpace() {
|
||||
private int getIndicatorSpace(int position) {
|
||||
if (mIndicatorSpace != 0) return mIndicatorSpace;
|
||||
if (mIndicatorWidth != 0) {
|
||||
View tag = getTabViewByPosition(0);
|
||||
View tag = getTabViewByPosition(position);
|
||||
if (tag != null) return (tag.getWidth() - mIndicatorWidth) / 2;
|
||||
}
|
||||
return 0;
|
||||
@ -174,15 +174,15 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList
|
||||
right += (int) (nextTabView.getRight() * positionOffset + tabView.getRight() * (1.f - positionOffset));
|
||||
}
|
||||
|
||||
left += getIndicatorSpace();
|
||||
right -= getIndicatorSpace();
|
||||
left += getIndicatorSpace(position);
|
||||
right -= getIndicatorSpace(position);
|
||||
top = tabView.getTop() + getPaddingTop();
|
||||
bottom = tabView.getBottom() - getPaddingBottom();
|
||||
range.set(left, top, right, bottom);
|
||||
} else {
|
||||
|
||||
left = tabView.getLeft() + getIndicatorSpace();
|
||||
right = tabView.getRight() - getIndicatorSpace();
|
||||
left = tabView.getLeft() + getIndicatorSpace(position);
|
||||
right = tabView.getRight() - getIndicatorSpace(position);
|
||||
top = tabView.getTop() + getPaddingTop();
|
||||
bottom = tabView.getBottom() - getPaddingBottom();
|
||||
range.set(left, top, right, bottom);
|
||||
|
||||
@ -46,7 +46,7 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
val absolutePath = Environment.getExternalStorageDirectory().absolutePath
|
||||
val xapkFile = File(path)
|
||||
|
||||
ZipFile(xapkFile).use { zip ->
|
||||
val unzipClosure: (zip: ZipFile) -> Unit = { zip ->
|
||||
for (zipEntry in zip.entries().asSequence()) {
|
||||
val outputFile = if (zipEntry.name.getExtension() == XapkInstaller.XAPK_DATA_EXTENSION_NAME) {
|
||||
File(absolutePath + File.separator + zipEntry.name)
|
||||
@ -91,7 +91,7 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
bytes = input.read(buffer)
|
||||
if (canceled) {
|
||||
mUnzipListener.onCancel(mDownloadEntity)
|
||||
return
|
||||
return@use
|
||||
} else {
|
||||
// 防止多次短时间内多次触发onProgress方法导致阻塞主线程(低端机会出现十分明显的卡顿)
|
||||
debounceActionWithInterval(-1, 500) {
|
||||
@ -104,6 +104,16 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
mUnzipListener.onNext(mDownloadEntity, outputFile.path)
|
||||
}
|
||||
}
|
||||
|
||||
// Kotlin 1.4.X 在安卓 4.4 以下使用 use 默认关闭 ZipFile 的流时会触发
|
||||
// java.lang.IncompatibleClassChangeError: interface not implemented 的 Error (Throwable)
|
||||
// 但实测是不影响解压的,所以这里换用 let 不关闭流,确保不闪退,并且不影响解压结果
|
||||
// 帮用户解压了,但游戏能不能安装就看天吧 (毕竟支持4.X的游戏也不多了)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
ZipFile(File(path)).use { unzipClosure.invoke(it) }
|
||||
} else {
|
||||
ZipFile(File(path)).let { unzipClosure.invoke(it) }
|
||||
}
|
||||
mUnzipListener.onSuccess(mDownloadEntity)
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) throw e
|
||||
@ -208,18 +218,21 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
|
||||
private fun getUnzipSize(path: String): Long {
|
||||
var totalSize = 0L
|
||||
// 这里安卓5.0以下使用use会报错闪退
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
ZipFile(File(path)).use {
|
||||
for (entry in it.entries()) {
|
||||
totalSize += entry.size
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (entry in ZipFile(File(path)).entries()) {
|
||||
|
||||
val calculateSizeClosure: (zip: ZipFile) -> Unit = { zip ->
|
||||
for (entry in zip.entries()) {
|
||||
totalSize += entry.size
|
||||
}
|
||||
}
|
||||
|
||||
// Kotlin 1.4.X 在安卓 4.4 以下使用 use 默认ZipFile 的流时会触发
|
||||
// java.lang.IncompatibleClassChangeError: interface not implemented 的 Error (Throwable)
|
||||
// 实测是不影响解压,所以这里换用 let 不关闭流,确保不闪退
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
ZipFile(File(path)).use { calculateSizeClosure.invoke(it) }
|
||||
} else {
|
||||
ZipFile(File(path)).let { calculateSizeClosure.invoke(it) }
|
||||
}
|
||||
return totalSize
|
||||
}
|
||||
}
|
||||
@ -254,6 +254,14 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
String downloadId = PackageInstaller.createDownloadId(gameEntity.getName());
|
||||
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
|
||||
path = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/" + gameEntity.getName() + "." + apkEntity.getFormat();
|
||||
|
||||
// 下载模拟器游戏配置文件,地址是 "模拟器游戏类型根目录/cheat/"
|
||||
if (!TextUtils.isEmpty(gameEntity.getSimulatorGameConfig())) {
|
||||
String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + apkEntity.getPackageName()+ ".ini";
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
FileUtils.downloadFile(gameEntity.getSimulatorGameConfig(), configFilePath);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
path = PackageInstaller.getDownloadPathWithId(downloadId, apkEntity.getFormat());
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import com.gh.gamecenter.packagehelper.PackageViewModel
|
||||
import com.gh.gamecenter.retrofit.EmptyResponse
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.CONCERN_GAME_SP_KEY
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.halo.assistant.fragment.SettingsFragment
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -99,7 +100,7 @@ object PackageObserver {
|
||||
DownloadManager.getInstance(application).cancel(
|
||||
mDownloadEntity.url, false, true) // 默认不删除安装包 mSp.getBoolean("autodelete", true)
|
||||
}
|
||||
if (sp.getBoolean(SettingsFragment.CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
|
||||
if (sp.getBoolean(CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
|
||||
// 安装后关注游戏
|
||||
val finalDownloadEntity = mDownloadEntity
|
||||
RetrofitManager.getInstance(application).sensitiveApi
|
||||
|
||||
@ -4,26 +4,23 @@ import android.net.Uri
|
||||
import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.DeviceUtils
|
||||
import com.gh.common.util.NetworkUtils
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.common.util.debugOnly
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DataSpec
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheUtil
|
||||
import com.google.android.exoplayer2.util.Util
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheWriter
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import tv.danmaku.ijk.media.exo2.ExoSourceManager
|
||||
import tv.danmaku.ijk.media.exo2.source.GSYDefaultHttpDataSource
|
||||
import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSourceFactory
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
object ExoCacheManager {
|
||||
|
||||
private val threads = ConcurrentHashMap<String, AtomicBoolean>()
|
||||
private val writers = ConcurrentHashMap<String, CacheWriter>()
|
||||
|
||||
private fun getPreLength(): Long {
|
||||
val totalRamSizeOfDevice = DeviceUtils.getTotalRamSizeOfDevice(HaloApp.getInstance().application)
|
||||
@ -54,40 +51,45 @@ object ExoCacheManager {
|
||||
val preLength = getPreLength()
|
||||
if (preLength == 0L) return
|
||||
runOnIoThread {
|
||||
Thread.sleep(100)
|
||||
threads[videoUri] = AtomicBoolean(false)
|
||||
val contentLength = getContentLength(videoUri)
|
||||
val cacheLength = if (contentLength >= preLength) preLength else contentLength
|
||||
val dataSpec = DataSpec(Uri.parse(videoUri), 0, cacheLength, null)
|
||||
val simpleCache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
|
||||
val dataSourceFactory = GSYExoHttpDataSourceFactory(Util.getUserAgent(HaloApp.getInstance().application,
|
||||
"ExoCacheManager"), DefaultBandwidthMeter.Builder(HaloApp.getInstance().application).build(),
|
||||
GSYDefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
|
||||
GSYDefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false)
|
||||
val cacheDataSource = CacheDataSource(simpleCache, dataSourceFactory.createDataSource())
|
||||
val specBuilder = DataSpec.Builder()
|
||||
.setUri(Uri.parse(videoUri))
|
||||
.setLength(cacheLength)
|
||||
.build()
|
||||
val dataSource: DataSource = DefaultDataSourceFactory(HaloApp.getInstance()).createDataSource()
|
||||
val cacheDataSource = CacheDataSource(simpleCache, dataSource)
|
||||
val cacheWriter = CacheWriter(
|
||||
cacheDataSource,
|
||||
specBuilder,
|
||||
true,
|
||||
null
|
||||
) { requestLength, bytesCached, newBytesCached ->
|
||||
// debugOnly {
|
||||
// Utils.log("$requestLength-$bytesCached-$newBytesCached")
|
||||
// }
|
||||
}
|
||||
writers[videoUri] = cacheWriter
|
||||
try {
|
||||
CacheUtil.cache(dataSpec, simpleCache, CacheUtil.DEFAULT_CACHE_KEY_FACTORY, cacheDataSource, CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->
|
||||
if (requestLength == bytesCached) {
|
||||
threads.remove(videoUri)
|
||||
}
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// Utils.log("$requestLength--$bytesCached--$newBytesCached")
|
||||
// }
|
||||
}, threads[videoUri])
|
||||
} catch (e: Throwable) {
|
||||
threads.remove(videoUri)
|
||||
cacheWriter.cache()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun cancel(videoUri: String) {
|
||||
threads[videoUri]?.set(true)
|
||||
writers[videoUri]?.cancel()
|
||||
writers.remove(videoUri)
|
||||
}
|
||||
|
||||
fun cancelAll() {
|
||||
for (entry in threads.entries) {
|
||||
entry.value.set(true)
|
||||
val iterator = writers.entries.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val entry = iterator.next()
|
||||
entry.value.cancel()
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import android.util.DisplayMetrics
|
||||
@ -48,7 +47,6 @@ import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.github.piasy.biv.view.BigImageView
|
||||
import com.github.piasy.biv.view.FrescoImageViewFactory
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.*
|
||||
@ -60,7 +58,6 @@ import kotlin.collections.ArrayList
|
||||
*
|
||||
* @author 黄壮华
|
||||
*
|
||||
* todo BigImageView静态webp/动态webp(ImageInfoExtractor.getImageType(image))判断有问题,导致部分静态webp无法使用缩放功能
|
||||
*/
|
||||
class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
|
||||
@ -189,16 +186,21 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
mSavePicBtn.setOnClickListener {
|
||||
checkStoragePermissionBeforeAction {
|
||||
mBigImageView?.currentImageFile?.run {
|
||||
adapter?.saveImageToFile(this, mFinalUrl)
|
||||
ImageUtils.saveImageToFile(this, mFinalUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mArticleDetailBtn.setOnClickListener {
|
||||
val intent = ArticleDetailActivity.getIntent(this, CommunityEntity(if (!mAnswerEntity?.communityId.isNullOrEmpty()) mAnswerEntity?.communityId
|
||||
?: "" else mAnswerEntity?.articleCommunityId ?: "", mAnswerEntity?.communityName
|
||||
?: ""), mAnswerEntity?.id
|
||||
?: "", mEntrance, "")
|
||||
val intent = ArticleDetailActivity.getIntent(
|
||||
this,
|
||||
CommunityEntity(
|
||||
if (!mAnswerEntity?.communityId.isNullOrEmpty()) mAnswerEntity?.communityId ?: "" else mAnswerEntity?.articleCommunityId ?: "",
|
||||
mAnswerEntity?.communityName ?: ""),
|
||||
mAnswerEntity?.id
|
||||
?: "",
|
||||
mEntrance,
|
||||
"")
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
@ -221,44 +223,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
mViewPager.onDestroy() // 注销EventBus
|
||||
}
|
||||
|
||||
private fun saveImageToFile(src: File, curUrl: String?) {
|
||||
var `in`: InputStream? = null
|
||||
var out: OutputStream? = null
|
||||
try {
|
||||
val fileName: String = if (mShowBase64Image) {
|
||||
MD5Utils.getUrlMD5(curUrl!!.substring(0, 50)) + ".png"
|
||||
} else {
|
||||
curUrl!!.substring(curUrl.lastIndexOf("/"))
|
||||
}
|
||||
val savePath = Environment.getExternalStorageDirectory().absolutePath + "/Pictures/ghzhushou/"
|
||||
val file = File(savePath)
|
||||
if (!file.exists()) {
|
||||
file.mkdirs()
|
||||
}
|
||||
val dst = File(savePath, fileName)
|
||||
if (dst.exists()) {
|
||||
dst.delete()
|
||||
}
|
||||
`in` = FileInputStream(src)
|
||||
out = FileOutputStream(dst)
|
||||
val buf = ByteArray(1024)
|
||||
var len: Int
|
||||
while (`in`.read(buf).also { len = it } > 0) {
|
||||
out.write(buf, 0, len)
|
||||
}
|
||||
Utils.toast(this@ImageViewerActivity, "图片已保存到/Pictures/ghzhushou/")
|
||||
MessageShareUtils.refreshImage(this@ImageViewerActivity, dst)
|
||||
} catch (e: Exception) {
|
||||
Utils.log("图片保存失败:$e")
|
||||
} finally {
|
||||
try {
|
||||
out?.close()
|
||||
`in`?.close()
|
||||
} catch (ignore: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float,
|
||||
positionOffsetPixels: Int) {
|
||||
@ -609,7 +573,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
}
|
||||
reportTv.setOnClickListener {
|
||||
checkStoragePermissionBeforeAction {
|
||||
saveImageToFile(imageView.currentImageFile, finalUrl)
|
||||
ImageUtils.saveImageToFile(imageView.currentImageFile, finalUrl, mShowBase64Image)
|
||||
dialog.cancel()
|
||||
}
|
||||
dialog.cancel()
|
||||
@ -621,44 +585,6 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
|
||||
return view
|
||||
}
|
||||
|
||||
fun saveImageToFile(src: File, curUrl: String?) {
|
||||
var `in`: InputStream? = null
|
||||
var out: OutputStream? = null
|
||||
try {
|
||||
val fileName: String = if (mShowBase64Image) {
|
||||
MD5Utils.getContentMD5(System.currentTimeMillis().toString()) + ".png"
|
||||
} else {
|
||||
Uri.parse(curUrl).lastPathSegment.toString()
|
||||
}
|
||||
val savePath = Environment.getExternalStorageDirectory().absolutePath + "/Pictures/ghzhushou/"
|
||||
val file = File(savePath)
|
||||
if (!file.exists()) {
|
||||
file.mkdirs()
|
||||
}
|
||||
val dst = File(savePath, fileName)
|
||||
if (dst.exists()) {
|
||||
dst.delete()
|
||||
}
|
||||
`in` = FileInputStream(src)
|
||||
out = FileOutputStream(dst)
|
||||
val buf = ByteArray(1024)
|
||||
var len: Int
|
||||
while (`in`.read(buf).also { len = it } > 0) {
|
||||
out.write(buf, 0, len)
|
||||
}
|
||||
Utils.toast(this@ImageViewerActivity, "图片已保存到/Pictures/ghzhushou/")
|
||||
MessageShareUtils.refreshImage(this@ImageViewerActivity, dst)
|
||||
} catch (e: Exception) {
|
||||
Utils.log("图片保存失败:$e")
|
||||
} finally {
|
||||
try {
|
||||
out?.close()
|
||||
`in`?.close()
|
||||
} catch (ignore: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
|
||||
container.removeView(`object` as View)
|
||||
}
|
||||
|
||||
@ -59,7 +59,9 @@ import com.gh.common.util.NotificationHelper;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.common.util.QuickLoginHelper;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.common.util.SentryHelper;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.common.util.ToastUtils;
|
||||
import com.gh.common.util.UrlFilterUtils;
|
||||
@ -92,6 +94,7 @@ import com.github.piasy.biv.BigImageViewer;
|
||||
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
|
||||
import com.google.android.exoplayer2.upstream.cache.Cache;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
@ -307,18 +310,15 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
});
|
||||
|
||||
//恢复顶部视频默认静音状态
|
||||
SPUtils.setBoolean(Constants.SP_TOP_VIDEO_VOICE, true);
|
||||
//恢复视频流非Wifi提醒
|
||||
SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true);
|
||||
//重置首页视频播放进度
|
||||
SPUtils.setString(Constants.SP_HOME_VIDEO_PLAY_RECORD, "");
|
||||
|
||||
// 重新打开APP重置"显示返回任务悬浮图标"标志位
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_TASK_FLOAT, false);
|
||||
|
||||
postAttentionVideoRecord();
|
||||
deleteSimulatorGame();
|
||||
|
||||
QuickLoginHelper.getPhoneInfo(this);
|
||||
}
|
||||
|
||||
//上传关注视频浏览记录
|
||||
@ -453,8 +453,8 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
if (view != null) {
|
||||
view.setVisibility(View.GONE);
|
||||
ExtensionsKt.removeFromParent(view);
|
||||
}
|
||||
mMainWrapperFragment.getWelcomeDialog();
|
||||
|
||||
checkDialog();
|
||||
}
|
||||
@ -465,7 +465,9 @@ public class MainActivity extends BaseActivity {
|
||||
checkNotificationPermission();
|
||||
// 检查助手更新
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
UpdateManager.getInstance(this).checkUpdate(true, null);
|
||||
UpdateManager updateManager = UpdateManager.getInstance(this);
|
||||
updateManager.checkUpdate(true, null);
|
||||
updateManager.setDismissCallback(() -> mMainWrapperFragment.getWelcomeDialog());
|
||||
});
|
||||
}
|
||||
|
||||
@ -554,17 +556,27 @@ public class MainActivity extends BaseActivity {
|
||||
break;
|
||||
case HOST_LAUNCH_SIMULATOR_GAME:
|
||||
String json = getIntent().getStringExtra(EntranceUtils.KEY_GAME);
|
||||
GameEntity gameEntity = GsonUtils.getGson().fromJson(json, new TypeToken<GameEntity>() {
|
||||
}.getType());
|
||||
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
if (downloadEntity != null) {
|
||||
File file = new File(downloadEntity.getPath());
|
||||
if (!file.exists()) {
|
||||
ToastUtils.INSTANCE.showToast("文件已被删除,无法启动");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
GameEntity gameEntity = GsonUtils.getGson().fromJson(json, new TypeToken<GameEntity>() {
|
||||
}.getType());
|
||||
DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
if (downloadEntity != null) {
|
||||
File file = new File(downloadEntity.getPath());
|
||||
if (!file.exists()) {
|
||||
ToastUtils.INSTANCE.showToast("文件已被删除,无法启动");
|
||||
return;
|
||||
}
|
||||
|
||||
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
|
||||
SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity);
|
||||
}
|
||||
} catch (JsonSyntaxException exception) {
|
||||
exception.printStackTrace();
|
||||
toast("模拟器游戏启动失败,请联系客服反馈相关信息");
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"SIMULATOR_SHORTCUT_LAUNCH_ERROR",
|
||||
"raw_json",
|
||||
json
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KEY_MARKET_DETAILS:
|
||||
@ -576,7 +588,6 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
Utils.log(bundle);
|
||||
if (bundle.getInt(EntranceUtils.KEY_POSITION) != -1) {
|
||||
Utils.log("abc");
|
||||
EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, bundle.getInt(EntranceUtils.KEY_POSITION)));
|
||||
}
|
||||
}
|
||||
@ -585,8 +596,6 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
/**
|
||||
* 应用跳转
|
||||
*
|
||||
* @param packageName
|
||||
*/
|
||||
private void redirectGameDetail(String packageName) {
|
||||
String filterQuery = UrlFilterUtils.getFilterQuery("package", packageName, "type", "package_redirect");
|
||||
@ -749,7 +758,7 @@ public class MainActivity extends BaseActivity {
|
||||
private void switchToCommunityTabAndRefresh() {
|
||||
getIntent().putExtra(SWITCH_TO_COMMUNITY, false);
|
||||
Log.e("Switch", "true");
|
||||
EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_ASK));
|
||||
EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_BBS));
|
||||
EventBus.getDefault().post(new EBReuse(CommunityFragment.EB_RETRY_PAGE));
|
||||
}
|
||||
|
||||
@ -882,7 +891,7 @@ public class MainActivity extends BaseActivity {
|
||||
if (info != null) {
|
||||
if (EntranceUtils.HOST_COMMUNITY.equals(info.getType())) {
|
||||
UserManager.getInstance().setCommunityData(new CommunityEntity(info.getLink(), info.getText()));
|
||||
runOnUiThread(() -> mMainWrapperFragment.setCurrentItem(MainWrapperFragment.INDEX_ASK));
|
||||
runOnUiThread(() -> mMainWrapperFragment.setCurrentItem(MainWrapperFragment.INDEX_BBS));
|
||||
} else {
|
||||
DirectUtils.directToSpecificPage(this,
|
||||
info.getType(),
|
||||
|
||||
@ -39,6 +39,7 @@ import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NewLogUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.common.view.FixLinearLayoutManager;
|
||||
import com.gh.common.view.VerticalItemDecoration;
|
||||
@ -667,6 +668,15 @@ public class NewsDetailActivity extends ToolBarActivity implements OnClickListen
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
if (mEntrance.contains("板块成员") || mEntrance.contains("论坛详情")) {
|
||||
long stayTime = (System.currentTimeMillis() - startPageTime) / 1000;
|
||||
NewLogUtils.INSTANCE.logActivityPause("版规说明", "jump_layout_description", stayTime, "", "", "", "");
|
||||
}
|
||||
}
|
||||
|
||||
// 关注事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(EBConcernChanged changed) {
|
||||
|
||||
27
app/src/main/java/com/gh/gamecenter/SingletonWebActivity.kt
Normal file
27
app/src/main/java/com/gh/gamecenter/SingletonWebActivity.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package com.gh.gamecenter
|
||||
|
||||
import android.content.Intent
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.halo.assistant.fragment.WebFragment
|
||||
|
||||
class SingletonWebActivity : WebActivity() {
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
if (intent?.extras?.getString(EntranceUtils.KEY_URL)
|
||||
== targetFragment.arguments?.getString(EntranceUtils.KEY_URL)) {
|
||||
// 同样的地址,不理会
|
||||
} else {
|
||||
if (targetFragment is WebFragment) {
|
||||
targetFragment.arguments?.putString(EntranceUtils.KEY_URL, intent?.extras?.getString(EntranceUtils.KEY_URL))
|
||||
(targetFragment as WebFragment).reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun provideNormalIntent(): Intent? {
|
||||
return getTargetIntent(this, SingletonWebActivity::class.java, WebFragment::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
@ -222,7 +222,7 @@ public class SkipActivity extends BaseActivity {
|
||||
} else {
|
||||
location = path;
|
||||
}
|
||||
DirectUtils.directToVideoDetail(this, path, location,
|
||||
DirectUtils.directToLegacyVideoDetail(this, path, location,
|
||||
false, TextUtils.isEmpty(gameId) ? "" : gameId, ENTRANCE_BROWSER, "浏览器", TextUtils.isEmpty(referer) ? "" : referer,
|
||||
TextUtils.isEmpty(type) ? "" : type, TextUtils.isEmpty(act) ? "" : act, TextUtils.isEmpty(paginationType) ? "page" : paginationType, TextUtils.isEmpty(fieldId) ? "" : fieldId,
|
||||
TextUtils.isEmpty(sectionName) ? "" : sectionName);
|
||||
@ -273,12 +273,17 @@ public class SkipActivity extends BaseActivity {
|
||||
bundle.putString(KEY_TYPE, type);
|
||||
EntranceUtils.jumpActivity(this, bundle);
|
||||
break;
|
||||
case EntranceUtils.HOST_VIDEO_DETAIL:
|
||||
DirectUtils.directToVideoDetail(this, path, ENTRANCE_BROWSER, "");
|
||||
break;
|
||||
case HOST_LIBAO:
|
||||
DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_USERHOME:
|
||||
String position = uri.getQueryParameter("position");
|
||||
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
|
||||
String subTypeString = uri.getQueryParameter("sub_type");
|
||||
|
||||
DirectUtils.directToHomeActivity(this, path, subTypeString, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
case HOST_COMMUNITY_COLUMN:
|
||||
CommunityEntity community = new CommunityEntity();
|
||||
@ -376,7 +381,8 @@ public class SkipActivity extends BaseActivity {
|
||||
DirectUtils.directToGameRatingDetail(this, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), ENTRANCE_BROWSER);
|
||||
break;
|
||||
case EntranceUtils.HOST_FORUM:
|
||||
DirectUtils.directToForum(this);
|
||||
position = uri.getQueryParameter("position");
|
||||
DirectUtils.directToForum(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
|
||||
break;
|
||||
case EntranceUtils.HOST_HELP_AND_FEEDBACK:
|
||||
position = uri.getQueryParameter("position");
|
||||
|
||||
@ -5,10 +5,8 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -27,14 +25,12 @@ import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.dialog.PrivacyDialogFragment;
|
||||
import com.gh.common.tracker.Tracker;
|
||||
import com.gh.common.tracker.TrackerLogger;
|
||||
import com.gh.common.util.AdHelper;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.DeviceTokenUtils;
|
||||
import com.gh.common.util.DeviceUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.EmptyCallback;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.GameSubstituteRepositoryHelper;
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
@ -103,10 +99,13 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mIsNewForThisVersion = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true);
|
||||
HaloApp.getInstance().isNewForThisVersion = mIsNewForThisVersion;
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
TrackerLogger.logAppLaunch(Tracker.INSTANCE.getLaunchId(), Tracker.INSTANCE.getSessionId());
|
||||
DisplayUtils.transparentStatusBar(this);
|
||||
|
||||
TrackerLogger.logAppLaunch(this);
|
||||
|
||||
// 处理助手已经在后台运行导致的再次启动助手
|
||||
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
|
||||
@ -122,7 +121,9 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
|
||||
// 判断是不是光环的新用户
|
||||
if (SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)) {
|
||||
mStartMainActivityDirectly = true;
|
||||
// 引导页需用户点击 “立即体验” 按钮才进入首页,所以这里不能置为true
|
||||
// https://git.ghzs.com/pm/halo-app-issues/-/issues/1422(第3点)
|
||||
// mStartMainActivityDirectly = true;
|
||||
SPUtils.setLong(Constants.SP_INITIAL_USAGE_TIME, System.currentTimeMillis());
|
||||
HaloApp.getInstance().isBrandNewInstall = true;
|
||||
showPrivacyDialog(guideLayout);
|
||||
@ -237,6 +238,30 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void getMark() {
|
||||
// 安装相应包名以后不需请求接口获取返回数据
|
||||
if (PackageUtils.isInstalled(HaloApp.getInstance().getApplication(), "com.enotary.cloud")) {
|
||||
HaloApp.getInstance().setServerUserMark("new");
|
||||
return;
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi()
|
||||
.getMark()
|
||||
.subscribe(new BiResponse<ResponseBody>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseBody data) {
|
||||
try {
|
||||
JSONObject object = new JSONObject(data.string());
|
||||
HaloApp.getInstance().setServerUserMark(object.getString("mark"));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void showPrivacyPolicy(SimpleCallback<Boolean> callback) {
|
||||
RetrofitManager.getInstance(this).getApi()
|
||||
@ -291,7 +316,7 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
private void launchMainActivity() {
|
||||
HaloApp.getInstance().postInit(true);
|
||||
|
||||
TrackerLogger.logAppLaunchSuccessful(Tracker.INSTANCE.getLaunchId(), Tracker.INSTANCE.getSessionId());
|
||||
TrackerLogger.logAppLaunchSuccessful();
|
||||
|
||||
getAd();
|
||||
prefetchData();
|
||||
@ -355,6 +380,7 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
deviceDialogSetting();
|
||||
getFilterDetailTags();
|
||||
getAuthDialog();
|
||||
getMark();
|
||||
getRegulationTestStatus();
|
||||
UsageStatsHelper.checkAndPostUsageStats();
|
||||
GameSubstituteRepositoryHelper.updateGameSubstituteRepository();
|
||||
|
||||
@ -550,6 +550,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
@Override
|
||||
public <T> void onListClick(View view, int position, T data) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_CREDENTIALS_REQUEST);
|
||||
}
|
||||
}, null);
|
||||
@ -567,6 +568,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
@Override
|
||||
public <T> void onListClick(View view, int position, T data) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_SCREENSHOT_REQUEST);
|
||||
}
|
||||
}, null);
|
||||
@ -1052,6 +1054,11 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSingleSuccess(@NotNull Map<String, String> imageUrl) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@NotNull LinkedHashMap<String, String> imageUrl, @NotNull Map<String, ? extends Exception> errorMap) {
|
||||
Utils.log("意见反馈:图片上传完成");
|
||||
@ -1381,6 +1388,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
List<String> picList = (List<String>) data;
|
||||
if (position == mAdapter.getItemCount() - 1 && picList.size() < 5) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_REQUEST);
|
||||
}
|
||||
}, null);
|
||||
@ -1389,6 +1397,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
List<String> picList = (List<String>) data;
|
||||
if (position == mAdapter.getItemCount() - 1 && picList.size() < 5) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
|
||||
startActivityForResult(intent, MEDIA_STORE_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,482 +0,0 @@
|
||||
//package com.gh.gamecenter;
|
||||
//
|
||||
//import android.annotation.SuppressLint;
|
||||
//import android.app.Activity;
|
||||
//import android.app.Dialog;
|
||||
//import android.content.Context;
|
||||
//import android.content.Intent;
|
||||
//import android.content.res.Configuration;
|
||||
//import android.graphics.BitmapFactory;
|
||||
//import android.graphics.Color;
|
||||
//import android.net.Uri;
|
||||
//import android.os.Bundle;
|
||||
//import android.os.Environment;
|
||||
//import android.text.TextUtils;
|
||||
//import android.util.Base64;
|
||||
//import android.util.DisplayMetrics;
|
||||
//import android.view.View;
|
||||
//import android.view.ViewGroup;
|
||||
//import android.view.Window;
|
||||
//import android.widget.LinearLayout;
|
||||
//import android.widget.RelativeLayout;
|
||||
//import android.widget.TextView;
|
||||
//
|
||||
//import androidx.annotation.NonNull;
|
||||
//import androidx.annotation.Nullable;
|
||||
//import androidx.core.content.ContextCompat;
|
||||
//import androidx.viewpager.widget.PagerAdapter;
|
||||
//import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
||||
//
|
||||
//import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
|
||||
//import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
//import com.facebook.imagepipeline.core.ImagePipeline;
|
||||
//import com.facebook.imagepipeline.request.ImageRequest;
|
||||
//import com.gh.base.BaseActivity;
|
||||
//import com.gh.common.AppExecutor;
|
||||
//import com.gh.common.Base64ImageHolder;
|
||||
//import com.gh.common.util.DisplayUtils;
|
||||
//import com.gh.common.util.EntranceUtils;
|
||||
//import com.gh.common.util.ImageUtils;
|
||||
//import com.gh.common.util.MD5Utils;
|
||||
//import com.gh.common.util.MessageShareUtils;
|
||||
//import com.gh.common.util.NetworkUtils;
|
||||
//import com.gh.common.util.PermissionHelper;
|
||||
//import com.gh.common.util.SimpleImageLoader;
|
||||
//import com.gh.common.view.Gh_RelativeLayout;
|
||||
//import com.gh.common.view.Gh_ViewPager;
|
||||
//import com.gh.gamecenter.entity.ImageInfoEntity;
|
||||
//import com.gh.gamecenter.retrofit.Response;
|
||||
//import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
//import com.github.piasy.biv.view.BigImageView;
|
||||
//import com.github.piasy.biv.view.FrescoImageViewFactory;
|
||||
//import com.lightgame.utils.Utils;
|
||||
//
|
||||
//import java.io.BufferedOutputStream;
|
||||
//import java.io.File;
|
||||
//import java.io.FileInputStream;
|
||||
//import java.io.FileOutputStream;
|
||||
//import java.io.InputStream;
|
||||
//import java.io.OutputStream;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.HashSet;
|
||||
//import java.util.Locale;
|
||||
//import java.util.Map;
|
||||
//
|
||||
//import butterknife.BindView;
|
||||
//import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
//import io.reactivex.schedulers.Schedulers;
|
||||
//
|
||||
///**
|
||||
// * 查看游戏截图页面
|
||||
// *
|
||||
// * @author 黄壮华
|
||||
// *
|
||||
// * todo BigImageView静态webp/动态webp(ImageInfoExtractor.getImageType(image))判断有问题,导致部分静态webp无法使用缩放功能
|
||||
// */
|
||||
//public class ViewImageActivity extends BaseActivity implements OnPageChangeListener {
|
||||
//
|
||||
// public static final int REQUEST_FOR_VIEWED_IMAGE = 921;
|
||||
// public static final String VIEWED_IMAGE = "viewed_image";
|
||||
//
|
||||
// @BindView(R.id.image_detail_page)
|
||||
// Gh_ViewPager mViewPager;
|
||||
// @BindView(R.id.image_detail_progress)
|
||||
// TextView mProgressHint;
|
||||
// @BindView(R.id.image_mask)
|
||||
// View mIndicatorMask;
|
||||
// @BindView(R.id.image_indicator_tv)
|
||||
// TextView mIndicatorTv;
|
||||
//
|
||||
// private ViewImageAdapter adapter;
|
||||
//
|
||||
// private ImagePipeline mImagePipeline;
|
||||
//
|
||||
// private boolean mShowBase64Image = false;
|
||||
//
|
||||
// private static final String KEY_BASE64 = "base64";
|
||||
//
|
||||
// private static final String KEY_URLS = "urls";
|
||||
// private static final String KEY_CURRENT = "current";
|
||||
//
|
||||
// private ArrayList<String> urls;
|
||||
// private HashSet<Integer> mViewedSet; // 让调用者知道该图片是否被看过了
|
||||
// private Map<String, ImageInfoEntity> mImageInfoMap;
|
||||
//
|
||||
// private int mLimitWidth;
|
||||
//
|
||||
// private boolean isOrientation;
|
||||
//
|
||||
// public static Intent getBase64ViewImageIntent(Context context, boolean showSingleBase64Image) {
|
||||
// Intent checkIntent = new Intent(context, ViewImageActivity.class);
|
||||
// checkIntent.putExtra(KEY_BASE64, showSingleBase64Image);
|
||||
// return checkIntent;
|
||||
// }
|
||||
//
|
||||
// public static Intent getViewImageIntent(Context context, ArrayList<String> list, int position, String entrance) {
|
||||
// Intent checkIntent = new Intent(context, ViewImageActivity.class);
|
||||
// checkIntent.putExtra(KEY_URLS, list);
|
||||
// checkIntent.putExtra(KEY_CURRENT, position);
|
||||
// checkIntent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
// return checkIntent;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected int getLayoutId() {
|
||||
// return R.layout.activity_viewimage;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onCreate(Bundle savedInstanceState) {
|
||||
// super.onCreate(savedInstanceState);
|
||||
// mViewedSet = new HashSet<>();
|
||||
// mImageInfoMap = new HashMap<>();
|
||||
// // init data
|
||||
// int current = 0;
|
||||
// Bundle extras = getIntent().getExtras();
|
||||
// if (extras != null) {
|
||||
// if (extras.getBoolean(KEY_BASE64)) {
|
||||
// mShowBase64Image = true;
|
||||
// urls = new ArrayList<>();
|
||||
// urls.add(Base64ImageHolder.INSTANCE.getImage());
|
||||
// } else {
|
||||
// urls = extras.getStringArrayList(KEY_URLS);
|
||||
// current = extras.getInt(KEY_CURRENT, 0);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (savedInstanceState != null) {
|
||||
// current = savedInstanceState.getInt(EntranceUtils.KEY_CURRENTITEM, 0);
|
||||
// isOrientation = savedInstanceState.getBoolean("isOrientation");
|
||||
// }
|
||||
//
|
||||
// if (urls.size() > 1) mIndicatorMask.setVisibility(View.VISIBLE);
|
||||
// mIndicatorTv.setText(String.format("%d/%d", current + 1, urls.size()));
|
||||
//
|
||||
// mImagePipeline = Fresco.getImagePipeline();
|
||||
//
|
||||
// // init slide
|
||||
// DisplayMetrics outMetrics = new DisplayMetrics();
|
||||
// getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
|
||||
// int widthPixels = outMetrics.widthPixels;
|
||||
// if (NetworkUtils.isWifiOr4GConnected(this)) {
|
||||
// mLimitWidth = widthPixels * 2;
|
||||
// } else {
|
||||
// mLimitWidth = widthPixels;
|
||||
// }
|
||||
// // init viewPage
|
||||
// adapter = new ViewImageAdapter();
|
||||
// mViewPager.setAdapter(adapter);
|
||||
// mViewPager.setCurrentItem(current);
|
||||
// mViewPager.addOnPageChangeListener(this);
|
||||
//
|
||||
// if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
// isOrientation = true; // 横屏
|
||||
// } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
// isOrientation = false;// 竖屏
|
||||
// }
|
||||
//
|
||||
// mProgressHint.setOnClickListener(v -> {
|
||||
// int position = mViewPager.getCurrentItem();
|
||||
// Object object = mViewPager.findViewWithTag(position);
|
||||
// if (object != null) {
|
||||
// mProgressHint.setWidth(mProgressHint.getWidth());
|
||||
// RelativeLayout view = (RelativeLayout) object;
|
||||
// final BigImageView imageView = view.findViewById(R.id.viewimage_iv_show);
|
||||
// String url = urls.get(position);
|
||||
// imageView.showImage(Uri.parse(url));
|
||||
// imageView.setImageLoaderCallback(new SimpleImageLoader() {
|
||||
// @Override
|
||||
// public void onProgress(int progress) {
|
||||
// if (position == mViewPager.getCurrentItem()) { // 防止下载过程中切换图片
|
||||
// if (progress < 100) {
|
||||
// mProgressHint.setText((progress + "%"));
|
||||
// } else {
|
||||
// mProgressHint.setText("已完成");
|
||||
// mBaseHandler.postDelayed(() -> {
|
||||
// if (position == mViewPager.getCurrentItem()) { // 防止等待过程中切换图片
|
||||
// mProgressHint.setVisibility(View.GONE);
|
||||
// }
|
||||
// }, 500);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// DisplayUtils.transparentStatusAndNavigation(this);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onSaveInstanceState(Bundle outState) {
|
||||
// super.onSaveInstanceState(outState);
|
||||
// outState.putInt(EntranceUtils.KEY_CURRENTITEM, mViewPager.getCurrentItem());
|
||||
// outState.putBoolean("isOrientation", isOrientation);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onDestroy() {
|
||||
// super.onDestroy();
|
||||
// if (mShowBase64Image) {
|
||||
// urls.clear();
|
||||
// Base64ImageHolder.INSTANCE.setImage("");
|
||||
// }
|
||||
// mViewPager.onDestroy(); // 注销EventBus
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onPageScrolled(int position, float positionOffset,
|
||||
// int positionOffsetPixels) {
|
||||
// if (positionOffset != 0) {
|
||||
// mProgressHint.setVisibility(View.GONE);
|
||||
// } else {
|
||||
// String url = urls.get(position);
|
||||
// ImageInfoEntity imageInfoEntity = mImageInfoMap.get(url);
|
||||
// if (imageInfoEntity != null && imageInfoEntity.getFileSize() != null &&
|
||||
// !mImagePipeline.isInBitmapMemoryCache(ImageRequest.fromUri(url)) &&
|
||||
// !mImagePipeline.isInDiskCacheSync(ImageRequest.fromUri(url))) {
|
||||
// String size = String.format(Locale.CHINA, "%.1fM",
|
||||
// Integer.valueOf(imageInfoEntity.getFileSize().getValue()) / 1024F / 1024F);
|
||||
// mProgressHint.setVisibility(View.VISIBLE);
|
||||
// mProgressHint.setText(("查看原图(" + size + ")"));
|
||||
// ViewGroup.LayoutParams layoutParams = mProgressHint.getLayoutParams();
|
||||
// layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
// mProgressHint.setLayoutParams(layoutParams);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// mViewedSet.add(position);
|
||||
// setResult(Activity.RESULT_OK, new Intent().putExtra(VIEWED_IMAGE, mViewedSet));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onPageSelected(int position) {
|
||||
// Gh_RelativeLayout ghRelativeLayout;
|
||||
// for (int i = 0; i < mViewPager.getChildCount(); i++) {
|
||||
// if (mViewPager.getChildAt(i).getTag() != null) {
|
||||
// ghRelativeLayout = (Gh_RelativeLayout) mViewPager.getChildAt(i);
|
||||
// if (ghRelativeLayout == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// BigImageView imageView = ghRelativeLayout.findViewById(R.id.viewimage_iv_show);
|
||||
// SubsamplingScaleImageView ssiv = imageView.getSSIV();
|
||||
// if (ssiv != null) ssiv.resetScaleAndCenter();
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// mIndicatorTv.setText(String.format("%d/%d", position + 1, urls.size()));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onPageScrollStateChanged(int newState) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private void loadImageInfo(int position, int width) {
|
||||
// String url = urls.get(position);
|
||||
// RetrofitManager.getInstance(this)
|
||||
// .getApi().getImageInfo(url + "?x-oss-process=image/info")
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .observeOn(AndroidSchedulers.mainThread())
|
||||
// .subscribe(new Response<ImageInfoEntity>() {
|
||||
// @Override
|
||||
// public void onResponse(@Nullable ImageInfoEntity response) {
|
||||
// if (response != null && response.getImageWidth() != null &&
|
||||
// Integer.valueOf(response.getImageWidth().getValue()) > width) {
|
||||
// mImageInfoMap.put(url, response);
|
||||
// if (position == mViewPager.getCurrentItem()) {
|
||||
// onPageScrolled(position, 0, 0); // 刷新下载原图提示按钮
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// private void loadImage(String url, final BigImageView imageView) {
|
||||
// if (TextUtils.isEmpty(url)) return;
|
||||
//
|
||||
// if (url.startsWith("data:image/png;base64")) {
|
||||
// AppExecutor.getIoExecutor().execute(() -> {
|
||||
// String base64String = url.replace("data:image/png;base64", "");
|
||||
// try {
|
||||
// File imageFile = new File(getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".png");
|
||||
//
|
||||
// byte[] decodedString = Base64.decode(base64String, Base64.DEFAULT);
|
||||
//
|
||||
// BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(imageFile));
|
||||
// bos.write(decodedString);
|
||||
// bos.flush();
|
||||
// bos.close();
|
||||
//
|
||||
// AppExecutor.getUiExecutor().execute(() -> {
|
||||
// imageView.setImageViewFactory(new FrescoImageViewFactory());
|
||||
// imageView.showImage(Uri.fromFile(imageFile));
|
||||
// });
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// // 添加GIF支持
|
||||
// imageView.setImageViewFactory(new FrescoImageViewFactory());
|
||||
// imageView.showImage(Uri.parse(url));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private class ViewImageAdapter extends PagerAdapter {
|
||||
//
|
||||
// @Override
|
||||
// public int getCount() {
|
||||
// if (urls == null) {
|
||||
// return 0;
|
||||
// }
|
||||
// return urls.size();
|
||||
// }
|
||||
//
|
||||
// @SuppressLint("MissingPermission")
|
||||
// @NonNull
|
||||
// @Override
|
||||
// public Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||
// String url = urls.get(position);
|
||||
// ImageRequest imageRequest = ImageRequest.fromUri(url);
|
||||
// boolean isInMemoryCache = mImagePipeline.isInBitmapMemoryCache(imageRequest);
|
||||
// boolean isInDiskCache = imageRequest != null && mImagePipeline.isInDiskCacheSync(imageRequest);
|
||||
//
|
||||
// Gh_RelativeLayout view = (Gh_RelativeLayout) View.inflate(container.getContext(), R.layout.viewimage_normal_item, null);
|
||||
// BigImageView imageView = view.findViewById(R.id.viewimage_iv_show);
|
||||
//
|
||||
// if (!isInMemoryCache
|
||||
// && !isInDiskCache
|
||||
// && !NetworkUtils.isWifiOr4GConnected(ViewImageActivity.this)
|
||||
// && !url.contains(".gif")) {
|
||||
// url = ImageUtils.getTransformLimitUrl(url, mLimitWidth, getApplicationContext());
|
||||
// }
|
||||
//
|
||||
// String finalUrl = url;
|
||||
// imageView.setImageLoaderCallback(new SimpleImageLoader() {
|
||||
// @Override
|
||||
// public void onSuccess(File image) {
|
||||
// if (!finalUrl.equals(urls.get(position))) {
|
||||
// BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
// options.inJustDecodeBounds = true;
|
||||
// BitmapFactory.decodeFile(new File(image.getPath()).getAbsolutePath(), options);
|
||||
// loadImageInfo(position, options.outWidth); // 加载图片参数,目的是用户显示原文按钮
|
||||
// }
|
||||
// SubsamplingScaleImageView ssiv = imageView.getSSIV();
|
||||
// if (ssiv != null) {
|
||||
// ssiv.setMaxScale(10f); // 这个缩放倍数最好很具宽高自动调节
|
||||
// ssiv.setOnImageEventListener(new SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||
// @Override
|
||||
// public void onReady() {
|
||||
// ssiv.resetScaleAndCenter();
|
||||
// }
|
||||
// });
|
||||
// ssiv.setOnClickListener(v -> finish());
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// loadImage(url, imageView);
|
||||
//
|
||||
// //长按
|
||||
// imageView.setOnLongClickListener(v -> {
|
||||
// final Dialog dialog = new Dialog(ViewImageActivity.this);
|
||||
//
|
||||
// LinearLayout container1 = new LinearLayout(ViewImageActivity.this);
|
||||
// container1.setOrientation(LinearLayout.VERTICAL);
|
||||
// container1.setBackgroundColor(Color.WHITE);
|
||||
//
|
||||
// final TextView reportTv = new TextView(ViewImageActivity.this);
|
||||
// reportTv.setPadding(
|
||||
// DisplayUtils.dip2px(ViewImageActivity.this, 20),
|
||||
// DisplayUtils.dip2px(ViewImageActivity.this, 12),
|
||||
// 0,
|
||||
// DisplayUtils.dip2px(ViewImageActivity.this, 12));
|
||||
// reportTv.setText(R.string.save_pic);
|
||||
// reportTv.setTextSize(17);
|
||||
// reportTv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.title));
|
||||
// reportTv.setBackgroundResource(R.drawable.textview_white_style);
|
||||
// int widthPixels = getResources().getDisplayMetrics().widthPixels;
|
||||
// reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10,
|
||||
// LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||
// container1.addView(reportTv);
|
||||
//
|
||||
// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
// dialog.setContentView(container1);
|
||||
//
|
||||
// if (!isFinishing()) {
|
||||
// dialog.show();
|
||||
// }
|
||||
//
|
||||
// reportTv.setOnClickListener(v1 -> {
|
||||
// PermissionHelper.checkStoragePermissionBeforeAction(ViewImageActivity.this, () -> {
|
||||
// saveImageToFile(imageView.getCurrentImageFile(), finalUrl);
|
||||
// dialog.cancel();
|
||||
// });
|
||||
// dialog.cancel();
|
||||
// });
|
||||
//
|
||||
// return false;
|
||||
// });
|
||||
//
|
||||
// view.setTag(position);
|
||||
// container.addView(view);
|
||||
// return view;
|
||||
// }
|
||||
//
|
||||
// private void saveImageToFile(File src, String curUrl) {
|
||||
// InputStream in = null;
|
||||
// OutputStream out = null;
|
||||
// try {
|
||||
// String fileName;
|
||||
// if (mShowBase64Image) {
|
||||
// fileName = MD5Utils.getUrlMD5(curUrl.substring(0, 50)) + ".png";
|
||||
// } else {
|
||||
// fileName = curUrl.substring(curUrl.lastIndexOf("/"));
|
||||
// }
|
||||
// String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/";
|
||||
// File file = new File(savePath);
|
||||
// if (!file.exists()) {
|
||||
// file.mkdirs();
|
||||
// }
|
||||
//
|
||||
// File dst = new File(savePath, fileName);
|
||||
// if (dst.exists()) {
|
||||
// dst.delete();
|
||||
// }
|
||||
//
|
||||
// in = new FileInputStream(src);
|
||||
// out = new FileOutputStream(dst);
|
||||
// byte[] buf = new byte[1024];
|
||||
// int len;
|
||||
// while ((len = in.read(buf)) > 0) {
|
||||
// out.write(buf, 0, len);
|
||||
// }
|
||||
//
|
||||
// Utils.toast(ViewImageActivity.this, "图片已保存到/Pictures/ghzhushou/");
|
||||
// MessageShareUtils.refreshImage(ViewImageActivity.this, dst);
|
||||
// } catch (Exception e) {
|
||||
// Utils.log("图片保存失败:" + e.toString());
|
||||
// } finally {
|
||||
// try {
|
||||
// if (out != null) out.close();
|
||||
// if (in != null) in.close();
|
||||
// } catch (Exception ignore) {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Override
|
||||
// public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||
// container.removeView((View) object);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||
// return view == object;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -2,7 +2,6 @@ package com.gh.gamecenter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
@ -12,16 +11,11 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.IntentUtils;
|
||||
import com.gh.gamecenter.entity.ConcernEntity;
|
||||
import com.gh.gamecenter.entity.NewsEntity;
|
||||
import com.gh.gamecenter.entity.ToolBoxEntity;
|
||||
import com.halo.assistant.fragment.WebFragment;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.halo.assistant.fragment.WebFragment.KEY_GAME_NAME;
|
||||
import static com.halo.assistant.fragment.WebFragment.KEY_REQUIRE_BACK_CONFIRMATION;
|
||||
@ -51,7 +45,6 @@ public class WebActivity extends NormalActivity {
|
||||
} else {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,7 +58,7 @@ public class WebActivity extends NormalActivity {
|
||||
bundle.putBoolean(EntranceUtils.KEY_WEB_SHARE, showWebShare);
|
||||
bundle.putString(EntranceUtils.KEY_URL, url);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, true);
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
return IntentUtils.getWebTargetIntent(context, bundle, url);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -77,7 +70,7 @@ public class WebActivity extends NormalActivity {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getWebIntent(Context context) {
|
||||
public static Intent getUserRegulationWebIntent(Context context) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_GAMENAME, context.getString(R.string.disclaimer_title));
|
||||
bundle.putString(EntranceUtils.KEY_URL, context.getString(R.string.disclaimer_url));
|
||||
@ -169,23 +162,6 @@ public class WebActivity extends NormalActivity {
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static Intent getBadgeCenterIntent(Context context, String userId, String name, String icon) {
|
||||
String url;
|
||||
if (("internal").equals(BuildConfig.FLAVOR)) {
|
||||
url = Constants.BADGE_ADDRESS_DEV;
|
||||
} else {
|
||||
url = Constants.BADGE_ADDRESS;
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s?user_id=%s&name=%s&icon=%s×tamp=%d", url, userId, name, URLEncoder.encode(icon), Math.round((new Date().getTime() / 1000) / 1000));
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_URL, url);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, true);
|
||||
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntentByNews(Context context, ConcernEntity concernEntity, String entrance) {
|
||||
Bundle bundle = new Bundle();
|
||||
@ -206,14 +182,13 @@ public class WebActivity extends NormalActivity {
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, String url, boolean autoCompletionTitle) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_URL, url);
|
||||
bundle.putBoolean(WebFragment.KEY_COMPLETION_TITLE, autoCompletionTitle);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, false);
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
return IntentUtils.getWebTargetIntent(context, bundle, url);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -224,7 +199,7 @@ public class WebActivity extends NormalActivity {
|
||||
bundle.putBoolean(WebFragment.KEY_COMPLETION_TITLE, autoCompletionTitle);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, false);
|
||||
bundle.putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, isOpenNativePage);
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
return IntentUtils.getWebTargetIntent(context, bundle, url);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -237,20 +212,7 @@ public class WebActivity extends NormalActivity {
|
||||
bundle.putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, false);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_BACK_PRESSED, isWebPageHandleBackPressed);
|
||||
bundle.putInt(WebFragment.KEY_QA_TYPE, qaType);
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntentByUrl(Context context, String url) {
|
||||
return getIntentByUrl(context, url, false);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntentByUrl(Context context, String url, boolean leaveWebPageHandleTitle) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_URL, url);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, leaveWebPageHandleTitle);
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
return IntentUtils.getWebTargetIntent(context, bundle, url);
|
||||
}
|
||||
|
||||
public static Intent getIntentForWebGame(Context context, String url, String gameName, boolean interveneBackpress, String closeButton) {
|
||||
@ -263,7 +225,7 @@ public class WebActivity extends NormalActivity {
|
||||
bundle.putBoolean(KEY_REQUIRE_BACK_CONFIRMATION, true);
|
||||
bundle.putString(WebFragment.KEY_BACK_CONFIRMATION_CONTENT, "退出后将不保存当前游戏进度,确定退出吗?");
|
||||
}
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
return IntentUtils.getWebTargetIntent(context, bundle, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -18,6 +18,7 @@ import com.gh.common.util.EnergyTaskHelper;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.IntegralLogHelper;
|
||||
import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.NewLogUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.gamecenter.eventbus.EBShare;
|
||||
import com.lightgame.utils.Utils;
|
||||
@ -233,6 +234,11 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback {
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("成功", "微博");
|
||||
}
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
|
||||
NewLogUtils.logShareResult(true);
|
||||
}
|
||||
} else {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("成功", "微博");
|
||||
}
|
||||
@ -248,6 +254,11 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback {
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("取消", "微博");
|
||||
}
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
|
||||
NewLogUtils.logShareResult(false);
|
||||
}
|
||||
} else {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("取消", "微博");
|
||||
}
|
||||
@ -263,6 +274,11 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback {
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("失败", "微博");
|
||||
}
|
||||
if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle ||
|
||||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
|
||||
NewLogUtils.logShareResult(false);
|
||||
}
|
||||
} else {
|
||||
IntegralLogHelper.INSTANCE.logInviteResult("失败", "微博");
|
||||
}
|
||||
|
||||
@ -326,7 +326,8 @@ public class DetailViewHolder {
|
||||
}
|
||||
|
||||
if (mViewHolder.mDownloadPb.getDownloadType() != DownloadProgressBar.DownloadType.INSTALL_NORMAL
|
||||
&& mViewHolder.mDownloadPb.getDownloadType() != DownloadProgressBar.DownloadType.INSTALL_PLUGIN) {
|
||||
&& mViewHolder.mDownloadPb.getDownloadType() != DownloadProgressBar.DownloadType.INSTALL_PLUGIN
|
||||
&& mViewHolder.mDownloadPb.getDownloadType() != DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN) {
|
||||
EventBus.getDefault().post(new EBScroll(Constants.EB_GAME_DETAIL, mGameEntity.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,8 @@ import com.gh.common.util.dip2px
|
||||
import com.gh.gamecenter.databinding.GameHeadItemBinding
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
|
||||
class GameHeadViewHolder(var binding: GameHeadItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
class GameHeadViewHolder(var binding: GameHeadItemBinding) :
|
||||
BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
fun bindHead(subject: SubjectEntity) {
|
||||
val headContainerLp = binding.headContainer.layoutParams
|
||||
@ -24,10 +25,19 @@ class GameHeadViewHolder(var binding: GameHeadItemBinding) : BaseRecyclerViewHol
|
||||
|
||||
binding.subject = subject
|
||||
binding.headPb.visibility = View.GONE
|
||||
val text = if ("change" == subject.home) "换一批" else "全部 >"
|
||||
val text = if ("change" == subject.home) {
|
||||
"换一批"
|
||||
} else {
|
||||
when (subject.home) {
|
||||
"more" -> "更多 >"
|
||||
"hide" -> ""
|
||||
else -> "全部 >"
|
||||
}
|
||||
}
|
||||
binding.headMore.text = text
|
||||
|
||||
if (subject.indexRightTop != null && subject.indexRightTop != "none") {
|
||||
// 开测表用到的
|
||||
binding.headMore.visibility = View.VISIBLE
|
||||
if (subject.indexRightTop == "all") {
|
||||
binding.headMore.text = "全部 >"
|
||||
@ -40,6 +50,8 @@ class GameHeadViewHolder(var binding: GameHeadItemBinding) : BaseRecyclerViewHol
|
||||
&& subject.type != "column_collection"
|
||||
&& subject.type != "gallery_slide") {
|
||||
binding.headMore.visibility = View.GONE
|
||||
} else if (subject.home == "hide"){
|
||||
binding.headMore.visibility = View.GONE
|
||||
} else {
|
||||
binding.headMore.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.gamecenter.adapter.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
@ -24,6 +25,10 @@ public class GameViewHolder extends BaseRecyclerViewHolder {
|
||||
public LinearLayout gameLabelList;
|
||||
public LinearLayout gameInfo;
|
||||
public ProgressBar gameProgressbar;
|
||||
@Nullable
|
||||
public View recommendContainer;
|
||||
public TextView recommendTv;
|
||||
public ImageView recommendIv;
|
||||
public TextView gameDownloadSpeed;
|
||||
public TextView gameDownloadPercentage;
|
||||
public TextView gameServerType;
|
||||
@ -44,6 +49,9 @@ public class GameViewHolder extends BaseRecyclerViewHolder {
|
||||
gameDes = binding.gameDes;
|
||||
gameDownloadSpeed = binding.downloadSpeed;
|
||||
gameRating = binding.gameRating;
|
||||
recommendContainer = binding.recommendContainer;
|
||||
recommendTv = binding.recommendTv;
|
||||
recommendIv = binding.recommendIv;
|
||||
}
|
||||
|
||||
public void initServerType(GameEntity gameEntity) {
|
||||
|
||||
@ -214,9 +214,13 @@ class AmwayFragment : LazyListFragment<AmwayListItemData, AmwayViewModel>() {
|
||||
MtaHelper.onEventWithTime("安利墙", mElapsedHelper.elapsedTime, "浏览")
|
||||
}
|
||||
|
||||
override fun onFragmentResume() {
|
||||
override fun onResume() {
|
||||
if (isEverPause) mAdapter?.notifyDataSetChanged()
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onFragmentResume() {
|
||||
super.onFragmentResume()
|
||||
DownloadManager.getInstance(context).addObserver(dataWatcher)
|
||||
|
||||
mElapsedHelper.resetCounting()
|
||||
|
||||
@ -30,7 +30,15 @@ class AmwaySuccessFragment : NormalFragment() {
|
||||
setNavigationTitle("安利墙")
|
||||
|
||||
checkCommentBtn.setOnClickListener {
|
||||
GameDetailActivity.startGameDetailCommentActivity(requireContext(), mGameEntity, "安利墙")
|
||||
if (mGameEntity != null) {
|
||||
GameDetailActivity.startGameDetailCommentActivity(
|
||||
requireContext(),
|
||||
mGameEntity,
|
||||
"安利墙"
|
||||
)
|
||||
} else {
|
||||
requireActivity().finish()
|
||||
}
|
||||
}
|
||||
|
||||
checkAmwayBtn.setOnClickListener {
|
||||
|
||||
@ -226,7 +226,9 @@ public abstract class LazyListFragment<T, VM extends BaseListViewModel /* 该泛
|
||||
mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
|
||||
if (mReuseNoData != null) mReuseNoData.setVisibility(View.GONE);
|
||||
|
||||
mListRv.setVisibility(View.GONE);
|
||||
if (mListRv != null) {
|
||||
mListRv.setVisibility(View.GONE);
|
||||
}
|
||||
mBaseHandler.postDelayed(() -> {
|
||||
mListViewModel.load(LoadType.REFRESH);
|
||||
}, 500);
|
||||
|
||||
@ -145,6 +145,7 @@ public abstract class ListFragment<T, VM extends BaseListViewModel /* 该泛型
|
||||
mListRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
if (!shouldLoadMore()) return;
|
||||
RecyclerView.LayoutManager layoutManager = mListRv.getLayoutManager();
|
||||
if (layoutManager instanceof LinearLayoutManager) {
|
||||
if (((LinearLayoutManager) layoutManager).findLastVisibleItemPosition() == provideListAdapter().getItemCount() - 1
|
||||
@ -282,4 +283,8 @@ public abstract class ListFragment<T, VM extends BaseListViewModel /* 该泛型
|
||||
protected void hideRefreshingLayout() {
|
||||
if (mListRefresh != null) mListRefresh.setRefreshing(false);
|
||||
}
|
||||
|
||||
protected boolean shouldLoadMore() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +137,10 @@ public abstract class ListViewModel<LD /*ListData*/, ID /*ItemData*/> extends Ba
|
||||
loadStatusControl(response.size());
|
||||
}
|
||||
|
||||
public MutableLiveData<List<LD>> getListLiveData(){
|
||||
return mListLiveData;
|
||||
}
|
||||
|
||||
private void handleFailure(Exception exception) {
|
||||
if (exception instanceof HttpException && ((HttpException) exception).code() == 404) {
|
||||
loadStatusControl(0);
|
||||
|
||||
@ -33,6 +33,9 @@ class CatalogFragment : LazyFragment() {
|
||||
mViewModel = viewModelProviderFromParent(CatalogViewModel.Factory(mCatalogId, mCatalogTitle), mCatalogId)
|
||||
|
||||
mViewModel?.validEntranceName = if (mEntrance.contains("首页")) "首页" else "板块"
|
||||
if (arguments?.getBoolean(EntranceUtils.KEY_IS_HOME) == true) {
|
||||
mViewModel?.validEntranceName = "首页Tab栏"
|
||||
}
|
||||
mViewModel?.logAppearance()
|
||||
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
@ -8,10 +8,7 @@ import butterknife.BindView
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.observeNonNull
|
||||
import com.gh.common.util.viewModelProvider
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.ConfigFilterView
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.common.xapk.XapkUnzipStatus
|
||||
@ -139,7 +136,7 @@ class NewCategoryListFragment : ListFragment<GameEntity, NewCategoryListViewMode
|
||||
for (index in 0 until categoryList.size) {
|
||||
if (categoryList[index].name == mViewModel.selectedCategory.name) {
|
||||
tagsRecyclerView.postDelayed({
|
||||
tagsRecyclerView.smoothScrollToPosition(index)
|
||||
tryCatchInRelease { tagsRecyclerView.smoothScrollToPosition(index) }
|
||||
}, 200)
|
||||
break
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.gamecenter.category2
|
||||
import android.graphics.Color
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
@ -39,14 +40,15 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
mCategoryTitle = arguments?.getString(EntranceUtils.KEY_CATEGORY_TITLE) ?: ""
|
||||
mViewModel = viewModelProviderFromParent(CategoryV2ViewModel.Factory(mCategoryId, mCategoryTitle), mCategoryId)
|
||||
|
||||
// 除了这里以外,下面还有一个判断是否为首页 tab 栏的赋值
|
||||
mViewModel?.entrance = if (mEntrance.contains("首页")) "首页" else "板块"
|
||||
if (arguments?.getBoolean(EntranceUtils.KEY_IS_HOME) == true) {
|
||||
mHomeViewModel = viewModelProviderFromParent()
|
||||
mViewModel?.entrance = "首页Tab栏"
|
||||
}
|
||||
mViewModel?.logAppearance()
|
||||
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
if (arguments?.getBoolean(EntranceUtils.KEY_IS_HOME) == true) {
|
||||
mHomeViewModel = viewModelProviderFromParent()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
@ -63,6 +65,21 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
drawerLayout.setScrimColor(R.color.black_alpha_30.toColor())
|
||||
// 关闭手势滑动
|
||||
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
}
|
||||
|
||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
showGuide()
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
}
|
||||
|
||||
})
|
||||
directoryContainer.layoutParams.width = width
|
||||
directoryRv.layoutParams.width = width
|
||||
|
||||
@ -131,6 +148,33 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
})
|
||||
}
|
||||
|
||||
fun removeGuide() {
|
||||
mBinding?.run {
|
||||
guideContainer.visibility = View.GONE
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_CATEGORY_GUIDE, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showGuide() {
|
||||
mBinding?.run {
|
||||
val isShow = SPUtils.getBoolean(Constants.SP_SHOW_CATEGORY_GUIDE)
|
||||
if (isShow) return
|
||||
|
||||
guideContainer.layoutParams = (guideContainer.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
val screenWidth = resources.displayMetrics.widthPixels
|
||||
leftMargin = screenWidth * 66F.dip2px() / 360F.dip2px()
|
||||
}
|
||||
guideContainer.visibility = View.VISIBLE
|
||||
|
||||
postDelayedRunnable({
|
||||
tryCatchInRelease {
|
||||
guideContainer.visibility = View.GONE
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_CATEGORY_GUIDE, true)
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(menuItem: MenuItem?) {
|
||||
menuItem?.run {
|
||||
if (itemId == R.id.menu_search) {
|
||||
@ -222,7 +266,7 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
if (SPUtils.getBoolean(Constants.SP_FIRST_ENTER_CATEGORY_V2, true)) {
|
||||
SPUtils.setBoolean(Constants.SP_FIRST_ENTER_CATEGORY_V2, false)
|
||||
mBinding?.drawerLayout?.postDelayed({
|
||||
openDrawer()
|
||||
tryCatchInRelease { openDrawer() }
|
||||
}, 500L)
|
||||
}
|
||||
}
|
||||
@ -253,6 +297,8 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
.commitAllowingStateLoss()
|
||||
} else {
|
||||
if (position == 0) {
|
||||
removeGuide()
|
||||
|
||||
mSpecialCatalogFragment = childFragmentManager
|
||||
.findFragmentByTag(SpecialCatalogFragment::class.java.simpleName)
|
||||
as? SpecialCatalogFragment ?: SpecialCatalogFragment()
|
||||
@ -307,6 +353,8 @@ class CategoryV2Fragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (sidebar.name == "全部" && selectedCategoryList.isNotEmpty()) {
|
||||
i = selectedCategoryList[0].primaryIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +103,6 @@ class CategoryV2ListAdapter(context: Context,
|
||||
|
||||
gameName.run {
|
||||
textSize = 13F
|
||||
typeface = Typeface.DEFAULT
|
||||
}
|
||||
|
||||
gameDescContainer.layoutParams = (gameDescContainer.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
|
||||
@ -104,14 +104,22 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
logClickReset("游戏列表")
|
||||
resetDirectoryList()
|
||||
}
|
||||
resetSortSize()
|
||||
changeCategoryTab()
|
||||
openDirectoryLayout()
|
||||
// openDirectoryLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetSortSize() {
|
||||
mBinding?.filterContainer?.resetSortSize()
|
||||
mListViewModel?.sortSize = SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")
|
||||
|
||||
}
|
||||
|
||||
private fun initFilterView() {
|
||||
mBinding?.filterContainer?.run {
|
||||
visibility = View.VISIBLE
|
||||
|
||||
setOnConfigSetupListener(object : CategoryFilterView.OnCategoryFilterSetupListener {
|
||||
override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
|
||||
mListViewModel?.updateSortConfig(sortSize = sortSize)
|
||||
@ -125,6 +133,21 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
openDirectoryLayout()
|
||||
}
|
||||
})
|
||||
|
||||
setOnFilterClickListener(object : CategoryFilterView.OnFilterClickListener {
|
||||
override fun onCategoryClick() {
|
||||
removeGuide()
|
||||
}
|
||||
|
||||
override fun onTypeClick() {
|
||||
removeGuide()
|
||||
}
|
||||
|
||||
override fun onSizeClick() {
|
||||
removeGuide()
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,6 +245,10 @@ class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeGuide() {
|
||||
(parentFragment as? CategoryV2Fragment)?.removeGuide()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged()
|
||||
super.onResume()
|
||||
|
||||
@ -16,15 +16,15 @@ import com.gh.gamecenter.baselist.ListAdapter;
|
||||
import com.gh.gamecenter.baselist.LoadType;
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding;
|
||||
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder;
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity;
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import kotlin.Pair;
|
||||
|
||||
/**
|
||||
@ -99,7 +99,8 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> implements ISyncAda
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (entity.getActive()) {
|
||||
mContext.startActivity(AnswerDetailActivity.getIntent(mContext, entity.getId(), mEntrance, path));
|
||||
// mContext.startActivity(AnswerDetailActivity.getIntent(mContext, entity.getId(), mEntrance, path));
|
||||
mContext.startActivity(NewQuestionDetailActivity.getCommentIntent(mContext, entity.getQuestions().getId(), entity.getId(), mEntrance, path));
|
||||
} else {
|
||||
showDeleteDialog(entity.getId());
|
||||
}
|
||||
@ -112,7 +113,8 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> implements ISyncAda
|
||||
});
|
||||
viewHolder.getBinding().title.setOnClickListener(v -> {
|
||||
Questions questions = entity.getQuestions();
|
||||
mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
|
||||
// mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
|
||||
mContext.startActivity(NewQuestionDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
|
||||
});
|
||||
break;
|
||||
case ItemViewType.ITEM_FOOTER:
|
||||
|
||||
@ -13,9 +13,11 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.baselist.ListAdapter
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
|
||||
class CommunityArticleAdapter(context: Context,
|
||||
private val mViewModel: CommunityArticleViewModel,
|
||||
@ -68,14 +70,21 @@ class CommunityArticleAdapter(context: Context,
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.bbs == CommunityEntity()) {
|
||||
entity.bbs = entity.community
|
||||
}
|
||||
holder.bindArticleItem(entity, mEntrance, path)
|
||||
holder.itemView.setOnClickListener {
|
||||
if (entity.active) {
|
||||
mContext.startActivity(ArticleDetailActivity.getIntent(mContext, entity.community, entity.id, mEntrance, path))
|
||||
if (entity.type == "question") {
|
||||
mContext.startActivity(NewQuestionDetailActivity.getIntent(mContext, entity.id, mEntrance, path))
|
||||
} else {
|
||||
DialogUtils.showCancelAlertDialog(mContext, "提示", "内容已被删除,是否取消收藏?", "取消收藏", "暂不", {
|
||||
mViewModel.deleteCollection(entity.community.id, entity.id)
|
||||
}, null)
|
||||
if (entity.active) {
|
||||
mContext.startActivity(ArticleDetailActivity.getIntent(mContext, entity.community, entity.id, mEntrance, path))
|
||||
} else {
|
||||
DialogUtils.showCancelAlertDialog(mContext, "提示", "内容已被删除,是否取消收藏?", "取消收藏", "暂不", {
|
||||
mViewModel.deleteCollection(entity.community.id, entity.id)
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
|
||||
if (!entity.read) {
|
||||
|
||||
@ -9,6 +9,7 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.baselist.ListViewModel
|
||||
import com.gh.gamecenter.baselist.LoadType
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
@ -17,11 +18,11 @@ import com.lightgame.utils.Utils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.Function
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
|
||||
|
||||
class CommunityArticleViewModel(application: Application) : ListViewModel<ArticleEntity, ArticleEntity>(application) {
|
||||
|
||||
var type: String = CommunityArticleFragment.Type.COLLECTION.value
|
||||
@ -32,7 +33,17 @@ class CommunityArticleViewModel(application: Application) : ListViewModel<Articl
|
||||
|
||||
override fun provideDataSingle(page: Int): Single<List<ArticleEntity>> {
|
||||
return if (type == CommunityArticleFragment.Type.COLLECTION.value) {
|
||||
Single.fromObservable(RetrofitManager.getInstance(getApplication()).api.getCollectionCommunityArticle(UserManager.getInstance().userId, page))
|
||||
Single.fromObservable(
|
||||
RetrofitManager.getInstance(getApplication()).api
|
||||
.getCollectionArticleAndQuestion(UserManager.getInstance().userId, page)
|
||||
.flatMap(Function<List<AnswerEntity>, Observable<List<ArticleEntity>>> { list ->
|
||||
Observable.create { emitter->
|
||||
val articleList = list.map { it.transformArticleEntity() }.toList()
|
||||
emitter.onNext(articleList)
|
||||
emitter.onComplete()
|
||||
}
|
||||
})
|
||||
)
|
||||
} else {
|
||||
if (page > 5) {
|
||||
Single.create { it.onSuccess(arrayListOf()) }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user