Compare commits
228 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cdc76b548 | |||
| b56ecfbf8f | |||
| 27c0b4c497 | |||
| de1558d58f | |||
| 0197355126 | |||
| e66698d2bd | |||
| def5996c49 | |||
| 700fd2e390 | |||
| 21a8eaafeb | |||
| 4391891999 | |||
| 8302e8b5e0 | |||
| a8de52d5cd | |||
| 46a42c9212 | |||
| 9ed97ea32c | |||
| 4f087cdcc7 | |||
| 4c4fcba2d2 | |||
| 69e9bfa7a9 | |||
| c3b29697bc | |||
| f0937e8d1e | |||
| 85f713dc2d | |||
| cd146366c0 | |||
| 08054ad6e5 | |||
| 011b4b536a | |||
| d2e118180c | |||
| 93856925ba | |||
| da0a33798b | |||
| 33f4f2e60b | |||
| 5827583edc | |||
| 2b33d95329 | |||
| 7f0be97170 | |||
| b6a0fa9196 | |||
| 52c624e94b | |||
| de847ac0d5 | |||
| 2bb579fec7 | |||
| 6a6b15fb14 | |||
| 81e6778148 | |||
| 309a6a6425 | |||
| 65e5ca64a1 | |||
| 69825d33ff | |||
| ec4acd0043 | |||
| 22bb168e49 | |||
| b7bea01eb1 | |||
| 82c3591d25 | |||
| 20d8de32ec | |||
| 3976646f39 | |||
| c849d4e0b0 | |||
| 671fab2fee | |||
| 8491609da7 | |||
| 67257748f9 | |||
| 312a3fe7bb | |||
| 2c16c54c96 | |||
| bbae5f0b9c | |||
| 95022da700 | |||
| 6471e95077 | |||
| 707e6f5d11 | |||
| 66dfcc8064 | |||
| 0400b7d396 | |||
| 96d4ca43ff | |||
| d2c0699b66 | |||
| 0e4cf2cd3a | |||
| 8144a7e857 | |||
| ea38698ac3 | |||
| d00b34ebdd | |||
| a4c285df6f | |||
| 6dfd9d5b7a | |||
| 876f7317a8 | |||
| 430a975e98 | |||
| f277319019 | |||
| 6b9fedd289 | |||
| d0ad48ada2 | |||
| a6b7beed75 | |||
| fa257e4a04 | |||
| 8d827b7275 | |||
| 27d73b545c | |||
| 7802d961a3 | |||
| d5d63371e3 | |||
| fcf1d38578 | |||
| fe17f817da | |||
| bfa76c0fda | |||
| 2e1a99f905 | |||
| e7cb8e41b5 | |||
| f88d4bde45 | |||
| b470194807 | |||
| ba5e3cb3eb | |||
| d5440b5d01 | |||
| a8f3f27fb3 | |||
| bec06bfbf4 | |||
| 9c510dc132 | |||
| 8302c99d57 | |||
| 5209e5b463 | |||
| 663e5124fe | |||
| dea2f569a1 | |||
| 03d25eaeae | |||
| e84f56975d | |||
| a3a21efba3 | |||
| 1daa4f91b3 | |||
| ee1ddbcdce | |||
| 772549e543 | |||
| db537e756a | |||
| f9c236fd63 | |||
| f414ecee32 | |||
| 5b1d0d5821 | |||
| 1c80ba56a5 | |||
| a92044f815 | |||
| 00f94bf950 | |||
| e27f061a92 | |||
| 40d28948e1 | |||
| 9b6e29d5f2 | |||
| 0ee000f08a | |||
| 6bdd021856 | |||
| 301e14268a | |||
| 825ea594f4 | |||
| 8fcb072abb | |||
| f17a4e6372 | |||
| a5b1202e5e | |||
| b5e025984c | |||
| 33dba4e9bf | |||
| 92492b21ae | |||
| 1c8ca4b8c2 | |||
| 466061222d | |||
| 905e229142 | |||
| 6906b96ef9 | |||
| fb748df3ce | |||
| 844de786d0 | |||
| 7dfe55014a | |||
| 24f19e2a61 | |||
| f947040241 | |||
| 569bb61545 | |||
| 78ea8b3e73 | |||
| 6b5056da41 | |||
| 2a86546f1a | |||
| d669fec902 | |||
| 3fc14b5194 | |||
| 4a3a039d0e | |||
| 1f43523f04 | |||
| 26e23fa736 | |||
| 958bce8d42 | |||
| 8f15e52eb5 | |||
| 4bedede646 | |||
| f66ee1721e | |||
| 138c5bb4c2 | |||
| d1245a9a1e | |||
| 561d6f7ea2 | |||
| d5992f7ed3 | |||
| d941aa0c71 | |||
| 7fa1d1e11b | |||
| 3edff028bf | |||
| 78d3c529c6 | |||
| f0af2e280b | |||
| 34623163e6 | |||
| c90bd007c7 | |||
| 5f9637ec50 | |||
| 1a05e13b03 | |||
| c835f88695 | |||
| 5674fe76a2 | |||
| e6933b4ded | |||
| 8a10dac03d | |||
| de71ebad52 | |||
| 310d1a2d5c | |||
| 30fcaf190b | |||
| f004b15cf0 | |||
| 480c91feb5 | |||
| 2c70b7eefc | |||
| 2be2513081 | |||
| 48c0d5d2cd | |||
| 3c5a6bcdec | |||
| bd2a3d529a | |||
| 6c0ac67cfa | |||
| cb07b8c9f4 | |||
| e22be3f233 | |||
| fd02f120c2 | |||
| 6496b3dad6 | |||
| 375b57cd3d | |||
| 269265b054 | |||
| d74154080b | |||
| 7471825a7c | |||
| 90580316e8 | |||
| 61e0ef2960 | |||
| 1125bb9b4c | |||
| 1e424a3791 | |||
| a901d95895 | |||
| 1a0a92c542 | |||
| 6ba8344292 | |||
| 38d2429183 | |||
| 36c755f781 | |||
| 093c731ba7 | |||
| eae9c11d72 | |||
| 3faae4b34c | |||
| 04eef35cbd | |||
| 6b08cb2159 | |||
| 0777ca90e0 | |||
| 4a322d07d9 | |||
| df49f98e46 | |||
| 122e3f6aa0 | |||
| b902837b1c | |||
| 62639a9c79 | |||
| 06dc7fc566 | |||
| ece6e099ec | |||
| f3ce82275a | |||
| 4000dd8383 | |||
| d67053ce7c | |||
| 37bca1ee1c | |||
| 229d3e9c88 | |||
| c5d79a014b | |||
| 7d609b9c2a | |||
| 97eabcc600 | |||
| 932863a73f | |||
| 4014fc27af | |||
| fdf7be4a9f | |||
| b0fd801fec | |||
| 34c0bbe434 | |||
| 92c5697565 | |||
| 445759e511 | |||
| a5b32cc099 | |||
| 7a5f24bfe7 | |||
| b40d58f1ae | |||
| ef28fc3616 | |||
| 80d2e2c488 | |||
| ca07f10c9d | |||
| 8a7fa127ba | |||
| 8ee6039a2b | |||
| aac58029f6 | |||
| 640a8d4e0f | |||
| 9f621696c1 | |||
| a45fff7cca | |||
| 8f37cbdfde | |||
| 3ffd6f74f1 | |||
| 3f9fb27642 |
16
README.md
16
README.md
@ -1,9 +1,5 @@
|
||||
# 光环助手Android客户端
|
||||
|
||||
### sourcesets/debug/release
|
||||
|
||||
* https://developer.android.com/studio/build/build-variants.html#sourcesets
|
||||
|
||||
### APK打包配置
|
||||
|
||||
* 使用[ApkChannelPackage](https://github.com/ltlovezh/ApkChannelPackage)的方案
|
||||
@ -51,7 +47,7 @@
|
||||
* ~~Adapter ViewHolder的功能,部分重写到ViewHolder类本身~~
|
||||
|
||||
* ~~activity 统一入口未完成(外部入口相关),去除多余activity使用,统一toolbar~~
|
||||
* release / debug compile不同的类库,不需要再做什么开关
|
||||
* ~~release / debug compile不同的类库,不需要再做什么开关~~
|
||||
|
||||
* ~~Toolbar分离,有图形按钮/没有图形按钮~~
|
||||
|
||||
@ -59,12 +55,12 @@
|
||||
|
||||
- 解决 Utils 工具类引发的内存泄漏问题
|
||||
- 把原有 EventBus 的消息 Type 统一到一个文件内
|
||||
- 明确 MVVM 中 Repository 及其衍生类的具体实现方式
|
||||
- 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
|
||||
- 将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中
|
||||
- ~~将 ListViewModel 所对应的 ListRepository 合并到 ListViewModel 中~~
|
||||
- 依照光环助手界面功能以大模块 - 小模块的方式去修改包结构,包内文件建议以包名摘要作为前缀
|
||||
- 使用 RxJava 的 Debounce 和 Map 操作优化搜索触发机制 参考资料:[1](https://proandroiddev.com/building-an-autocompleting-edittext-using-rxjava-f69c5c3f5a40),[2](https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352)
|
||||
- ~~使用 RxJava 的 Debounce 和 Map 操作优化搜索触发机制 参考资料:[1](https://proandroiddev.com/building-an-autocompleting-edittext-using-rxjava-f69c5c3f5a40),[2](https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352)~~
|
||||
|
||||
- 把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题
|
||||
- ~~把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题~~
|
||||
|
||||
- 上传图片改为用Retrofit上传
|
||||
- ~~rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) 解决方法->com.gh.gamecenter.retrofit.Response~~
|
||||
- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗)
|
||||
@ -25,7 +25,8 @@ android {
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
jumboMode = true
|
||||
// jumboMode = true
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
@ -88,13 +89,10 @@ android {
|
||||
debuggable true
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
versionNameSuffix "-debug"
|
||||
signingConfig signingConfigs.debug
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E1\""
|
||||
}
|
||||
release {
|
||||
debuggable false
|
||||
@ -103,10 +101,8 @@ android {
|
||||
shrinkResources true
|
||||
signingConfig signingConfigs.release
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E1\""
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,12 +122,21 @@ android {
|
||||
buildConfigField "String", "MESSAGE_HOST", "\"${MESSAGE_HOST}\""
|
||||
buildConfigField "String", "DATA_HOST", "\"${DATA_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
|
||||
}
|
||||
// internal test dev host
|
||||
internal {
|
||||
dimension "nonsense"
|
||||
versionNameSuffix "-debug"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
|
||||
buildConfigField "String", "USER_HOST", "\"${DEV_USER_HOST}\""
|
||||
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
|
||||
@ -139,6 +144,13 @@ android {
|
||||
buildConfigField "String", "MESSAGE_HOST", "\"${DEV_MESSAGE_HOST}\""
|
||||
buildConfigField "String", "DATA_HOST", "\"${DEV_DATA_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${DEBUG_MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${DEBUG_MEIZUPUSH_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${DEBUG_BUGLY_APPID}\""
|
||||
}
|
||||
}
|
||||
@ -184,7 +196,6 @@ dependencies {
|
||||
implementation "com.android.support:percent:${androidSupport}"
|
||||
implementation "com.android.support.constraint:constraint-layout:${constraintLayout}"
|
||||
implementation "com.kyleduo.switchbutton:library:${switchButton}"
|
||||
implementation "com.readystatesoftware.systembartint:systembartint:${systemBarTint}"
|
||||
|
||||
implementation "com.facebook.fresco:fresco:${fresco}"
|
||||
implementation "com.facebook.fresco:animated-gif:${fresco}"
|
||||
@ -195,8 +206,7 @@ dependencies {
|
||||
|
||||
implementation "com.squareup.retrofit2:retrofit:${retrofit}"
|
||||
implementation "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava:${retrofit}"
|
||||
// implementation "com.google.code.gson:gson:${gson}"
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit}"
|
||||
|
||||
implementation "com.j256.ormlite:ormlite-android:${ormlite}"
|
||||
implementation "com.j256.ormlite:ormlite-core:${ormlite}"
|
||||
@ -209,14 +219,9 @@ dependencies {
|
||||
implementation "org.greenrobot:eventbus:${eventbus}"
|
||||
annotationProcessor "org.greenrobot:eventbus-annotation-processor:${eventbusApt}"
|
||||
|
||||
implementation "io.reactivex:rxjava:${rxJava}"
|
||||
implementation "io.reactivex:rxandroid:${rxAndroid}"
|
||||
implementation "com.jakewharton.rxbinding:rxbinding:${rxBinding}"
|
||||
|
||||
//TODO update to rx 2.x
|
||||
// implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
|
||||
// implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
|
||||
// implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
|
||||
implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
|
||||
implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
|
||||
implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
|
||||
|
||||
implementation "com.google.zxing:core:${zxing}"
|
||||
implementation "com.google.zxing:android-core:${zxing}"
|
||||
@ -242,13 +247,15 @@ dependencies {
|
||||
implementation 'com.google.android:flexbox:0.2.2'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
kapt 'com.android.databinding:compiler:3.0.1'
|
||||
kapt 'com.android.databinding:compiler:3.1.3'
|
||||
|
||||
implementation 'com.contrarywind:Android-PickerView:4.1.3'
|
||||
|
||||
implementation "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}"
|
||||
implementation "net.cachapa.expandablelayout:expandablelayout:${expandableLayout}"
|
||||
|
||||
implementation "top.zibin:Luban:${luban}"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
implementation project(':libraries:MTA')
|
||||
implementation project(':libraries:QQShare')
|
||||
@ -257,7 +264,7 @@ dependencies {
|
||||
implementation project(':libraries:WechatShare')
|
||||
implementation project(':libraries:iosched')
|
||||
implementation project(':libraries:LogHub')
|
||||
|
||||
implementation project(':libraries:im')
|
||||
}
|
||||
File propFile = file('sign.properties')
|
||||
if (propFile.exists()) {
|
||||
@ -287,3 +294,31 @@ if (propFile.exists()) {
|
||||
} else {
|
||||
android.buildTypes.release.signingConfig = null
|
||||
}
|
||||
|
||||
// 用于测试读取 META-INF 里的 JSON 的代码
|
||||
//task generateMetaJson {
|
||||
// def resDir = new File(buildDir, 'generated/FILES_FOR_META_INF/')
|
||||
// def destDir = new File(resDir, 'META-INF/')
|
||||
// // Add resDir as a resource directory so that it is automatically included in the APK.
|
||||
// android {
|
||||
// sourceSets {
|
||||
// main.resources {
|
||||
// srcDir resDir
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// doLast {
|
||||
// if (!destDir.exists()) destDir.mkdirs()
|
||||
// copy {
|
||||
// into destDir
|
||||
// from new File('generated/FILES_FOR_META_INF/META-INF/halo_skip.json')
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//// Specify when put_files_in_META_INF should run
|
||||
//project.afterEvaluate {
|
||||
// tasks.findAll { task ->
|
||||
// task.name.startsWith('merge') && task.name.endsWith('Resources')
|
||||
// }.each { t -> t.dependsOn generateMetaJson }
|
||||
//}
|
||||
|
||||
@ -107,7 +107,7 @@
|
||||
android:name = "com.gh.gamecenter.ConcernActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.SubjectActivity"
|
||||
android:name = "com.gh.gamecenter.subject.refactor.SubjectActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.PluginActivity"
|
||||
@ -299,13 +299,13 @@
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.qa.ask.QuestionEditActivity"
|
||||
android:name = "com.gh.gamecenter.qa.questions.edit.QuestionEditActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.kaifu.add.AddKaiFuActivity"
|
||||
android:screenOrientation = "portrait"
|
||||
android:windowSoftInputMode = "stateHidden"/>
|
||||
android:windowSoftInputMode = "stateHidden" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.kaifu.patch.PatchKaifuActivity"
|
||||
@ -323,6 +323,27 @@
|
||||
android:name = "com.gh.gamecenter.NetworkDiagnosisActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.personalhome.fans.FansActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.personalhome.fans.FollowersActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.PersonalHomeActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.personalhome.answer.PersonalAnswerActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.personalhome.question.PersonalQuestionActivity"
|
||||
android:screenOrientation = "portrait" />
|
||||
|
||||
|
||||
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
|
||||
<activity
|
||||
android:name = "com.gh.gamecenter.PushProxyActivity"
|
||||
@ -383,6 +404,40 @@
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
|
||||
<receiver android:name = "com.gh.gamecenter.receiver.UmengMessageReceiver" >
|
||||
<intent-filter >
|
||||
<action android:name = "com.gh.gamecenter.UMENG" />
|
||||
</intent-filter >
|
||||
</receiver >
|
||||
|
||||
<!--魅族push应用定义消息receiver声明 -->
|
||||
<receiver android:name="com.gh.gamecenter.receiver.MeizuPushReceiver">
|
||||
<intent-filter>
|
||||
<!-- 接收push消息 -->
|
||||
<action android:name="com.meizu.flyme.push.intent.MESSAGE" />
|
||||
<!-- 接收register消息 -->
|
||||
<action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
|
||||
<!-- 接收unregister消息-->
|
||||
<action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />
|
||||
<!-- 兼容低版本Flyme3推送服务配置 -->
|
||||
<action android:name="com.meizu.c2dm.intent.REGISTRATION" />
|
||||
<action android:name="com.meizu.c2dm.intent.RECEIVE" />
|
||||
|
||||
<category android:name="${applicationId}"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="com.gh.common.im.ImReceiver"
|
||||
android:enabled="true">
|
||||
<intent-filter android:priority="2147483647">
|
||||
<action android:name="com.gh.im"/>
|
||||
<action android:name="action_finish"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name = "com.gh.base.GHUmengNotificationService" />
|
||||
|
||||
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
|
||||
|
||||
</application >
|
||||
|
||||
@ -13,7 +13,11 @@ function setupWhenContentEditable() {
|
||||
e.preventDefault();
|
||||
var text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
text = text.replace(/\n/g, '<br>');
|
||||
document.execCommand("insertHTML", false, text);
|
||||
if("" != text) {
|
||||
document.execCommand("insertHTML", false, text);
|
||||
} else {
|
||||
window.onPasteListener.onPaste();
|
||||
}
|
||||
});
|
||||
|
||||
requestContentFocus();
|
||||
|
||||
@ -11,5 +11,6 @@
|
||||
<script type="text/javascript" src="zepto.min.js"></script>
|
||||
<script type="text/javascript" src="rich_editor.js"></script>
|
||||
<script type="text/javascript" src="content.js"></script>
|
||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-lazyload/10.15.0/lazyload.min.js"></script>-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
40
app/src/main/assets/emojikf
Normal file
40
app/src/main/assets/emojikf
Normal file
@ -0,0 +1,40 @@
|
||||
emoji_kf_1.png,:smile:
|
||||
emoji_kf_2.png,:smiley:
|
||||
emoji_kf_3.png,:laughing:
|
||||
emoji_kf_4.png,:blush:
|
||||
emoji_kf_5.png,:heart_eyes:
|
||||
emoji_kf_6.png,:smirk:
|
||||
emoji_kf_7.png,:flushed:
|
||||
emoji_kf_8.png,:kissing_heart:
|
||||
emoji_kf_9.png,:grin:
|
||||
emoji_kf_10.png,:wink:
|
||||
emoji_kf_11.png,:stuck_out_tongue_winking_eye:
|
||||
emoji_kf_12.png,:stuck_out_tongue_closed eyes:
|
||||
emoji_kf_13.png,:worried:
|
||||
emoji_kf_14.png,:sleeping:
|
||||
emoji_kf_15.png,:expressionless:
|
||||
emoji_kf_16.png,:sweat_smile:
|
||||
emoji_kf_17.png,:joy:
|
||||
emoji_kf_18.png,:cold_sweat:
|
||||
emoji_kf_19.png,:sob:
|
||||
emoji_kf_20.png,:angry:
|
||||
emoji_kf_21.png,:mask:
|
||||
emoji_kf_22.png,:scream:
|
||||
emoji_kf_23.png,:sunglasses:
|
||||
emoji_kf_24.png,:heart:
|
||||
emoji_kf_25.png,:broken_heart:
|
||||
emoji_kf_26.png,:star:
|
||||
emoji_kf_27.png,:anger:
|
||||
emoji_kf_28.png,:exclamation:
|
||||
emoji_kf_29.png,:question:
|
||||
emoji_kf_30.png,:zzz:
|
||||
emoji_kf_31.png,:thumbsup:
|
||||
emoji_kf_32.png,:thumbsdown:
|
||||
emoji_kf_33.png,:ok_hand:
|
||||
emoji_kf_34.png,:punch:
|
||||
emoji_kf_35.png,:yeah:
|
||||
emoji_kf_36.png,:clap:
|
||||
emoji_kf_37.png,:muscle:
|
||||
emoji_kf_38.png,:pray:
|
||||
emoji_kf_39.png,:skull:
|
||||
emoji_kf_40.png,:trollface:
|
||||
BIN
app/src/main/assets/iattest.wav
Normal file
BIN
app/src/main/assets/iattest.wav
Normal file
Binary file not shown.
5
app/src/main/assets/microlog.properties
Normal file
5
app/src/main/assets/microlog.properties
Normal file
@ -0,0 +1,5 @@
|
||||
# This is a simple Microlog configuration file
|
||||
microlog.level=DEBUG
|
||||
microlog.appender=LogCatAppender;FileAppender
|
||||
microlog.formatter=PatternFormatter
|
||||
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
|
||||
@ -193,38 +193,45 @@ RE.setBlockquote = function() {
|
||||
}
|
||||
|
||||
RE.insertImage = function(url) {
|
||||
var html = "<div><img src =\"" + url + "\" style=\" max-width: 100%; display:block; margin:8px auto; height: auto;\"></div><br>"
|
||||
var html = "<div><img src =\"" + url + "\" style=\" max-width: 100%; display:block; margin:15px auto; height: auto;\"></div><br>"
|
||||
RE.insertHTML(html);
|
||||
}
|
||||
|
||||
RE.replaceTbImage = function() {
|
||||
//RE.lazyLoad = function() {
|
||||
// var myLazyLoad = new LazyLoad({
|
||||
// elements_selector: ".lazy"
|
||||
// })
|
||||
//}
|
||||
|
||||
// 替换成缩略图
|
||||
RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
if(img.src.indexOf("/tb/") > 0) continue;
|
||||
var imgArr = img.src.split("/");
|
||||
var tbImg = ""
|
||||
for (var j = 0; j < imgArr.length; j++) {
|
||||
if (j == imgArr.length - 1) {
|
||||
tbImg += "tb/" + imgArr[j];
|
||||
} else {
|
||||
tbImg += imgArr[j] + "/";
|
||||
}
|
||||
if(img.src.indexOf("?") > 0) continue;
|
||||
|
||||
var tbImg
|
||||
if(img.src.indexOf(".gif") > 0) {
|
||||
tbImg = img.src + gifRuleFlag
|
||||
} else {
|
||||
tbImg = img.src + imgRuleFlag
|
||||
}
|
||||
img.style.cssText = "max-width: 30%; display:block; margin:8px auto; height: auto;"
|
||||
|
||||
img.style.cssText = "max-width: 60%; display:block; margin:15px auto; height: auto;"
|
||||
img.src = tbImg;
|
||||
|
||||
if (i == 0) {
|
||||
var bigImg = document.createElement('img');
|
||||
bigImg.src = "file:///android_asset/web_load_dfimg_icon.png";
|
||||
bigImg.style.cssText = "max-width: 20%; margin:8px 0 0 0; height: auto;"
|
||||
bigImg.style.cssText = "max-width: 20%; margin:15px 0 0 0; height: auto;"
|
||||
img.parentNode.insertBefore(bigImg, img.parentNode.childNodes[0]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RE.replaceAllDfImage = function() {
|
||||
// 替换成默认图
|
||||
RE.replaceAllDfImage = function(imgRuleFlag, gifRuleFlag) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
@ -232,34 +239,54 @@ RE.replaceAllDfImage = function() {
|
||||
img.parentNode.removeChild(img.parentNode.childNodes[0]);
|
||||
i--;
|
||||
} else {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.replace("/tb/", "/");
|
||||
if(img.src.indexOf(".gif") > 0) {
|
||||
if(gifRuleFlag.indexOf(",default") > 0) {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.split("?")[0] + gifRuleFlag
|
||||
}
|
||||
} else {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.split("?")[0] + imgRuleFlag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 去除显示大图
|
||||
RE.hideShowBigPic = function() {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
var j = 0;
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
if(img.src.indexOf("/tb/") > 0) {
|
||||
if(img.src.indexOf(",thumbnail") > 0 && img.src.indexOf(".gif") == -1) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
// 去除显示大图
|
||||
if (j == 0) {
|
||||
RE.replaceAllDfImage();
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
if(img.src.indexOf("web_load_dfimg_icon") > 0) {
|
||||
img.parentNode.removeChild(img.parentNode.childNodes[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RE.replaceDfImageByUrl = function(imgUrl) {
|
||||
RE.replaceDfImageByUrl = function(imgUrl, imgRuleFlag, gifRuleFlag) {
|
||||
var imgs = document.getElementsByTagName("img");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
var img = imgs[i];
|
||||
if (img.src == imgUrl) {
|
||||
if (img.src.indexOf(imgUrl) != -1) {
|
||||
img.style.cssText = "max-width: 100%; display:block; margin:8px auto; height: auto;"
|
||||
img.src = img.src.replace("/tb/", "/");
|
||||
if(img.src.indexOf(".gif") > 0) {
|
||||
img.src = img.src.split("?")[0] + gifRuleFlag
|
||||
} else {
|
||||
img.src = img.src.split("?")[0] + imgRuleFlag
|
||||
}
|
||||
}
|
||||
}
|
||||
RE.hideShowBigPic();
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
package com.gh.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.arch.lifecycle.Lifecycle;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.Window;
|
||||
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
@ -17,6 +19,7 @@ import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.tencent.tauth.Tencent;
|
||||
@ -28,6 +31,8 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
@ -73,9 +78,25 @@ public abstract class BaseActivity extends BaseToolBarActivity implements EasyPe
|
||||
}
|
||||
}
|
||||
|
||||
// 小米沉浸式黑色字体
|
||||
public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
|
||||
Class<? extends Window> clazz = activity.getWindow().getClass();
|
||||
try {
|
||||
int darkModeFlag = 0;
|
||||
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
|
||||
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
|
||||
darkModeFlag = field.getInt(layoutParams);
|
||||
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
|
||||
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setStatusBarDarkMode(true, this);
|
||||
EventBus.getDefault().register(this);
|
||||
ButterKnife.bind(this);
|
||||
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
|
||||
@ -149,13 +170,11 @@ public abstract class BaseActivity extends BaseToolBarActivity implements EasyPe
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
} else if ("notfound".equals(showDialog.getType())) {
|
||||
DialogUtils.showAlertDialog(this, "下载失败", "下载链接已失效,建议提交反馈"
|
||||
, "立即反馈", "取消"
|
||||
, () -> {
|
||||
SuggestionActivity.startSuggestionActivity(this, 4,
|
||||
SuggestionActivity.startSuggestionActivity(this, SuggestType.gameQuestion,
|
||||
null, showDialog.getPath() + ",问题反馈:下载链接失效");
|
||||
}, null);
|
||||
}
|
||||
|
||||
@ -7,8 +7,11 @@ import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.normal.ToolbarController;
|
||||
import com.lightgame.BaseAppCompatActivity;
|
||||
@ -80,6 +83,16 @@ public abstract class BaseToolBarActivity extends BaseAppCompatActivity implemen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 限制标题实际宽度 防止标题挡住toolbar menu按钮
|
||||
if (menu.size() > 2 && mTitleTv != null) {
|
||||
ViewGroup.LayoutParams layoutParams = mTitleTv.getLayoutParams();
|
||||
if (layoutParams instanceof RelativeLayout.LayoutParams) {
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) layoutParams;
|
||||
params.setMargins(DisplayUtils.dip2px(90), 0, DisplayUtils.dip2px(90), 0);
|
||||
mTitleTv.setLayoutParams(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
19
app/src/main/java/com/gh/base/CurrentActivityHolder.kt
Normal file
19
app/src/main/java/com/gh/base/CurrentActivityHolder.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Activity
|
||||
|
||||
object CurrentActivityHolder {
|
||||
|
||||
@JvmStatic
|
||||
val activitySet = HashSet<Activity>()
|
||||
|
||||
@JvmStatic
|
||||
fun getCurrentActivity(): Activity? {
|
||||
return if (activitySet.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
activitySet.iterator().next()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,8 @@ import android.app.Activity;
|
||||
import android.app.Application.ActivityLifecycleCallbacks;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.gh.common.im.ImManager;
|
||||
import com.gh.common.notifier.Notifier;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.lightgame.utils.AppManager;
|
||||
@ -34,6 +36,8 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
|
||||
public void onActivityResumed(Activity activity) {
|
||||
|
||||
DataUtils.onResume(activity);
|
||||
CurrentActivityHolder.getActivitySet().add(activity);
|
||||
ImManager.updateFloatingWindow();
|
||||
//FIXME 这里应该只是部分Activity需要
|
||||
try {
|
||||
// 初始化gameMap
|
||||
@ -46,11 +50,12 @@ public class GHActivityLifecycleCallbacksImpl implements ActivityLifecycleCallba
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
DataUtils.onPause(activity);
|
||||
CurrentActivityHolder.getActivitySet().remove(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
|
||||
Notifier.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -6,8 +6,8 @@ import android.os.Bundle;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.gamecenter.GameDetailActivity;
|
||||
import com.gh.gamecenter.NewsDetailActivity;
|
||||
import com.gh.gamecenter.SubjectActivity;
|
||||
import com.gh.gamecenter.WebActivity;
|
||||
import com.gh.gamecenter.subject.refactor.SubjectActivity;
|
||||
import com.umeng.message.UmengNotificationClickHandler;
|
||||
import com.umeng.message.entity.UMessage;
|
||||
|
||||
@ -38,7 +38,7 @@ public class GHUmengNotificationClickHandler extends UmengNotificationClickHandl
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, target);
|
||||
break;
|
||||
case EntranceUtils.HOST_COLUMN:
|
||||
bundle.putString(EntranceUtils.KEY_TO, SubjectActivity.class.getSimpleName());
|
||||
bundle.putString(EntranceUtils.KEY_TO, SubjectActivity.class.getName());
|
||||
bundle.putString(EntranceUtils.KEY_ID, target);
|
||||
break;
|
||||
case EntranceUtils.HOST_WEB:
|
||||
|
||||
232
app/src/main/java/com/gh/base/GHUmengNotificationService.kt
Normal file
232
app/src/main/java/com/gh/base/GHUmengNotificationService.kt
Normal file
@ -0,0 +1,232 @@
|
||||
package com.gh.base
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import com.gh.common.notifier.Notifier
|
||||
import com.gh.common.util.DataUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.StringUtils
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.PushEntity
|
||||
import com.gh.gamecenter.entity.PushMessageEntity
|
||||
import com.gh.gamecenter.entity.PushMessageUnreadEntity
|
||||
import com.gh.gamecenter.entity.PushNotificationEntity
|
||||
import com.gh.gamecenter.message.MessageUnreadRepository
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
|
||||
import com.gh.gamecenter.receiver.UmengMessageReceiver
|
||||
import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_CLICK
|
||||
import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_REMOVE
|
||||
import com.google.gson.Gson
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.umeng.message.UmengMessageService
|
||||
import org.android.agoo.common.AgooConstants
|
||||
import java.util.*
|
||||
|
||||
class GHUmengNotificationService : UmengMessageService() {
|
||||
|
||||
companion object {
|
||||
const val ACTION_UMENG = "com.gh.gamecenter.UMENG"
|
||||
|
||||
const val MESSAGE_FROM_SYSTEM = "message_from_system"
|
||||
|
||||
const val HALO_MESSAGE_DIALOG = "HALO_MESSAGE_DIALOG"
|
||||
|
||||
const val HALO_MESSAGE_CENTER = "HALO_MESSAGE_CENTER"
|
||||
|
||||
const val ANSWER = "answer"
|
||||
|
||||
const val FOLLOW_QUESTION = "follow_question"
|
||||
|
||||
const val NOTIFICATION_ID = 2015
|
||||
|
||||
const val DISPLAY_TYPE_NOTIFICATION = "notification"
|
||||
|
||||
const val DISPLAY_TYPE_CUSTOM = "custom"
|
||||
}
|
||||
|
||||
val notificationTags = arrayOf("GH_UMENG_TAG_1", "GH_UMENG_TAG_2", "GH_UMENG_TAG_3")
|
||||
val gson = Gson()
|
||||
|
||||
override fun onMessage(context: Context, intent: Intent) {
|
||||
val message = intent.getStringExtra(AgooConstants.MESSAGE_BODY)
|
||||
val isMessageFromSystem = intent.getBooleanExtra(MESSAGE_FROM_SYSTEM, false)
|
||||
|
||||
try {
|
||||
val pushData = gson.fromJson(message, PushEntity::class.java)
|
||||
pushData?.let { handlePushData(context, it, message, isMessageFromSystem) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePushData(context: Context, pushData: PushEntity, message: String, isMessageFromSystem: Boolean) {
|
||||
val notificationManager = context.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (pushData.displayType == DISPLAY_TYPE_NOTIFICATION) {
|
||||
// 其它类型的透传信息
|
||||
// 显示到通知栏
|
||||
val msg = gson.fromJson(message, PushNotificationEntity::class.java)
|
||||
val data = msg?.extra?.data
|
||||
|
||||
// 系统推送,直接处理跳转
|
||||
if (isMessageFromSystem) {
|
||||
val intent = Intent()
|
||||
intent.setClass(context, UmengMessageReceiver::class.java)
|
||||
intent.putExtra(EntranceUtils.KEY_DATA, data?.link)
|
||||
intent.putExtra(EntranceUtils.KEY_TYPE, UmengMessageReceiver.DIRECT_ONLY)
|
||||
intent.putExtra(EntranceUtils.KEY_MESSAGE, message)
|
||||
context.sendBroadcast(intent)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断是否过滤该消息
|
||||
if (validatePush(data?.condition)) {
|
||||
val clickIntent = Intent()
|
||||
val removeIntent = Intent()
|
||||
|
||||
clickIntent.setClass(context, UmengMessageReceiver::class.java)
|
||||
clickIntent.putExtra(EntranceUtils.KEY_DATA, data?.link)
|
||||
clickIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
|
||||
clickIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_CLICK)
|
||||
|
||||
removeIntent.setClass(context, UmengMessageReceiver::class.java)
|
||||
removeIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_REMOVE)
|
||||
removeIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
|
||||
|
||||
val clickPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(),
|
||||
clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val deletePendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt() + 1,
|
||||
removeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel("Halo_Push", "Halo_Push", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
val notification = NotificationCompat.Builder(context, "Halo_Push")
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setTicker(pushData.body?.ticker)
|
||||
.setContentTitle(pushData.body?.title)
|
||||
.setContentText(pushData.body?.text)
|
||||
.setContentIntent(clickPendingIntent)
|
||||
.setDeleteIntent(deletePendingIntent)
|
||||
.build()
|
||||
notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
|
||||
|
||||
notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
|
||||
}
|
||||
} else {
|
||||
if (HALO_MESSAGE_DIALOG == pushData.body?.custom) {
|
||||
// 回答了问题或者关注了问题的消息
|
||||
val msg = gson.fromJson(message, PushMessageEntity::class.java)
|
||||
val data = msg?.extra?.data
|
||||
|
||||
val type = if (ANSWER == data?.type) {
|
||||
"回答了你的问题"
|
||||
} else {
|
||||
"回答了你关注的问题"
|
||||
}
|
||||
|
||||
val userName = StringUtils.shrinkStringWithDot(data?.userEntity?.name, 8)
|
||||
val displayText = userName + type
|
||||
|
||||
if (Notifier.isActivityValid(CurrentActivityHolder.getCurrentActivity()) &&
|
||||
Notifier.shouldShowNotifier(data?.answer?.id + displayText)) {
|
||||
Notifier.create(CurrentActivityHolder.getCurrentActivity())
|
||||
.setText(displayText)
|
||||
.setDuration(5000)
|
||||
.setIcon(data?.userEntity?.icon)
|
||||
.setOnClickListener(View.OnClickListener { _ ->
|
||||
val bundle = Bundle()
|
||||
bundle.putString(EntranceUtils.KEY_ANSWER_ID, data?.answer?.id)
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG)
|
||||
bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
|
||||
DataUtils.onMtaEvent(context, "消息弹窗",
|
||||
type, "")
|
||||
|
||||
Notifier.hide()
|
||||
})
|
||||
.show(false)
|
||||
Notifier.tagNotifierAsShowed(data?.answer?.id + displayText)
|
||||
}
|
||||
} else if (HALO_MESSAGE_CENTER == pushData.body?.custom) {
|
||||
// 消息中心逻辑
|
||||
val msg = gson.fromJson(message, PushMessageUnreadEntity::class.java)
|
||||
val data = msg?.extra?.data
|
||||
data?.let { MessageUnreadRepository.loadMessageUnreadData() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validatePush(condition: PushNotificationEntity.Data.Condition?): Boolean {
|
||||
if (condition == null) return true
|
||||
|
||||
// 校验渠道是否匹配
|
||||
condition.ghzs?.channel?.let {
|
||||
if (it.isNotEmpty() && it != HaloApp.getInstance().channel) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 校验光环版本版本是否匹配
|
||||
condition.ghzs?.version?.let {
|
||||
if (it.isNotEmpty() && !BuildConfig.VERSION_NAME.contains(it)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 校验已安装的应用里是否存在条件的包名
|
||||
if (condition.packageName.isNotEmpty()) {
|
||||
val installedPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
|
||||
for (packageName in installedPackageList) {
|
||||
if (condition.packageName == packageName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 规则:最多三条消息,以旧换新
|
||||
*
|
||||
* @return NotificationTag
|
||||
*/
|
||||
private fun getNotificationTag(context: Context): String {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val edit = sp.edit()
|
||||
|
||||
val timeTagMap = HashMap<Long, String>()
|
||||
for (tag in notificationTags) {
|
||||
val time = sp.getLong(tag, 0)
|
||||
if (time == 0L) {
|
||||
edit.putLong(tag, System.currentTimeMillis()).apply()
|
||||
return tag
|
||||
} else {
|
||||
timeTagMap[time] = tag
|
||||
}
|
||||
}
|
||||
|
||||
val minTime = Collections.min(timeTagMap.keys)
|
||||
val tag = timeTagMap[minTime]
|
||||
edit.putLong(tag, System.currentTimeMillis()).apply()
|
||||
return if (TextUtils.isEmpty(tag)) notificationTags[0] else tag!!
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -29,9 +30,9 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import rx.Observable;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
|
||||
@ -111,6 +112,9 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
super.onCreate(savedInstanceState);
|
||||
final Intent intent = getActivity().getIntent();
|
||||
mEntrance = intent.getStringExtra(KEY_ENTRANCE);
|
||||
if (TextUtils.isEmpty(mEntrance) && getArguments() != null) {
|
||||
mEntrance = getArguments().getString(KEY_ENTRANCE);
|
||||
}
|
||||
|
||||
isEverPause = false;
|
||||
EventBus.getDefault().register(this);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.base.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
@ -57,6 +58,17 @@ public abstract class BaseFragment_TabLayout extends NormalFragment implements V
|
||||
return R.layout.fragment_taglyout_viewpager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
List<Fragment> fragments = getChildFragmentManager().getFragments();
|
||||
if (fragments != null) {
|
||||
for (Fragment fragment : fragments) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
@ -21,6 +21,8 @@ public class WaitingDialogFragment extends BaseDialogFragment {
|
||||
|
||||
private OnDialogBackListener mBackListener;
|
||||
|
||||
private TextView message;
|
||||
|
||||
public static WaitingDialogFragment newInstance(String message) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_MSG, message);
|
||||
@ -43,7 +45,7 @@ public class WaitingDialogFragment extends BaseDialogFragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
final View view = inflater.inflate(R.layout.set_wait_dialog, null);
|
||||
final TextView message = (TextView) view.findViewById(R.id.set_wait_message);
|
||||
message = (TextView) view.findViewById(R.id.set_wait_message);
|
||||
message.setText(getArguments().getString(KEY_MSG));
|
||||
return view;
|
||||
}
|
||||
@ -62,6 +64,10 @@ public class WaitingDialogFragment extends BaseDialogFragment {
|
||||
this.mBackListener = backListener;
|
||||
}
|
||||
|
||||
public void uploadWaitingHint(String hint) {
|
||||
if (message != null) message.setText(hint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBack() {
|
||||
if (mBackListener != null) {
|
||||
|
||||
21
app/src/main/java/com/gh/common/AppExecutor.kt
Normal file
21
app/src/main/java/com/gh/common/AppExecutor.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object AppExecutor {
|
||||
@JvmStatic
|
||||
var ioExecutor = Executors.newSingleThreadExecutor()
|
||||
@JvmStatic
|
||||
var uiExecutor = MainThreadExecutor()
|
||||
|
||||
class MainThreadExecutor : Executor {
|
||||
private val mainThreadHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
override fun execute(command: Runnable) {
|
||||
mainThreadHandler.post(command)
|
||||
}
|
||||
}
|
||||
}
|
||||
39
app/src/main/java/com/gh/common/LocalBroadcastReceiver.kt
Normal file
39
app/src/main/java/com/gh/common/LocalBroadcastReceiver.kt
Normal file
@ -0,0 +1,39 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.gh.common.im.ImManager
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.m7.imkfsdk.chat.ChatActivity
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
/**
|
||||
* 可使用 [LocalBroadcastManager] 来进行简单的模块间消息通知
|
||||
*/
|
||||
|
||||
class LocalBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
intent?.let {
|
||||
when (intent.action) {
|
||||
ChatActivity.ACTION_DISMISS_FLOATING_WINDOW -> {
|
||||
ImManager.dismissFloatingWindow()
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api.postImEnding(UserManager.getInstance().userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
ChatActivity.ACTION_HIDE_UNREAD_DOT -> {
|
||||
ImManager.updateShouldShowFloatingWindowDot(false)
|
||||
}
|
||||
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
137
app/src/main/java/com/gh/common/PushManager.kt
Normal file
137
app/src/main/java/com/gh/common/PushManager.kt
Normal file
@ -0,0 +1,137 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.preference.PreferenceManager
|
||||
import com.gh.base.GHUmengNotificationService
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.util.edit
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.entity.AliasEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.google.gson.Gson
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import com.umeng.commonsdk.UMConfigure
|
||||
import com.umeng.message.IUmengRegisterCallback
|
||||
import com.umeng.message.PushAgent
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.android.agoo.huawei.HuaWeiRegister
|
||||
import org.android.agoo.mezu.MeizuRegister
|
||||
import org.android.agoo.xiaomi.MiPushRegistar
|
||||
import org.json.JSONObject
|
||||
|
||||
object PushManager {
|
||||
|
||||
var gson = Gson()
|
||||
var deviceToken: String? = ""
|
||||
var previousAlias: AliasEntity? = null
|
||||
var application = HaloApp.getInstance().application
|
||||
|
||||
const val SP_PUSH_ALIAS = "push_alias"
|
||||
|
||||
@JvmStatic
|
||||
fun init(channel: String) {
|
||||
//初始化友盟推送
|
||||
UMConfigure.init(application,
|
||||
Config.UMENG_APPKEY, channel,
|
||||
UMConfigure.DEVICE_TYPE_PHONE,
|
||||
Config.UMENG_MESSAGE_SECRET)
|
||||
|
||||
// 注册小米、华为和魅族通道
|
||||
MiPushRegistar.register(application, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
|
||||
HuaWeiRegister.register(application)
|
||||
MeizuRegister.register(application, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
|
||||
|
||||
//友盟推送
|
||||
val pushAgent = PushAgent.getInstance(application)
|
||||
pushAgent.onAppStart() // 开启App统计
|
||||
|
||||
//注册推送服务,每次调用register方法都会回调该接口
|
||||
registerDevice()
|
||||
|
||||
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(application).getString(SP_PUSH_ALIAS, "")
|
||||
previousAlias = gson.fromJson(aliasInSp, AliasEntity::class.java)
|
||||
|
||||
if (previousAlias == null) {
|
||||
getAndSetAlias()
|
||||
}
|
||||
|
||||
// 完全自定义处理(透传)
|
||||
pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
|
||||
}
|
||||
|
||||
private fun registerDevice() {
|
||||
PushAgent.getInstance(application).register(object : IUmengRegisterCallback {
|
||||
override fun onSuccess(dToken: String) {
|
||||
//注册成功会返回device token
|
||||
deviceToken = dToken
|
||||
getAndSetAlias()
|
||||
Utils.log("deviceToken::$dToken")
|
||||
}
|
||||
|
||||
override fun onFailure(s: String, s1: String) {
|
||||
Utils.log("deviceToken::" + "注册失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAndSetAlias() {
|
||||
if (deviceToken.isNullOrEmpty()) {
|
||||
registerDevice()
|
||||
return
|
||||
}
|
||||
|
||||
val meta = MetaUtil.getMeta()
|
||||
|
||||
val jsonObject = JSONObject()
|
||||
jsonObject.put("device_token", deviceToken)
|
||||
jsonObject.put("imei", meta.imei)
|
||||
jsonObject.put("android_id", meta.android_id)
|
||||
jsonObject.put("model", meta.model)
|
||||
jsonObject.put("manufacturer", meta.manufacturer)
|
||||
jsonObject.put("os", meta.os)
|
||||
jsonObject.put("os_version", meta.android_version)
|
||||
jsonObject.put("mac", meta.mac)
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
|
||||
|
||||
RetrofitManager.getInstance(application).api.getAlias(body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(
|
||||
{ setAlias(it) },
|
||||
{ it.printStackTrace() }
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setAlias(alias: AliasEntity) {
|
||||
val pushAgent = PushAgent.getInstance(application)
|
||||
|
||||
previousAlias = alias
|
||||
PreferenceManager.getDefaultSharedPreferences(application).edit {
|
||||
putString(SP_PUSH_ALIAS, gson.toJson(previousAlias))
|
||||
}
|
||||
|
||||
pushAgent.setAlias(alias.alias, alias.aliasType) { b, s ->
|
||||
Utils.log("注册别名 $b + $s")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteAlias() {
|
||||
val pushAgent = PushAgent.getInstance(application)
|
||||
|
||||
previousAlias?.let {
|
||||
pushAgent.deleteAlias(it.alias, it.aliasType) { b, s ->
|
||||
Utils.log("删除别名 $b + $s")
|
||||
}
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(application).edit {
|
||||
putString(SP_PUSH_ALIAS, "")
|
||||
}
|
||||
previousAlias = null
|
||||
}
|
||||
}
|
||||
61
app/src/main/java/com/gh/common/TimeElapsedHelper.kt
Normal file
61
app/src/main/java/com/gh/common/TimeElapsedHelper.kt
Normal file
@ -0,0 +1,61 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* 统计用户在当前 Fragment 的停留时间,在 onViewDestroy 或 onDestroy 里获取 elapsedTime 即可,单位为秒
|
||||
*/
|
||||
class TimeElapsedHelper(var fragment: Fragment) {
|
||||
|
||||
private var isWorking = false
|
||||
|
||||
var elapsedTime: Int = 0
|
||||
|
||||
init {
|
||||
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentResumed(fm: FragmentManager?, f: Fragment?) {
|
||||
if (f === fragment) {
|
||||
resumeCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentPaused(fm: FragmentManager?, f: Fragment?) {
|
||||
if (f === fragment) {
|
||||
pauseCounting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentViewDestroyed(fm: FragmentManager?, f: Fragment?) {
|
||||
if (f === fragment) {
|
||||
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
private fun resumeCounting() {
|
||||
isWorking = true
|
||||
TimeElapsedThreadHolder.threadService.execute {
|
||||
while (isWorking) {
|
||||
try {
|
||||
elapsedTime++
|
||||
Thread.sleep(1000)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun pauseCounting() {
|
||||
isWorking = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object TimeElapsedThreadHolder {
|
||||
val threadService = Executors.newSingleThreadExecutor()
|
||||
}
|
||||
@ -6,6 +6,7 @@ import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.entity.NewsEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
@ -46,6 +47,8 @@ public class Config {
|
||||
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // TODO ghzs/ghzs666 统一
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
private static String SETTINGS_KEY = "settingsKey";
|
||||
|
||||
private static SettingsEntity mSettingsEntity;
|
||||
|
||||
public static boolean isShow() {
|
||||
@ -54,7 +57,7 @@ public class Config {
|
||||
|
||||
if (!isExistDownloadFilter()) return false;
|
||||
|
||||
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if ("all".equals(entity.getGame())) {
|
||||
if (entity.isPluginfy() && "normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
@ -76,10 +79,13 @@ public class Config {
|
||||
|
||||
public static boolean isShowDownload(String gameId) {
|
||||
|
||||
if (PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication())
|
||||
.getBoolean("isFixDownload", false)) return true;
|
||||
|
||||
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
|
||||
return false;
|
||||
|
||||
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if (gameId.equals(entity.getGame())) {
|
||||
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
@ -87,8 +93,7 @@ public class Config {
|
||||
return false;
|
||||
}
|
||||
} else if ("all".equals(entity.getGame())) {
|
||||
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())
|
||||
|| PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).getBoolean("isFixDownload", false)) {
|
||||
if ("normal".equals(entity.getPolicy()) && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -102,7 +107,7 @@ public class Config {
|
||||
if (TextUtils.isEmpty(gameId) || !isExistDownloadFilter())
|
||||
return false;
|
||||
|
||||
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if (gameId.equals(entity.getGame())) {
|
||||
if (entity.isPluginfy() && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
@ -123,7 +128,7 @@ public class Config {
|
||||
if (!isExistDownloadFilter())
|
||||
return false;
|
||||
|
||||
for (SettingsEntity.Download entity : mSettingsEntity.getDownload()) {
|
||||
for (SettingsEntity.Download entity : getSettings().getDownload()) {
|
||||
if ("all".equals(entity.getGame())) {
|
||||
if (entity.isPluginfy() && filterTime(entity.getTime())) {
|
||||
return true;
|
||||
@ -147,15 +152,29 @@ public class Config {
|
||||
}
|
||||
|
||||
public static void setSettings(SettingsEntity settingsEntity) {
|
||||
SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit();
|
||||
edit.putString(SETTINGS_KEY, GsonUtils.getInstance().toJson(settingsEntity)).apply();
|
||||
|
||||
mSettingsEntity = settingsEntity;
|
||||
}
|
||||
|
||||
public static SettingsEntity getSettings() {
|
||||
if (mSettingsEntity == null) {
|
||||
try {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication());
|
||||
String json = sp.getString(SETTINGS_KEY, null);
|
||||
if (!TextUtils.isEmpty(json)) {
|
||||
mSettingsEntity = GsonUtils.getInstance().fromJsonBean(json, SettingsEntity.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return mSettingsEntity;
|
||||
}
|
||||
|
||||
private static boolean isExistDownloadFilter() {
|
||||
if (mSettingsEntity == null || mSettingsEntity.getDownload() == null || mSettingsEntity.getDownload().size() == 0) {
|
||||
if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
||||
@ -15,6 +15,10 @@ public class Constants {
|
||||
public static final String USER_TOKEN_KEY = "userTokenKey";
|
||||
public static final String USER_INFO_KEY = "userInfoKey";
|
||||
|
||||
// 最近显示的弹窗信息
|
||||
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
|
||||
public static final String SP_LAST_OPENING_TIME = "last_opening_dialog_time";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
public static final String REGEX_ACCOUNT = "^[a-zA-Z_]\\w{5,17}$";
|
||||
|
||||
@ -22,9 +22,11 @@ import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.GameUtils;
|
||||
import com.gh.common.util.GameViewUtils;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.KaiFuUtils;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.NewsUtils;
|
||||
import com.gh.common.util.NumberUtils;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.StringUtils;
|
||||
import com.gh.common.view.DownloadDialog;
|
||||
@ -46,6 +48,7 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -56,9 +59,15 @@ import java.util.Locale;
|
||||
|
||||
public class BindingAdapters {
|
||||
|
||||
@BindingAdapter("imageIcon")
|
||||
public static void loadIcon(SimpleDraweeView view, String imageUrl) {
|
||||
ImageUtils.displayIcon(view, imageUrl);
|
||||
}
|
||||
|
||||
|
||||
@BindingAdapter("imageUrl")
|
||||
public static void loadImage(SimpleDraweeView view, String imageUrl) {
|
||||
view.setImageURI(imageUrl);
|
||||
ImageUtils.display(view, imageUrl);
|
||||
}
|
||||
|
||||
@BindingAdapter({"addDetailKaiFuView", "addDetailKaiFuViewListener", "isReadyPatch"})
|
||||
@ -96,6 +105,12 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果超过10000,则转换为1.0W
|
||||
@BindingAdapter("transSimpleCount")
|
||||
public static void transSimpleCount(TextView view, int count) {
|
||||
view.setText(NumberUtils.transSimpleCount(count));
|
||||
}
|
||||
|
||||
@BindingAdapter({"addKaiFuView", "clickListener"})
|
||||
public static void addKaiFuView(LinearLayout view, List<KaiFuCalendarEntity> list, OnViewClickListener listener) {
|
||||
if (list == null) return;
|
||||
@ -420,9 +435,9 @@ public class BindingAdapters {
|
||||
ApkEntity apkEntity = gameEntity.getApk().get(0);
|
||||
String msg = FileUtils.isCanDownload(progressBar.getContext(), apkEntity.getSize());
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), "(我的光环:我的游戏)", "下载开始");
|
||||
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), "(我的光环:我的游戏)", "下载开始", method);
|
||||
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
|
||||
|
||||
DownloadManager.createDownload(progressBar.getContext(),
|
||||
apkEntity,
|
||||
|
||||
@ -4,7 +4,7 @@ import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import rx.functions.Action1
|
||||
import io.reactivex.functions.Consumer
|
||||
|
||||
/**
|
||||
* Exposure Event Listener for RecyclerView
|
||||
@ -22,12 +22,12 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
|
||||
fragment.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentResumed(fm: FragmentManager?, f: Fragment?) {
|
||||
throttleBus = ExposureThrottleBus(Action1 { commitExposure(it) }, Action1(Throwable::printStackTrace))
|
||||
throttleBus = ExposureThrottleBus(Consumer { commitExposure(it) }, Consumer(Throwable::printStackTrace))
|
||||
}
|
||||
|
||||
override fun onFragmentPaused(fm: FragmentManager?, f: Fragment?) {
|
||||
visibleState?.let { commitExposure(it) }
|
||||
throttleBus?.unsubscribe()
|
||||
throttleBus?.clear()
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import com.gh.common.exposure.aliyun.LGLOG
|
||||
import com.gh.common.exposure.aliyun.LGLOGClient
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.google.gson.Gson
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
@ -23,13 +24,14 @@ object ExposureManager {
|
||||
private const val ACCESS_KEY_SECRET = "8dKtTPeE5WYA6ZCeuIBcIVp7eB0ir4"
|
||||
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
|
||||
private const val PROJECT = "ghzs"
|
||||
private const val LOG_STORE = "exposure"
|
||||
private const val STORE_SIZE = 100
|
||||
private const val STORE_FORCE_UPLOAD_PERIOD = 300 * 1000L
|
||||
|
||||
private var LOG_STORE = BuildConfig.EXPOSURE_REPO
|
||||
|
||||
private lateinit var client: LGLOGClient
|
||||
private lateinit var db: ExposureEventDao
|
||||
private val storeList = arrayListOf<ExposureEvent>()
|
||||
private val storeSet = hashSetOf<ExposureEvent>()
|
||||
private val storeOpThread = Executors.newSingleThreadExecutor()
|
||||
private val gson = Gson()
|
||||
|
||||
@ -43,13 +45,13 @@ object ExposureManager {
|
||||
client = LGLOGClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, PROJECT)
|
||||
db = ExposureDatabase.buildDatabase(application).logHubEventDao()
|
||||
|
||||
storeOpThread.execute({
|
||||
storeOpThread.execute {
|
||||
val eventList = db.getAll()
|
||||
storeList.addAll(eventList)
|
||||
})
|
||||
storeSet.addAll(eventList)
|
||||
}
|
||||
|
||||
fixedRateTimer(name = "ExposureManager-Store-Checker", initialDelay = 500, period = STORE_FORCE_UPLOAD_PERIOD) {
|
||||
checkAndUploadFromStore(true)
|
||||
checkAndUploadFromDatabase(true)
|
||||
}
|
||||
|
||||
MetaUtil.init(application)
|
||||
@ -77,70 +79,69 @@ object ExposureManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an Event to storeList, upload when storeList size exceeds STORE_SIZE
|
||||
* Store an Event to storeSet, upload when storeSet size exceeds STORE_SIZE
|
||||
*/
|
||||
private fun store(event: ExposureEvent) {
|
||||
storeOpThread.execute({
|
||||
storeOpThread.execute {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
storeList.add(event)
|
||||
storeSet.add(event)
|
||||
db.insert(event)
|
||||
exposureCache.add(event.id)
|
||||
}
|
||||
})
|
||||
checkAndUploadFromStore()
|
||||
checkAndUploadFromDatabase()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store Many Events to storeList, upload when storeList size exceeds STORE_SIZE
|
||||
* Store Many Events to storeSet, upload when storeSet size exceeds STORE_SIZE
|
||||
*/
|
||||
private fun store(eventList: List<ExposureEvent>) {
|
||||
storeOpThread.execute({
|
||||
storeOpThread.execute {
|
||||
for (event in eventList) {
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
storeList.add(event)
|
||||
storeSet.add(event)
|
||||
db.insert(event)
|
||||
exposureCache.add(event.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
checkAndUploadFromStore()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload an Event
|
||||
*/
|
||||
private fun upload(event: ExposureEvent) {
|
||||
storeOpThread.execute({
|
||||
storeOpThread.execute {
|
||||
client.PostLog(buildLogGroup(event), LOG_STORE)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload Many Events
|
||||
*/
|
||||
private fun upload(eventList: List<ExposureEvent>) {
|
||||
storeOpThread.execute({
|
||||
storeOpThread.execute {
|
||||
client.PostLog(buildLogGroup(eventList), LOG_STORE)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload Events From Store, and removed them
|
||||
*/
|
||||
private fun checkAndUploadFromStore(isForceUpload: Boolean = false) {
|
||||
if (storeList.size < STORE_SIZE && !isForceUpload || storeList.size == 0) return
|
||||
storeOpThread.execute({
|
||||
if (storeList.size < STORE_SIZE && !isForceUpload || storeList.size == 0) return@execute
|
||||
val uploaded = storeList.toList()
|
||||
private fun checkAndUploadFromDatabase(isForceUpload: Boolean = false) {
|
||||
storeOpThread.execute {
|
||||
if (storeSet.size < STORE_SIZE && !isForceUpload || storeSet.size == 0) return@execute
|
||||
val uploaded = storeSet.toList()
|
||||
try {
|
||||
client.PostLog(buildLogGroup(uploaded), LOG_STORE)
|
||||
} catch (exception: LogException) {
|
||||
// Return to insure no logs lost because of online commit failure
|
||||
return@execute
|
||||
}
|
||||
storeList.removeAll(uploaded)
|
||||
storeSet.removeAll(uploaded)
|
||||
db.deleteMany(uploaded)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildLog(event: ExposureEvent): LGLOG {
|
||||
|
||||
@ -1,38 +1,37 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import rx.Subscription
|
||||
import rx.functions.Action1
|
||||
import rx.schedulers.Schedulers
|
||||
import rx.subjects.PublishSubject
|
||||
import rx.subjects.Subject
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ExposureThrottleBus(var onSuccess: Action1<VisibleState>, var onError: Action1<Throwable>) {
|
||||
class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Consumer<Throwable>) {
|
||||
|
||||
companion object {
|
||||
private const val THRESHOLD_TIME = 300L
|
||||
}
|
||||
|
||||
private val mPublishSubject: Subject<VisibleState, VisibleState>
|
||||
private val mSubscription: Subscription
|
||||
private val mPublishSubject: PublishSubject<VisibleState> = PublishSubject.create()
|
||||
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
init {
|
||||
mPublishSubject = PublishSubject.create()
|
||||
|
||||
/**
|
||||
* Since onScroll() callback will be triggered multiple times for every swipe, we use
|
||||
* distinctUntilChanged() to prevent committing the same visibleState event and
|
||||
* throttleWithTimeout() to pass a visibleState event with a delay and drop current event if another event arrives before the timeout.
|
||||
*/
|
||||
mSubscription = mPublishSubject
|
||||
val disposable = mPublishSubject
|
||||
.distinctUntilChanged()
|
||||
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(onSuccess, onError)
|
||||
mCompositeDisposable.add(disposable)
|
||||
}
|
||||
|
||||
fun unsubscribe() {
|
||||
mSubscription.unsubscribe()
|
||||
fun clear() {
|
||||
mCompositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun postVisibleState(visibleState: VisibleState) {
|
||||
|
||||
@ -6,6 +6,9 @@ import java.util.*
|
||||
|
||||
object ExposureUtils {
|
||||
|
||||
val gson = Gson()
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadExposureEvent(entity: GameEntity, platform: String?, traceEvent: ExposureEvent?, downloadType: DownloadType): ExposureEvent {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.platform = platform
|
||||
@ -18,11 +21,12 @@ object ExposureUtils {
|
||||
return exposureEvent
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logADownloadCompleteExposureEvent(entity: GameEntity, platform: String?, trace: String?, downloadType: DownloadType) {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadCompleteType = downloadType.toString()
|
||||
val traceEvent = Gson().fromJson(trace, ExposureEvent::class.java)
|
||||
val traceEvent = gson.fromJson(trace, ExposureEvent::class.java)
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
source = traceEvent?.source ?: ArrayList(),
|
||||
eTrace = ExposureTraceUtils.appendTrace(traceEvent),
|
||||
|
||||
@ -19,5 +19,6 @@ data class Meta(
|
||||
val os: String? = "",
|
||||
val channel: String? = "",
|
||||
val appVersion: String? = "",
|
||||
val userId: String? = ""
|
||||
val userId: String? = "",
|
||||
val exposureVersion: String? = ""
|
||||
) : Parcelable
|
||||
@ -28,7 +28,7 @@ object MetaUtil {
|
||||
|
||||
fun refreshMeta() {
|
||||
m = Meta(getMac(), getIMEI(), getModel(), getManufacturer(), getAndroidId(), getAndroidSDK(),
|
||||
getAndroidVersion(), getNetwork(), getIP(), getOS(), getChannel(), BuildConfig.VERSION_NAME, UserManager.getInstance().userId)
|
||||
getAndroidVersion(), getNetwork(), getIP(), getOS(), getChannel(), BuildConfig.VERSION_NAME, UserManager.getInstance().userId, BuildConfig.EXPOSURE_VERSION)
|
||||
}
|
||||
|
||||
fun getMeta(): Meta {
|
||||
@ -51,7 +51,7 @@ object MetaUtil {
|
||||
*/
|
||||
fun getMac(): String? {
|
||||
|
||||
var mac: String
|
||||
var mac: String = ""
|
||||
|
||||
//Plan A
|
||||
try {
|
||||
@ -71,7 +71,12 @@ object MetaUtil {
|
||||
|
||||
// Plan C
|
||||
val wifiManager = application.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
mac = wifiManager.connectionInfo.macAddress
|
||||
try {
|
||||
mac = wifiManager.connectionInfo.macAddress
|
||||
} catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
}
|
||||
|
||||
return mac.trim()
|
||||
|
||||
}
|
||||
@ -87,7 +92,7 @@ object MetaUtil {
|
||||
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
return "!" + telephonyManager.imei
|
||||
return telephonyManager.imei
|
||||
}
|
||||
|
||||
return telephonyManager.getDeviceId()
|
||||
|
||||
@ -2,7 +2,7 @@ package com.gh.common.exposure.time
|
||||
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import rx.schedulers.Schedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
class Corrector {
|
||||
|
||||
67
app/src/main/java/com/gh/common/im/ImHintHelper.kt
Normal file
67
app/src/main/java/com/gh/common/im/ImHintHelper.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package com.gh.common.im
|
||||
|
||||
import android.app.Activity
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
object ImHintHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun show(activity: Activity?) {
|
||||
activity?.let {
|
||||
var hintView = retrieveHintViewFromActivity(it)
|
||||
if (hintView == null) {
|
||||
hintView = ImHintView(it)
|
||||
hintView.showDot(ImManager.shouldShowFloatingWindowDot)
|
||||
|
||||
val decorView = it.window.decorView as ViewGroup
|
||||
it.runOnUiThread {
|
||||
decorView.addView(hintView)
|
||||
}
|
||||
} else {
|
||||
hintView.showDot(ImManager.shouldShowFloatingWindowDot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun dismiss(activity: Activity?) {
|
||||
activity?.let {
|
||||
clearCurrent(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun retrieveHintViewFromActivity(activity: Activity?) : ImHintView? {
|
||||
(activity?.window?.decorView as? ViewGroup)?.let {
|
||||
for (i in 0..it.childCount) {
|
||||
val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
|
||||
if (childView != null && childView.windowToken != null) {
|
||||
return childView
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun clearCurrent(activity: Activity?) {
|
||||
(activity?.window?.decorView as? ViewGroup)?.let {
|
||||
for (i in 0..it.childCount) {
|
||||
val childView = if (it.getChildAt(i) is ImHintView) it.getChildAt(i) as ImHintView else null
|
||||
if (childView != null && childView.windowToken != null) {
|
||||
ViewCompat.animate(childView).alpha(0f).withEndAction(getRemoveViewRunnable(childView))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRemoveViewRunnable(childView: View?): Runnable {
|
||||
return Runnable {
|
||||
childView?.let {
|
||||
(childView.parent as? ViewGroup)?.removeView(childView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
84
app/src/main/java/com/gh/common/im/ImHintView.kt
Normal file
84
app/src/main/java/com/gh/common/im/ImHintView.kt
Normal file
@ -0,0 +1,84 @@
|
||||
package com.gh.common.im
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
import android.view.KeyCharacterMap
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
import android.widget.RelativeLayout
|
||||
import com.gh.gamecenter.R
|
||||
import kotlinx.android.synthetic.main.view_im_hint.view.*
|
||||
|
||||
class ImHintView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: RelativeLayout(context, attrs, defStyle) {
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.view_im_hint, this)
|
||||
|
||||
ViewCompat.setTranslationZ(this, Integer.MAX_VALUE.toFloat() - 1)
|
||||
|
||||
ivContainer.setOnClickListener {
|
||||
if (context is Activity) {
|
||||
ImManager.startChatActivity(context)
|
||||
ImManager.removeNotification()
|
||||
}
|
||||
}
|
||||
|
||||
val lp = ivContainer.layoutParams as RelativeLayout.LayoutParams
|
||||
|
||||
lp.setMargins(0, 0, dp2px(30f), dp2px(106f) + retrieveNavigationHeight())
|
||||
}
|
||||
|
||||
fun showDot(show: Boolean) {
|
||||
if (show) {
|
||||
unreadDot.visibility = View.VISIBLE
|
||||
} else {
|
||||
unreadDot.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun dp2px(dp: Float): Int {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.applicationContext.resources.displayMetrics).toInt()
|
||||
}
|
||||
|
||||
private fun hasSoftKeys(): Boolean {
|
||||
if (context !is Activity) return false
|
||||
|
||||
val hasSoftwareKeys: Boolean
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
val d = (context as Activity).windowManager.defaultDisplay
|
||||
|
||||
val realDisplayMetrics = DisplayMetrics()
|
||||
d.getRealMetrics(realDisplayMetrics)
|
||||
|
||||
val realHeight = realDisplayMetrics.heightPixels
|
||||
val realWidth = realDisplayMetrics.widthPixels
|
||||
|
||||
val displayMetrics = DisplayMetrics()
|
||||
d.getMetrics(displayMetrics)
|
||||
|
||||
val displayHeight = displayMetrics.heightPixels
|
||||
val displayWidth = displayMetrics.widthPixels
|
||||
|
||||
hasSoftwareKeys = realWidth - displayWidth > 0 || realHeight - displayHeight > 0
|
||||
} else {
|
||||
val hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey()
|
||||
val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
|
||||
hasSoftwareKeys = !hasMenuKey && !hasBackKey
|
||||
}
|
||||
return hasSoftwareKeys
|
||||
}
|
||||
|
||||
private fun retrieveNavigationHeight(): Int {
|
||||
val resources = context.resources
|
||||
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
|
||||
return if (resourceId > 0 && hasSoftKeys()) resources.getDimensionPixelSize(resourceId) else 0
|
||||
}
|
||||
}
|
||||
146
app/src/main/java/com/gh/common/im/ImManager.kt
Normal file
146
app/src/main/java/com/gh/common/im/ImManager.kt
Normal file
@ -0,0 +1,146 @@
|
||||
package com.gh.common.im
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.MessageActivity
|
||||
import com.gh.gamecenter.SuggestSelectActivity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.m7.imkfsdk.KfStartHelper
|
||||
import com.moor.imkf.ChatListener
|
||||
import com.moor.imkf.IMChat
|
||||
import com.moor.imkf.IMChatManager
|
||||
import com.moor.imkf.IMMessage
|
||||
|
||||
object ImManager {
|
||||
|
||||
const val IM_KEY = "893be270-9c75-11e8-a344-212975ba32b9"
|
||||
const val SP_FLOATING_WINDOW_KEY = "IM_FLOATING_WINDOW"
|
||||
const val SP_FLOATING_WINDOW_DOT_KEY = "IM_FLOATING_WINDOW_DOT"
|
||||
|
||||
var shouldShowFloatingWindow = false
|
||||
var shouldShowFloatingWindowDot = false
|
||||
|
||||
@JvmStatic
|
||||
fun attachIm() {
|
||||
try {
|
||||
if (UserManager.getInstance().userInfoEntity != null) {
|
||||
IMChatManager.getInstance().init(
|
||||
HaloApp.getInstance().application,
|
||||
ImReceiver.UNIQUE_BROADCAST_ACTION,
|
||||
IM_KEY,
|
||||
UserManager.getInstance().userInfoEntity.name + "(" + UserManager.getInstance().userId + ")",
|
||||
UserManager.getInstance().userId)
|
||||
|
||||
shouldShowFloatingWindow = SPUtils.getBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId)
|
||||
shouldShowFloatingWindowDot = SPUtils.getBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId)
|
||||
updateFloatingWindow()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun detachIm() {
|
||||
try {
|
||||
IMChatManager.getInstance().quitSDk()
|
||||
shouldShowFloatingWindow = false
|
||||
updateFloatingWindow()
|
||||
removeNotification()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startChatActivity(activity: Activity) {
|
||||
if (!UserManager.getInstance().userId.isNullOrEmpty()) {
|
||||
try {
|
||||
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, false)
|
||||
shouldShowFloatingWindowDot = false
|
||||
val chatHelper = KfStartHelper(activity, UserManager.getInstance().userInfoEntity.icon)
|
||||
chatHelper.initSdkChat(
|
||||
ImReceiver.UNIQUE_BROADCAST_ACTION,
|
||||
IM_KEY,
|
||||
UserManager.getInstance().userInfoEntity.name + "(" + UserManager.getInstance().userId + ")",
|
||||
UserManager.getInstance().userId)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showFloatingWindow() {
|
||||
updateShouldShowFloatingWindow(true)
|
||||
updateShouldShowFloatingWindowDot(true)
|
||||
updateFloatingWindow()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun dismissFloatingWindow() {
|
||||
updateShouldShowFloatingWindow(false)
|
||||
updateShouldShowFloatingWindowDot(false)
|
||||
updateFloatingWindow()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeNotification() {
|
||||
val notificationManager = HaloApp.getInstance().application?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(ImReceiver.NOTIFICATION_ID)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun updateFloatingWindow() {
|
||||
try {
|
||||
CurrentActivityHolder.getCurrentActivity()?.let {
|
||||
if (isActivityValid(it)) {
|
||||
if (shouldShowFloatingWindow) {
|
||||
ImHintHelper.show(it)
|
||||
} else {
|
||||
ImHintHelper.dismiss(it)
|
||||
removeNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun sendFeedbackMessage(message: String) {
|
||||
val fromToMessage = IMMessage.createTxtMessage(message)
|
||||
HaloApp.getInstance().mainExecutor.execute {
|
||||
IMChat.getInstance().sendMessage(fromToMessage, object : ChatListener {
|
||||
override fun onProgress(p0: Int) {}
|
||||
override fun onSuccess() {}
|
||||
override fun onFailed() {}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun updateShouldShowFloatingWindow(show: Boolean) {
|
||||
SPUtils.setBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId, show)
|
||||
shouldShowFloatingWindow = show
|
||||
}
|
||||
|
||||
fun updateShouldShowFloatingWindowDot(show: Boolean) {
|
||||
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, show)
|
||||
shouldShowFloatingWindowDot = show
|
||||
}
|
||||
|
||||
private fun isActivityValid(activity: Activity): Boolean {
|
||||
return when (activity) {
|
||||
is MainActivity -> true
|
||||
is SuggestSelectActivity -> true
|
||||
is MessageActivity -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
76
app/src/main/java/com/gh/common/im/ImReceiver.kt
Normal file
76
app/src/main/java/com/gh/common/im/ImReceiver.kt
Normal file
@ -0,0 +1,76 @@
|
||||
package com.gh.common.im
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.gamecenter.R
|
||||
import com.m7.imkfsdk.chat.ChatActivity
|
||||
import com.moor.imkf.IMChatManager
|
||||
import com.moor.imkf.utils.Utils
|
||||
|
||||
class ImReceiver : BroadcastReceiver() {
|
||||
|
||||
companion object {
|
||||
const val UNIQUE_BROADCAST_ACTION = "com.gh.im"
|
||||
const val NOTIFICATION_ID: Int = 987321
|
||||
}
|
||||
|
||||
var notificationManager: NotificationManager? = null
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
intent?.let {
|
||||
if (intent.action == IMChatManager.NEW_MSG_ACTION) {
|
||||
notificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
// 判断 ImActivity 是否在最顶端
|
||||
if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
|
||||
ImManager.showFloatingWindow()
|
||||
ImManager.updateShouldShowFloatingWindowDot(false)
|
||||
} else {
|
||||
val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
|
||||
|
||||
contentIntent.putExtra("PeerId", "")
|
||||
contentIntent.putExtra("type", "peedId")
|
||||
|
||||
contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
val resultPendingIntent = PendingIntent.getActivity(
|
||||
Utils.getApp(),
|
||||
0,
|
||||
contentIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
// 新的通知
|
||||
val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
|
||||
val notification = builder.setTicker("您有新的消息")
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(resultPendingIntent)
|
||||
.setContentTitle("光环助手客服回复")
|
||||
.setContentText("您有新的消息")
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
notificationManager?.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
if (notification != null) {
|
||||
notificationManager?.notify(NOTIFICATION_ID, notification)
|
||||
ImManager.showFloatingWindow()
|
||||
}
|
||||
}
|
||||
} else if (intent.action == IMChatManager.FINISH_ACTION) {
|
||||
ImManager.dismissFloatingWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
170
app/src/main/java/com/gh/common/notifier/Notifier.kt
Normal file
170
app/src/main/java/com/gh/common/notifier/Notifier.kt
Normal file
@ -0,0 +1,170 @@
|
||||
package com.gh.common.notifier
|
||||
|
||||
import android.app.Activity
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.gamecenter.*
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
class Notifier private constructor() {
|
||||
|
||||
companion object {
|
||||
|
||||
private var activityWeakReference: WeakReference<Activity>? = null
|
||||
|
||||
private const val SP_VIEWED_NOTIFIER = "viewed_notifier"
|
||||
|
||||
/**
|
||||
* 根据内容决定是否显示 Notifier
|
||||
*/
|
||||
@JvmStatic
|
||||
fun shouldShowNotifier(content: String): Boolean {
|
||||
val viewedNotifierCollection = SPUtils.getString(SP_VIEWED_NOTIFIER)
|
||||
return !viewedNotifierCollection.contains(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记相应内容的 Notifier 已经显示过了
|
||||
*/
|
||||
@JvmStatic
|
||||
fun tagNotifierAsShowed(content: String) {
|
||||
val viewedNotifierCollection = SPUtils.getString(SP_VIEWED_NOTIFIER)
|
||||
if (viewedNotifierCollection.length > 1000) {
|
||||
SPUtils.setString(SP_VIEWED_NOTIFIER, content)
|
||||
} else {
|
||||
SPUtils.setString(SP_VIEWED_NOTIFIER, viewedNotifierCollection + content)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun create(activity: Activity?): Notifier {
|
||||
if (activity == null) {
|
||||
throw IllegalArgumentException("Activity cannot be null!")
|
||||
}
|
||||
|
||||
val notifier = Notifier()
|
||||
|
||||
// Hide current NotifierView, if one is active
|
||||
clearCurrent(activity)
|
||||
|
||||
notifier.setActivity(activity)
|
||||
notifier.notifierView = NotifierView(activity)
|
||||
|
||||
return notifier
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isActivityValid(activity: Activity?): Boolean {
|
||||
if (activity == null) return false
|
||||
|
||||
return when (activity) {
|
||||
is MessageActivity -> false
|
||||
is DownloadManagerActivity -> false
|
||||
is CleanApkActivity -> false
|
||||
is SplashScreenActivity -> false
|
||||
else -> isNotExistInActivity(activity)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isNotExistInActivity(activity: Activity?): Boolean {
|
||||
if (activity == null) return false
|
||||
|
||||
(activity.window?.decorView as? ViewGroup)?.let {
|
||||
//Find all NotifierView Views in Parent layout
|
||||
for (i in 0..it.childCount) {
|
||||
val childView = if (it.getChildAt(i) is NotifierView) it.getChildAt(i) as NotifierView else null
|
||||
if (childView != null && childView.windowToken != null) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the currently showing notifierView view, if one is present
|
||||
*
|
||||
* @param activity The current Activity
|
||||
*/
|
||||
@JvmStatic
|
||||
fun clearCurrent(activity: Activity?) {
|
||||
(activity?.window?.decorView as? ViewGroup)?.let {
|
||||
//Find all NotifierView Views in Parent layout
|
||||
for (i in 0..it.childCount) {
|
||||
val childView = if (it.getChildAt(i) is NotifierView) it.getChildAt(i) as NotifierView else null
|
||||
if (childView != null && childView.windowToken != null) {
|
||||
ViewCompat.animate(childView).alpha(0f).withEndAction(getRemoveViewRunnable(childView))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun hide() {
|
||||
activityWeakReference?.get()?.let { clearCurrent(it) }
|
||||
}
|
||||
|
||||
private fun getRemoveViewRunnable(childView: NotifierView?): Runnable {
|
||||
return Runnable {
|
||||
childView?.let {
|
||||
(childView.parent as? ViewGroup)?.removeView(childView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var notifierView: NotifierView? = null
|
||||
|
||||
private val activityDecorView: ViewGroup?
|
||||
get() {
|
||||
var decorView: ViewGroup? = null
|
||||
|
||||
activityWeakReference?.get()?.let {
|
||||
decorView = it.window.decorView as ViewGroup
|
||||
}
|
||||
|
||||
return decorView
|
||||
}
|
||||
|
||||
fun show(showVerticalTranslateAnimation: Boolean, delay: Long? = 0): NotifierView? {
|
||||
activityWeakReference?.get()?.let {
|
||||
it.runOnUiThread {
|
||||
activityDecorView?.postDelayed({
|
||||
notifierView?.showVerticalTranslateAnimation = showVerticalTranslateAnimation
|
||||
activityDecorView?.addView(notifierView)
|
||||
}, delay!!)
|
||||
}
|
||||
}
|
||||
|
||||
return notifierView
|
||||
}
|
||||
|
||||
fun setIcon(url: String?): Notifier {
|
||||
url?.let { notifierView?.setIcon(it) }
|
||||
return this
|
||||
}
|
||||
|
||||
fun setText(text: String?): Notifier {
|
||||
notifierView?.setText(text)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun setDuration(time: Long): Notifier {
|
||||
notifierView?.duration = time
|
||||
return this
|
||||
}
|
||||
|
||||
fun setOnClickListener(onClickListener: View.OnClickListener): Notifier {
|
||||
notifierView?.findViewById<View>(R.id.cardView)?.setOnClickListener(onClickListener)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun setActivity(activity: Activity) {
|
||||
activityWeakReference = WeakReference(activity)
|
||||
}
|
||||
}
|
||||
332
app/src/main/java/com/gh/common/notifier/NotifierView.kt
Normal file
332
app/src/main/java/com/gh/common/notifier/NotifierView.kt
Normal file
@ -0,0 +1,332 @@
|
||||
package com.gh.common.notifier
|
||||
|
||||
import android.animation.*
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Path
|
||||
import android.os.Build
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.widget.FrameLayout
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.doOnEnd
|
||||
import com.gh.common.util.doOnStart
|
||||
import com.gh.gamecenter.R
|
||||
import kotlinx.android.synthetic.main.view_notifier.view.*
|
||||
|
||||
class NotifierView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: FrameLayout(context, attrs, defStyle) {
|
||||
|
||||
companion object {
|
||||
const val SCALE_MINI = 0.2F
|
||||
const val SCALE_DEFAULT = 1F
|
||||
|
||||
const val DEFAULT_DURATION = 500L
|
||||
}
|
||||
|
||||
var onShowListener: OnShowNotificationListener? = null
|
||||
var onHideListener: OnHideNotificationListener? = null
|
||||
|
||||
lateinit var expandAnimator: ValueAnimator
|
||||
lateinit var shrinkAnimator: ValueAnimator
|
||||
|
||||
lateinit var translateUpAnimator: ObjectAnimator
|
||||
lateinit var translateDownAnimator: ObjectAnimator
|
||||
|
||||
lateinit var translateToLeftAnimator: ObjectAnimator
|
||||
lateinit var translateToRightAnimator: ObjectAnimator
|
||||
|
||||
lateinit var zoomInAnimator: ObjectAnimator
|
||||
lateinit var zoomOutAnimator: ObjectAnimator
|
||||
|
||||
var showAnimatorSet: AnimatorSet
|
||||
var hideAnimatorSet: AnimatorSet
|
||||
|
||||
var rightToLeftPath: Path
|
||||
var leftToRightPath: Path
|
||||
|
||||
var veryRight: Float = 0F
|
||||
var veryBottom: Float = 0F
|
||||
var centerX: Float = 0F
|
||||
|
||||
var navigationHeight = 0
|
||||
|
||||
var textWidth: Int = 0
|
||||
var cardViewWidth: Int = 0
|
||||
var verticalAnimationOffset: Int = 0
|
||||
|
||||
var duration = DEFAULT_DURATION
|
||||
|
||||
var showVerticalTranslateAnimation: Boolean = true
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.view_notifier, this)
|
||||
|
||||
ViewCompat.setTranslationZ(this, Integer.MAX_VALUE.toFloat())
|
||||
|
||||
cardView.scaleX = SCALE_MINI
|
||||
cardView.scaleY = SCALE_MINI
|
||||
|
||||
verticalAnimationOffset = dp2px(100F)
|
||||
|
||||
navigationHeight = retrieveNavigationHeight()
|
||||
|
||||
rightToLeftPath = Path()
|
||||
leftToRightPath = Path()
|
||||
|
||||
showAnimatorSet = AnimatorSet()
|
||||
hideAnimatorSet = AnimatorSet()
|
||||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
|
||||
centerX = (left + right - cardViewWidth) / 2F
|
||||
|
||||
// TODO Provide method to change these absolute offset.
|
||||
val r = right - dp2px(72F).toFloat()
|
||||
val b = bottom - dp2px(145F).toFloat() - navigationHeight
|
||||
|
||||
// Only set
|
||||
if (veryRight != r || veryBottom != b) {
|
||||
veryRight = r
|
||||
veryBottom = b
|
||||
|
||||
rightToLeftPath.moveTo(r, b)
|
||||
rightToLeftPath.lineTo(centerX, b)
|
||||
|
||||
leftToRightPath.moveTo(centerX, b)
|
||||
leftToRightPath.lineTo(r, b)
|
||||
|
||||
initAnimator()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initAnimator() {
|
||||
expandAnimator = ValueAnimator.ofFloat(0F, 1F)
|
||||
expandAnimator.duration = DEFAULT_DURATION
|
||||
expandAnimator.addUpdateListener { a ->
|
||||
val progress = a?.animatedValue as Float
|
||||
tvText.width = (textWidth * progress).toInt()
|
||||
}
|
||||
expandAnimator.doOnEnd {
|
||||
enableSwipeToDismiss()
|
||||
shrinkAfterDelay()
|
||||
}
|
||||
|
||||
shrinkAnimator = ValueAnimator.ofFloat(1F, 0F)
|
||||
shrinkAnimator.duration = DEFAULT_DURATION
|
||||
shrinkAnimator.addUpdateListener { a ->
|
||||
val progress = a?.animatedValue as Float
|
||||
tvText.width = (textWidth * progress).toInt()
|
||||
}
|
||||
shrinkAnimator.doOnEnd {
|
||||
val lp = FrameLayout.LayoutParams(cardView.layoutParams)
|
||||
lp.gravity = Gravity.NO_GRAVITY
|
||||
cardView.layoutParams = lp
|
||||
|
||||
disableSwipeToDismiss()
|
||||
}
|
||||
|
||||
translateToLeftAnimator = ObjectAnimator.ofFloat(cardView, "translationX", veryRight, centerX)
|
||||
translateToLeftAnimator.duration = DEFAULT_DURATION
|
||||
translateToLeftAnimator.doOnEnd {
|
||||
onShowListener?.onShow()
|
||||
|
||||
val lp = FrameLayout.LayoutParams(cardView.layoutParams)
|
||||
lp.gravity = Gravity.CENTER_HORIZONTAL
|
||||
cardView.layoutParams = lp
|
||||
cardView.translationX = 0f
|
||||
|
||||
expandAnimator.start()
|
||||
}
|
||||
|
||||
translateToRightAnimator = ObjectAnimator.ofFloat(cardView, "translationX", centerX, veryRight)
|
||||
translateToRightAnimator.duration = DEFAULT_DURATION
|
||||
|
||||
translateUpAnimator = ObjectAnimator.ofFloat(cardView, "translationY", veryBottom + verticalAnimationOffset, veryBottom)
|
||||
translateUpAnimator.duration = DEFAULT_DURATION
|
||||
translateUpAnimator.doOnStart { cardView.translationX = veryRight }
|
||||
|
||||
translateDownAnimator = ObjectAnimator.ofFloat(cardView, "translationY", veryBottom, veryBottom + verticalAnimationOffset)
|
||||
translateDownAnimator.duration = DEFAULT_DURATION
|
||||
|
||||
zoomInAnimator = ObjectAnimator.ofPropertyValuesHolder(cardView, PropertyValuesHolder.ofFloat("scaleX", SCALE_DEFAULT),
|
||||
PropertyValuesHolder.ofFloat("scaleY", SCALE_DEFAULT))
|
||||
zoomInAnimator.duration = DEFAULT_DURATION
|
||||
zoomInAnimator.doOnStart { cardView.translationX = veryRight }
|
||||
zoomInAnimator.doOnStart { cardView.translationY = veryBottom }
|
||||
|
||||
zoomOutAnimator = ObjectAnimator.ofPropertyValuesHolder(cardView, PropertyValuesHolder.ofFloat("scaleX", SCALE_MINI),
|
||||
PropertyValuesHolder.ofFloat("scaleY", SCALE_MINI))
|
||||
zoomOutAnimator.duration = DEFAULT_DURATION
|
||||
zoomOutAnimator.doOnEnd { removeFromParent() }
|
||||
|
||||
if (showVerticalTranslateAnimation) {
|
||||
showAnimatorSet.play(translateUpAnimator).with(zoomInAnimator).before(translateToLeftAnimator)
|
||||
} else {
|
||||
showAnimatorSet.play(zoomInAnimator).before(translateToLeftAnimator)
|
||||
}
|
||||
showAnimatorSet.start()
|
||||
}
|
||||
|
||||
private fun enableSwipeToDismiss() {
|
||||
cardView?.setOnTouchListener(SwipeDismissTouchListener(cardView, object : SwipeDismissTouchListener.DismissCallbacks {
|
||||
override fun canDismiss(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDismiss(view: View) {
|
||||
removeFromParent()
|
||||
}
|
||||
|
||||
override fun onTouch(view: View, touch: Boolean) {
|
||||
// Ignore.
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private fun disableSwipeToDismiss() {
|
||||
cardView?.setOnTouchListener(null)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
|
||||
showAnimatorSet.cancel()
|
||||
hideAnimatorSet.cancel()
|
||||
|
||||
removeAllListeners(expandAnimator,
|
||||
shrinkAnimator,
|
||||
translateUpAnimator,
|
||||
translateDownAnimator,
|
||||
translateToLeftAnimator,
|
||||
translateToRightAnimator)
|
||||
}
|
||||
|
||||
private fun removeAllListeners(vararg ts: Animator) {
|
||||
for (a in ts) {
|
||||
a.removeAllListeners()
|
||||
if (a is ValueAnimator) {
|
||||
a.removeAllUpdateListeners()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
performClick()
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
|
||||
private fun shrinkAfterDelay() {
|
||||
postDelayed({ shrink() }, duration)
|
||||
}
|
||||
|
||||
fun shrink() {
|
||||
shrinkAnimator.doOnEnd { hide() }
|
||||
shrinkAnimator.start()
|
||||
}
|
||||
|
||||
private fun removeFromParent() {
|
||||
clearAnimation()
|
||||
visibility = View.GONE
|
||||
|
||||
postDelayed(object : Runnable {
|
||||
override fun run() {
|
||||
try {
|
||||
if (parent == null) {
|
||||
Log.e(javaClass.simpleName, "getParent() returning Null")
|
||||
} else {
|
||||
try {
|
||||
(parent as ViewGroup).removeView(this@NotifierView)
|
||||
|
||||
onHideListener?.onHide()
|
||||
} catch (ex: Exception) {
|
||||
Log.e(javaClass.simpleName, "Cannot remove from parent layout")
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Log.e(javaClass.simpleName, Log.getStackTraceString(ex))
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
fun setText(text: String?) {
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
tvText.text = text
|
||||
tvText.measure(0, 0)
|
||||
textWidth = tvText.measuredWidth
|
||||
tvText.width = 0
|
||||
|
||||
cardView.measure(0, 0)
|
||||
cardViewWidth = cardView.measuredWidth
|
||||
}
|
||||
}
|
||||
|
||||
fun hide() {
|
||||
if (showVerticalTranslateAnimation) {
|
||||
hideAnimatorSet.play(translateDownAnimator).with(zoomOutAnimator).after(translateToRightAnimator)
|
||||
} else {
|
||||
hideAnimatorSet.play(zoomOutAnimator).after(translateToRightAnimator)
|
||||
}
|
||||
hideAnimatorSet.start()
|
||||
}
|
||||
|
||||
fun setIcon(url: String) {
|
||||
ImageUtils.display(ivIcon, url)
|
||||
}
|
||||
|
||||
private fun dp2px(dp: Float): Int {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.applicationContext.resources.displayMetrics).toInt()
|
||||
}
|
||||
|
||||
private fun hasSoftKeys(): Boolean {
|
||||
if (context !is Activity) return false
|
||||
|
||||
val hasSoftwareKeys: Boolean
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
val d = (context as Activity).windowManager.defaultDisplay
|
||||
|
||||
val realDisplayMetrics = DisplayMetrics()
|
||||
d.getRealMetrics(realDisplayMetrics)
|
||||
|
||||
val realHeight = realDisplayMetrics.heightPixels
|
||||
val realWidth = realDisplayMetrics.widthPixels
|
||||
|
||||
val displayMetrics = DisplayMetrics()
|
||||
d.getMetrics(displayMetrics)
|
||||
|
||||
val displayHeight = displayMetrics.heightPixels
|
||||
val displayWidth = displayMetrics.widthPixels
|
||||
|
||||
hasSoftwareKeys = realWidth - displayWidth > 0 || realHeight - displayHeight > 0
|
||||
} else {
|
||||
val hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey()
|
||||
val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
|
||||
hasSoftwareKeys = !hasMenuKey && !hasBackKey
|
||||
}
|
||||
return hasSoftwareKeys
|
||||
}
|
||||
|
||||
private fun retrieveNavigationHeight(): Int {
|
||||
val resources = context.resources
|
||||
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
|
||||
return if (resourceId > 0 && hasSoftKeys()) resources.getDimensionPixelSize(resourceId) else 0
|
||||
}
|
||||
|
||||
interface OnShowNotificationListener {
|
||||
fun onShow()
|
||||
}
|
||||
|
||||
interface OnHideNotificationListener {
|
||||
fun onHide()
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,238 @@
|
||||
package com.gh.common.notifier
|
||||
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Modifications Copyright (C) 2017 David Kwon
|
||||
*/
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ValueAnimator
|
||||
import android.os.Build
|
||||
import android.support.annotation.RequiresApi
|
||||
import android.view.MotionEvent
|
||||
import android.view.VelocityTracker
|
||||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
|
||||
/**
|
||||
* A [View.OnTouchListener] that makes any [View] dismissable when the
|
||||
* user swipes (drags her finger) horizontally across the view.
|
||||
*
|
||||
* @param view The view to make dismissable.
|
||||
* @param callbacks The callback to trigger when the user has indicated that she would like to
|
||||
* dismiss this view.
|
||||
*/
|
||||
class SwipeDismissTouchListener(
|
||||
private val mView: View,
|
||||
private val mCallbacks: DismissCallbacks) : View.OnTouchListener {
|
||||
|
||||
// Cached ViewConfiguration and system-wide constant values
|
||||
private val mSlop: Int
|
||||
private val mMinFlingVelocity: Int
|
||||
private val mAnimationTime: Long
|
||||
private var mViewWidth = 1 // 1 and not 0 to prevent dividing by zero
|
||||
|
||||
// Transient properties
|
||||
private var mDownX: Float = 0.toFloat()
|
||||
private var mDownY: Float = 0.toFloat()
|
||||
private var mSwiping: Boolean = false
|
||||
private var mSwipingSlop: Int = 0
|
||||
private var mVelocityTracker: VelocityTracker? = null
|
||||
private var mTranslationX: Float = 0.toFloat()
|
||||
|
||||
init {
|
||||
val vc = ViewConfiguration.get(mView.context)
|
||||
mSlop = vc.scaledTouchSlop
|
||||
mMinFlingVelocity = vc.scaledMinimumFlingVelocity * 16
|
||||
mAnimationTime = mView.context.resources.getInteger(
|
||||
android.R.integer.config_shortAnimTime).toLong()
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
|
||||
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
|
||||
// offset because the view is translated during swipe
|
||||
motionEvent.offsetLocation(mTranslationX, 0f)
|
||||
|
||||
if (mViewWidth < 2) {
|
||||
mViewWidth = mView.width
|
||||
}
|
||||
|
||||
when (motionEvent.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
mDownX = motionEvent.rawX
|
||||
mDownY = motionEvent.rawY
|
||||
if (mCallbacks.canDismiss()) {
|
||||
mVelocityTracker = VelocityTracker.obtain()
|
||||
mVelocityTracker!!.addMovement(motionEvent)
|
||||
}
|
||||
mCallbacks.onTouch(view, true)
|
||||
return false
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
mVelocityTracker?.run {
|
||||
val deltaX = motionEvent.rawX - mDownX
|
||||
this.addMovement(motionEvent)
|
||||
this.computeCurrentVelocity(1000)
|
||||
val velocityX = this.xVelocity
|
||||
val absVelocityX = Math.abs(velocityX)
|
||||
val absVelocityY = Math.abs(this.yVelocity)
|
||||
var dismiss = false
|
||||
var dismissRight = false
|
||||
if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
|
||||
dismiss = true
|
||||
dismissRight = deltaX > 0
|
||||
} else if (mMinFlingVelocity <= absVelocityX && absVelocityY < absVelocityX && mSwiping) {
|
||||
// dismiss only if flinging in the same direction as dragging
|
||||
dismiss = velocityX < 0 == deltaX < 0
|
||||
dismissRight = this.xVelocity > 0
|
||||
}
|
||||
if (dismiss) {
|
||||
// dismiss
|
||||
mView.animate()
|
||||
.translationX((if (dismissRight) mViewWidth else -mViewWidth).toFloat())
|
||||
.alpha(0f)
|
||||
.setDuration(mAnimationTime)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
performDismiss()
|
||||
}
|
||||
})
|
||||
} else if (mSwiping) {
|
||||
// cancel
|
||||
mView.animate()
|
||||
.translationX(0f)
|
||||
.alpha(1f)
|
||||
.setDuration(mAnimationTime)
|
||||
.setListener(null)
|
||||
mCallbacks.onTouch(view, false)
|
||||
}
|
||||
this.recycle()
|
||||
mVelocityTracker = null
|
||||
mTranslationX = 0f
|
||||
mDownX = 0f
|
||||
mDownY = 0f
|
||||
mSwiping = false
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
mVelocityTracker?.run {
|
||||
mView.animate()
|
||||
.translationX(0f)
|
||||
.alpha(1f)
|
||||
.setDuration(mAnimationTime)
|
||||
.setListener(null)
|
||||
this.recycle()
|
||||
mVelocityTracker = null
|
||||
mTranslationX = 0f
|
||||
mDownX = 0f
|
||||
mDownY = 0f
|
||||
mSwiping = false
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
mVelocityTracker?.run {
|
||||
this.addMovement(motionEvent)
|
||||
val deltaX = motionEvent.rawX - mDownX
|
||||
val deltaY = motionEvent.rawY - mDownY
|
||||
if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
|
||||
mSwiping = true
|
||||
mSwipingSlop = if (deltaX > 0) mSlop else -mSlop
|
||||
mView.parent.requestDisallowInterceptTouchEvent(true)
|
||||
|
||||
// Cancel listview's touch
|
||||
val cancelEvent = MotionEvent.obtain(motionEvent)
|
||||
cancelEvent.action = MotionEvent.ACTION_CANCEL or (motionEvent.actionIndex shl MotionEvent.ACTION_POINTER_INDEX_SHIFT)
|
||||
mView.onTouchEvent(cancelEvent)
|
||||
cancelEvent.recycle()
|
||||
}
|
||||
|
||||
if (mSwiping) {
|
||||
mTranslationX = deltaX
|
||||
mView.translationX = deltaX - mSwipingSlop
|
||||
// TODO: use an ease-out interpolator or such
|
||||
mView.alpha = Math.max(0f, Math.min(1f,
|
||||
1f - 2f * Math.abs(deltaX) / mViewWidth))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
view.performClick()
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
|
||||
private fun performDismiss() {
|
||||
// Animate the dismissed view to zero-height and then fire the dismiss callback.
|
||||
// This triggers layout on each animation frame; in the future we may want to do something
|
||||
// smarter and more performant.
|
||||
|
||||
val lp = mView.layoutParams
|
||||
val originalHeight = mView.height
|
||||
|
||||
val animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime)
|
||||
|
||||
animator.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
mCallbacks.onDismiss(mView)
|
||||
// Reset view presentation
|
||||
mView.alpha = 1f
|
||||
mView.translationX = 0f
|
||||
lp.height = originalHeight
|
||||
mView.layoutParams = lp
|
||||
}
|
||||
})
|
||||
|
||||
animator.addUpdateListener { valueAnimator ->
|
||||
lp.height = valueAnimator.animatedValue as Int
|
||||
mView.layoutParams = lp
|
||||
}
|
||||
|
||||
animator.start()
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback interface used by [SwipeDismissTouchListener] to inform its client
|
||||
* about a successful dismissal of the view for which it was created.
|
||||
*/
|
||||
interface DismissCallbacks {
|
||||
/**
|
||||
* Called to determine whether the view can be dismissed.
|
||||
*
|
||||
* @return boolean The view can dismiss.
|
||||
*/
|
||||
fun canDismiss(): Boolean
|
||||
|
||||
/**
|
||||
* Called when the user has indicated they she would like to dismiss the view.
|
||||
*
|
||||
* @param view The originating [View]
|
||||
*/
|
||||
fun onDismiss(view: View)
|
||||
|
||||
/**
|
||||
* Called when the user touches the view or release the view.
|
||||
*
|
||||
* @param view The originating [View]
|
||||
* @param touch The view is being touched.
|
||||
*/
|
||||
fun onTouch(view: View, touch: Boolean)
|
||||
}
|
||||
}
|
||||
128
app/src/main/java/com/gh/common/util/Animator.kt
Normal file
128
app/src/main/java/com/gh/common/util/Animator.kt
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.gh.common.util
|
||||
|
||||
import android.animation.Animator
|
||||
import android.support.annotation.RequiresApi
|
||||
|
||||
/**
|
||||
* Since [Android KTX] has not release a stable build yet,
|
||||
* we copy a single class to achieve the same goal.
|
||||
*
|
||||
* You might check the original extension class in the link below.
|
||||
*
|
||||
* https://github.com/android/android-ktx/blob/master/src/main/java/androidx/core/animation/Animator.kt.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add an action which will be invoked when the animation has ended.
|
||||
*
|
||||
* @return the [Animator.AnimatorListener] added to the Animator
|
||||
* @see Animator.end
|
||||
*/
|
||||
fun Animator.doOnEnd(action: (animator: Animator) -> Unit) = addListener(onEnd = action)
|
||||
|
||||
/**
|
||||
* Add an action which will be invoked when the animation has started.
|
||||
*
|
||||
* @return the [Animator.AnimatorListener] added to the Animator
|
||||
* @see Animator.start
|
||||
*/
|
||||
fun Animator.doOnStart(action: (animator: Animator) -> Unit) = addListener(onStart = action)
|
||||
|
||||
/**
|
||||
* Add an action which will be invoked when the animation has been cancelled.
|
||||
*
|
||||
* @return the [Animator.AnimatorListener] added to the Animator
|
||||
* @see Animator.cancel
|
||||
*/
|
||||
fun Animator.doOnCancel(action: (animator: Animator) -> Unit) = addListener(onCancel = action)
|
||||
|
||||
/**
|
||||
* Add an action which will be invoked when the animation has repeated.
|
||||
* @return the [Animator.AnimatorListener] added to the Animator
|
||||
*/
|
||||
fun Animator.doOnRepeat(action: (animator: Animator) -> Unit) = addListener(onRepeat = action)
|
||||
|
||||
/**
|
||||
* Add an action which will be invoked when the animation has resumed after a pause.
|
||||
*
|
||||
* @return the [Animator.AnimatorPauseListener] added to the Animator
|
||||
* @see Animator.resume
|
||||
*/
|
||||
@RequiresApi(19)
|
||||
fun Animator.doOnResume(action: (animator: Animator) -> Unit) = addPauseListener(onResume = action)
|
||||
|
||||
/**
|
||||
* Add an action which will be invoked when the animation has been paused.
|
||||
*
|
||||
* @return the [Animator.AnimatorPauseListener] added to the Animator
|
||||
* @see Animator.pause
|
||||
*/
|
||||
@RequiresApi(19)
|
||||
fun Animator.doOnPause(action: (animator: Animator) -> Unit) = addPauseListener(onPause = action)
|
||||
|
||||
/**
|
||||
* Add a listener to this Animator using the provided actions.
|
||||
*/
|
||||
fun Animator.addListener(
|
||||
onEnd: ((animator: Animator) -> Unit)? = null,
|
||||
onStart: ((animator: Animator) -> Unit)? = null,
|
||||
onCancel: ((animator: Animator) -> Unit)? = null,
|
||||
onRepeat: ((animator: Animator) -> Unit)? = null
|
||||
): Animator.AnimatorListener {
|
||||
val listener = object : Animator.AnimatorListener {
|
||||
override fun onAnimationRepeat(animator: Animator) {
|
||||
onRepeat?.invoke(animator)
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animator: Animator) {
|
||||
onEnd?.invoke(animator)
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animator: Animator) {
|
||||
onCancel?.invoke(animator)
|
||||
}
|
||||
|
||||
override fun onAnimationStart(animator: Animator) {
|
||||
onStart?.invoke(animator)
|
||||
}
|
||||
}
|
||||
addListener(listener)
|
||||
return listener
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pause and resume listener to this Animator using the provided actions.
|
||||
*/
|
||||
@RequiresApi(19)
|
||||
fun Animator.addPauseListener(
|
||||
onResume: ((animator: Animator) -> Unit)? = null,
|
||||
onPause: ((animator: Animator) -> Unit)? = null
|
||||
): Animator.AnimatorPauseListener {
|
||||
val listener = object : Animator.AnimatorPauseListener {
|
||||
override fun onAnimationPause(animator: Animator) {
|
||||
onPause?.invoke(animator)
|
||||
}
|
||||
|
||||
override fun onAnimationResume(animator: Animator) {
|
||||
onResume?.invoke(animator)
|
||||
}
|
||||
}
|
||||
addPauseListener(listener)
|
||||
return listener
|
||||
}
|
||||
@ -2,7 +2,6 @@ package com.gh.common.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -12,16 +11,16 @@ import java.util.regex.Pattern;
|
||||
|
||||
public class AskUtils {
|
||||
|
||||
public static String voteCountFormat(int voteCount) {
|
||||
String vote;
|
||||
if (voteCount >= 10000) {
|
||||
DecimalFormat df = new DecimalFormat("#.0万");
|
||||
vote = df.format(voteCount / 10000f);
|
||||
} else {
|
||||
vote = String.valueOf(voteCount);
|
||||
}
|
||||
return vote;
|
||||
}
|
||||
// public static String voteCountFormat(int voteCount) {
|
||||
// String vote;
|
||||
// if (voteCount >= 10000) {
|
||||
// DecimalFormat df = new DecimalFormat("#.0万");
|
||||
// vote = df.format(voteCount / 10000f);
|
||||
// } else {
|
||||
// vote = String.valueOf(voteCount);
|
||||
// }
|
||||
// return vote;
|
||||
// }
|
||||
|
||||
public static String stripHtml(String htmlStr) {
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import android.text.TextUtils;
|
||||
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
/**
|
||||
* Created by khy on 28/06/17.
|
||||
@ -14,18 +15,12 @@ import com.gh.gamecenter.manager.UserManager;
|
||||
public class CheckLoginUtils {
|
||||
|
||||
public static void checkLogin(final Context context, OnLoginListener listener) {
|
||||
// String token = LoginUtils.getToken(context);
|
||||
if (TextUtils.isEmpty(UserManager.getInstance().getToken())) {
|
||||
AskLogUtils.login(context, "dialog", null);
|
||||
DialogUtils.showWarningDialog(context, "登录提示", "需要登录才能使用该功能喔!", "取消", "快速登录",
|
||||
new DialogUtils.ConfirmListener() {
|
||||
@Override
|
||||
public void onConfirm() {
|
||||
AskLogUtils.login(context, "activity", null);
|
||||
Intent intent = LoginActivity.getIntent(context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}, null);
|
||||
Utils.toast(context, "需要登录");
|
||||
LogUtils.login(context, "dialog", null);
|
||||
LogUtils.login(context, "activity", null);
|
||||
Intent intent = LoginActivity.getIntent(context);
|
||||
context.startActivity(intent);
|
||||
} else {
|
||||
listener.onLogin();
|
||||
}
|
||||
|
||||
@ -10,7 +10,11 @@ public class ClassUtils {
|
||||
name = "GameDetailActivity";
|
||||
}
|
||||
try {
|
||||
return Class.forName("com.gh.gamecenter." + name);
|
||||
if (!name.contains("com.gh")) {
|
||||
return Class.forName("com.gh.gamecenter." + name);
|
||||
} else {
|
||||
return Class.forName(name);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@ -5,13 +5,13 @@ import com.gh.gamecenter.eventbus.EBCollectionChanged
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
|
||||
/**
|
||||
* Created by khy on 26/07/17.
|
||||
|
||||
@ -445,7 +445,7 @@ public class CommentUtils {
|
||||
holder.commentLikeIv.setImageResource(R.drawable.ic_like_select);
|
||||
}
|
||||
holder.commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
holder.commentLikeCountTv.setText(String.valueOf(entity.getVote()));
|
||||
holder.commentLikeCountTv.setText(NumberUtils.transSimpleCount(entity.getVote()));
|
||||
}
|
||||
|
||||
//检查是否是自身评论
|
||||
@ -456,17 +456,27 @@ public class CommentUtils {
|
||||
} else {
|
||||
holder.commentUserNameTv.setText(userInfo.getName());
|
||||
}
|
||||
ImageUtils.Companion.display(holder.commentUserIconDv, userInfo.getIcon());
|
||||
if (userInfo.getAuth() != null) {
|
||||
ImageUtils.display(holder.commentUserBadgeIv, userInfo.getAuth().getIcon());
|
||||
} else {
|
||||
ImageUtils.display(holder.commentUserBadgeIv, "");
|
||||
}
|
||||
ImageUtils.displayIcon(holder.commentUserIconDv, userInfo.getIcon());
|
||||
} else {
|
||||
if (entity.getMe() != null && entity.getMe().isAnswerOwn()) {
|
||||
holder.commentUserNameTv.setText(entity.getUser().getName() + "(作者)");
|
||||
} else {
|
||||
holder.commentUserNameTv.setText(entity.getUser().getName());
|
||||
}
|
||||
if (TextUtils.isEmpty(entity.getUser().getIcon())) {
|
||||
ImageUtils.Companion.display(holder.commentUserIconDv, R.drawable.user_default_icon_comment);
|
||||
if (entity.getUser().getAuth() != null) {
|
||||
ImageUtils.display(holder.commentUserBadgeIv, entity.getUser().getAuth().getIcon());
|
||||
} else {
|
||||
ImageUtils.Companion.display(holder.commentUserIconDv, entity.getUser().getIcon());
|
||||
ImageUtils.display(holder.commentUserBadgeIv, "");
|
||||
}
|
||||
if (TextUtils.isEmpty(entity.getUser().getIcon())) {
|
||||
ImageUtils.display(holder.commentUserIconDv, R.drawable.user_default_icon_comment);
|
||||
} else {
|
||||
ImageUtils.displayIcon(holder.commentUserIconDv, entity.getUser().getIcon());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
164
app/src/main/java/com/gh/common/util/CompressImageUtils.kt
Normal file
164
app/src/main/java/com/gh/common/util/CompressImageUtils.kt
Normal file
@ -0,0 +1,164 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.gamecenter.entity.SettingsEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
/**
|
||||
* Created by khy on 02/08/18.
|
||||
* 图片压缩工具类
|
||||
* 资料参考:https://github.com/zetbaitsu/Compressor
|
||||
* 压缩算法:http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/298
|
||||
*/
|
||||
object CompressImageUtils {
|
||||
|
||||
private const val compressLimitSize: Long = 50 * 1024
|
||||
private const val defaultQuality = 90
|
||||
private const val defaultRatio = 2
|
||||
private const val defaultCompressBorder = 1280
|
||||
|
||||
/**
|
||||
* 压缩图片并保存到目标文件
|
||||
* 该压缩方法是同步执行 请勿在主线程执行
|
||||
* 返回源文件的三种情况:小于特定值,图片类型为GIF,压缩失败
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
fun compressImageAndSaveToFile(imageFile: File, compressGif: Boolean): File {
|
||||
// 小于300K直接返回原图
|
||||
if (imageFile.length() < getImageSetting().processLimitSize) {
|
||||
return imageFile
|
||||
}
|
||||
|
||||
val cacheDir = getImageCacheDir()
|
||||
val parentFile = cacheDir.parentFile
|
||||
if (!parentFile.exists()) parentFile.mkdirs()
|
||||
var fileOutputStream: FileOutputStream? = null
|
||||
|
||||
try {
|
||||
// 确定图片类型
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(imageFile.absolutePath, options)
|
||||
val formatType = if (options.outMimeType.contains("png")) {
|
||||
Bitmap.CompressFormat.PNG
|
||||
} else if (options.outMimeType.contains("gif") && !compressGif) { // gif直接返回原图
|
||||
return imageFile
|
||||
} else {
|
||||
Bitmap.CompressFormat.WEBP
|
||||
}
|
||||
|
||||
fileOutputStream = FileOutputStream(cacheDir)
|
||||
// write the compressed bitmap at the destination specified by destinationPath.
|
||||
decodeSampledBitmapFromFile(imageFile).compress(formatType, getImageSetting().quality, fileOutputStream)
|
||||
return cacheDir
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
if (cacheDir.exists()) {
|
||||
cacheDir.delete()
|
||||
}
|
||||
} finally {
|
||||
if (fileOutputStream != null) {
|
||||
fileOutputStream.flush()
|
||||
fileOutputStream.close()
|
||||
}
|
||||
}
|
||||
return imageFile
|
||||
}
|
||||
|
||||
private fun getImageCacheDir(): File {
|
||||
// return File(Environment.getExternalStorageDirectory().absolutePath + "/Pictures/test/" + System.currentTimeMillis() + ".jpg")
|
||||
// 统一用jpg保存应该没有影响吧
|
||||
return File(HaloApp.getInstance().application.cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg")
|
||||
}
|
||||
|
||||
// 根据图片获取压缩后的位图
|
||||
@Throws(Exception::class)
|
||||
private fun decodeSampledBitmapFromFile(imageFile: File): Bitmap {
|
||||
// First decode with inJustDecodeBounds=true to check dimensions
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(imageFile.absolutePath, options)
|
||||
|
||||
// Raw height and width of image
|
||||
val height = options.outHeight
|
||||
val width = options.outWidth
|
||||
var inSampleSize = 1
|
||||
|
||||
var compressType: CompressType? = null
|
||||
|
||||
val longSide = Math.max(height, width) //最长边
|
||||
val shortSide = Math.min(height, width) //最短边
|
||||
val scale = longSide.toFloat() / shortSide // 长短边比例
|
||||
val compressLimit = getImageSetting().size
|
||||
|
||||
if (longSide > compressLimit && shortSide > compressLimit) {
|
||||
if (scale > getImageSetting().ratio) {
|
||||
inSampleSize = if (shortSide / compressLimit == 0) 1 else shortSide / compressLimit
|
||||
compressType = CompressType.LIMIT_SHORT // 横向长方形
|
||||
} else {
|
||||
inSampleSize = if (longSide / compressLimit == 0) 1 else longSide / compressLimit
|
||||
compressType = CompressType.LIMIT_LONG // 纵向长方形
|
||||
|
||||
}
|
||||
} else if (longSide > compressLimit && shortSide < compressLimit) {
|
||||
if (scale <= getImageSetting().ratio) {
|
||||
inSampleSize = if (longSide / compressLimit == 0) 1 else longSide / compressLimit
|
||||
compressType = CompressType.LIMIT_LONG
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate inSampleSize
|
||||
options.inSampleSize = inSampleSize
|
||||
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false
|
||||
|
||||
var scaledBitmap = BitmapFactory.decodeFile(imageFile.absolutePath, options)
|
||||
|
||||
val matrix = Matrix() // 精确缩放
|
||||
if (compressType != null) {
|
||||
val targetMatrixScale = if (compressType == CompressType.LIMIT_SHORT) {
|
||||
if (scaledBitmap.width > scaledBitmap.height) {
|
||||
compressLimit.toFloat() / scaledBitmap.height
|
||||
} else {
|
||||
compressLimit.toFloat() / scaledBitmap.width
|
||||
}
|
||||
} else {
|
||||
if (scaledBitmap.width > scaledBitmap.height) {
|
||||
compressLimit.toFloat() / scaledBitmap.width
|
||||
} else {
|
||||
compressLimit.toFloat() / scaledBitmap.height
|
||||
}
|
||||
}
|
||||
matrix.setScale(targetMatrixScale, targetMatrixScale)
|
||||
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.width, scaledBitmap.height, matrix, true)
|
||||
}
|
||||
return scaledBitmap
|
||||
}
|
||||
|
||||
fun getImageSetting(): SettingsEntity.Image {
|
||||
var settings = Config.getSettings()
|
||||
if (settings == null && settings?.image != null) {
|
||||
return settings.image
|
||||
}
|
||||
settings = SettingsEntity()
|
||||
val image = settings.Image()
|
||||
image.processLimitSize = compressLimitSize
|
||||
image.size = defaultCompressBorder
|
||||
image.ratio = defaultRatio
|
||||
image.quality = defaultQuality
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
enum class CompressType {
|
||||
// 0: 短边等比压缩至1280 H:长边 W:短边
|
||||
LIMIT_SHORT,
|
||||
// 1: 取长边等比压缩至1280 H:短边 W: 长边
|
||||
LIMIT_LONG
|
||||
}
|
||||
@ -69,7 +69,7 @@ public class ConcernContentUtils {
|
||||
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
|
||||
lparams.weight = 1;
|
||||
imageView.setLayoutParams(lparams);
|
||||
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
|
||||
ImageUtils.display(context.getResources(), imageView, width / 3 - DisplayUtils.dip2px(context, 4),
|
||||
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
|
||||
break;
|
||||
case 1:
|
||||
@ -78,7 +78,7 @@ public class ConcernContentUtils {
|
||||
lparams.setMargins(DisplayUtils.dip2px(context, 2), 0,
|
||||
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
|
||||
imageView.setLayoutParams(lparams);
|
||||
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
|
||||
ImageUtils.display(context.getResources(), imageView, lparams.width,
|
||||
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
|
||||
break;
|
||||
default:
|
||||
@ -89,7 +89,7 @@ public class ConcernContentUtils {
|
||||
DisplayUtils.dip2px(context, 2), DisplayUtils.dip2px(context, 4));
|
||||
lparams.weight = 1;
|
||||
imageView.setLayoutParams(lparams);
|
||||
ImageUtils.Companion.getInstance().display(context.getResources(), imageView,
|
||||
ImageUtils.display(context.getResources(), imageView, width / 2 - DisplayUtils.dip2px(context, 4),
|
||||
ScalingUtils.ScaleType.CENTER_CROP, list.get(position));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5,14 +5,14 @@ import com.gh.gamecenter.eventbus.EBConcernChanged
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.json.JSONArray
|
||||
import retrofit2.HttpException
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/8/24.
|
||||
@ -69,8 +69,7 @@ object ConcernUtils {
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
override fun onResponse(response: ResponseBody) {
|
||||
super.onResponse(response)
|
||||
override fun onResponse(response: ResponseBody?) {
|
||||
EventBus.getDefault().post(EBConcernChanged())
|
||||
}
|
||||
})
|
||||
|
||||
@ -2,10 +2,11 @@ package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
@ -13,11 +14,11 @@ import org.json.JSONObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by LGT on 2016/12/8.
|
||||
@ -42,7 +43,7 @@ public class DataLogUtils {
|
||||
String channel = HaloApp.getInstance().getChannel();
|
||||
map.put("version", version);
|
||||
map.put("user", user);
|
||||
map.put("device_id", TokenUtils.getDeviceId(context));
|
||||
map.put("device_id", Util_System_Phone_State.getDeviceId(context));
|
||||
map.put("channel", channel);
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
|
||||
@ -117,7 +117,7 @@ public class DataUtils {
|
||||
// }
|
||||
Properties prop = new Properties();
|
||||
for (int i = 0; i < kv.length; i++) {
|
||||
if (i % 2 != 0 || i != 0) {
|
||||
if (i % 2 != 0 && i != 0) {
|
||||
String key = kv[i - 1];
|
||||
String value = kv[i];
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
@ -163,18 +163,39 @@ public class DataUtils {
|
||||
StatService.trackCustomKVEvent(var0, var1, prop);
|
||||
}
|
||||
|
||||
public static void trackTimeEvent(Context context, String eventId, int costTime, String... kv) {
|
||||
|
||||
Properties prop = new Properties();
|
||||
for (int i = 0; i < kv.length; i++) {
|
||||
if (i % 2 != 0 || i != 0) {
|
||||
String key = kv[i - 1];
|
||||
String value = kv[i];
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
prop.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prop.size() == 0) return;
|
||||
|
||||
StatService.trackCustomKVTimeIntervalEvent(context, costTime, eventId, prop);
|
||||
}
|
||||
|
||||
// 游戏下载
|
||||
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status) {
|
||||
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
|
||||
Map<String, Object> kv = new HashMap<>();
|
||||
|
||||
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
|
||||
|
||||
kv.put("版本", platform);
|
||||
kv.put("状态", status);
|
||||
kv.put("用户机型", Build.MODEL);
|
||||
kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
|
||||
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
kv.put("位置", entrance);
|
||||
kv.put("类型", method);
|
||||
kv.put("厂商", Build.MANUFACTURER);
|
||||
kv.put("Android版本", Build.VERSION.RELEASE);
|
||||
onEvent(context, "游戏下载", gameName, kv);
|
||||
|
||||
Map<String, Object> kv2 = new HashMap<>();
|
||||
|
||||
139
app/src/main/java/com/gh/common/util/DeviceTokenUtils.kt
Normal file
139
app/src/main/java/com/gh/common/util/DeviceTokenUtils.kt
Normal file
@ -0,0 +1,139 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import android.preference.PreferenceManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.retrofit.StringResponse
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_Phone_State
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.File
|
||||
|
||||
|
||||
object DeviceTokenUtils {
|
||||
|
||||
const val DEVICE_ID = "uuid"
|
||||
|
||||
// 同步服务器时间
|
||||
@JvmStatic
|
||||
@Synchronized
|
||||
fun syncServerTime(context: Context) {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
RetrofitManager.getInstance(context).api.time
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : StringResponse() {
|
||||
override fun onResponse(response: String) {
|
||||
if (response.matches("^[0-9]{10}$".toRegex())) {
|
||||
try {
|
||||
val editor = sp.edit()
|
||||
editor.putLong("server_time", java.lang.Long.parseLong(response))
|
||||
editor.putLong("client_time", System.currentTimeMillis() / 1000)
|
||||
editor.apply()
|
||||
} catch (e: NumberFormatException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getLaunchType(): LunchType {
|
||||
var lunchType: LunchType? = null
|
||||
val values = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application).all
|
||||
// 版本更新
|
||||
if (values.isNotEmpty()) {
|
||||
for (value in values) {
|
||||
if (value.key.contains("isNewFirstLaunchV")) {
|
||||
lunchType = LunchType.update
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 再次重装
|
||||
if (lunchType == null && !getDeviceId().isNullOrEmpty()) {
|
||||
lunchType = LunchType.again
|
||||
}
|
||||
// 首次安装
|
||||
if (lunchType == null) {
|
||||
lunchType = LunchType.first
|
||||
}
|
||||
// 保存deviceId
|
||||
var deviceId = Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
|
||||
if (deviceId.isNullOrEmpty()) {
|
||||
deviceId = Utils.getTime(HaloApp.getInstance().application).toString()
|
||||
}
|
||||
setDeviceId(deviceId)
|
||||
|
||||
return lunchType
|
||||
}
|
||||
|
||||
private fun getDeviceFileList(): List<File> {
|
||||
val sdCardDir = Environment.getExternalStorageDirectory()
|
||||
val fileList: MutableList<File> = ArrayList()
|
||||
fileList.add(File(sdCardDir.path + "/gh-uuid/$DEVICE_ID"))
|
||||
fileList.add(File(sdCardDir.path + "/system/$DEVICE_ID"))
|
||||
fileList.add(File(sdCardDir.path + "/data/$DEVICE_ID"))
|
||||
return fileList
|
||||
}
|
||||
|
||||
|
||||
@Synchronized
|
||||
private fun setDeviceId(deviceId: String) {
|
||||
//将deviceId存到sp
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application)
|
||||
val edit = sp.edit()
|
||||
edit.putString(DEVICE_ID, deviceId)
|
||||
edit.apply()
|
||||
Utils.log("saveDeviceId", "保存成功SP")
|
||||
|
||||
//将deviceId存到SD卡
|
||||
for (file in getDeviceFileList()) {
|
||||
try {
|
||||
val parentFile = file.parentFile
|
||||
if (!parentFile.exists()) parentFile.mkdirs()
|
||||
file.writeText(deviceId)
|
||||
Utils.log("saveDeviceId", "保存成功SDCard目录为:${file.path}")
|
||||
} catch (e: Exception) {
|
||||
Utils.log("保存u${DEVICE_ID}到SDCard异常${file.path} " + e.toString())
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDeviceId(): String? {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application)
|
||||
var deviceId = sp.getString(DEVICE_ID, null)
|
||||
if (deviceId.isNullOrEmpty()) {
|
||||
val fileList = getDeviceFileList()
|
||||
for (file in fileList) {
|
||||
if (file.exists()) {
|
||||
try {
|
||||
deviceId = file.readText()
|
||||
Utils.log("getDeviceId", "获取成功DataFile$DEVICE_ID")
|
||||
return deviceId
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("getDeviceId", "获取成功SP$DEVICE_ID")
|
||||
}
|
||||
return deviceId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class LunchType {
|
||||
first,
|
||||
update,
|
||||
again
|
||||
}
|
||||
@ -158,41 +158,46 @@ public class DeviceUtils {
|
||||
}
|
||||
|
||||
public static String getNetwork(Context context) {
|
||||
NetworkInfo info = ((ConnectivityManager) context
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
|
||||
ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (connManager == null) return null;
|
||||
NetworkInfo info = connManager.getActiveNetworkInfo();
|
||||
if (info != null && info.isConnected()) {
|
||||
int typeMobile = info.getType();
|
||||
if (typeMobile == ConnectivityManager.TYPE_WIFI) {
|
||||
return "WIFI";
|
||||
} else if (typeMobile == ConnectivityManager.TYPE_MOBILE) {
|
||||
String status;
|
||||
switch (typeMobile) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||
case TelephonyManager.NETWORK_TYPE_IDEN:
|
||||
status = "2G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
status = "3G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
status = "4G";
|
||||
break;
|
||||
default:
|
||||
status = "未知";
|
||||
break;
|
||||
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (telephonyManager != null) {
|
||||
int networkType = telephonyManager.getNetworkType();
|
||||
String status;
|
||||
switch (networkType) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||
case TelephonyManager.NETWORK_TYPE_IDEN:
|
||||
status = "2G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
status = "3G";
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
status = "4G";
|
||||
break;
|
||||
default:
|
||||
status = "未知";
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -345,7 +345,7 @@ public class DialogUtils {
|
||||
, "取消", "前往QQ", new ConfirmListener() {
|
||||
@Override
|
||||
public void onConfirm() {
|
||||
QQUtils.startQQSession(context, qq);
|
||||
DirectUtils.directToQqConversation(context, qq);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
248
app/src/main/java/com/gh/common/util/DirectUtils.kt
Normal file
248
app/src/main/java/com/gh/common/util/DirectUtils.kt
Normal file
@ -0,0 +1,248 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import com.gh.base.fragment.BaseFragment_TabLayout
|
||||
import com.gh.common.util.EntranceUtils.*
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
import com.gh.gamecenter.eventbus.EBReuse
|
||||
import com.gh.gamecenter.eventbus.EBSkip
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.AskFragment
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity
|
||||
import com.gh.gamecenter.subject.refactor.SubjectActivity
|
||||
import com.gh.gamecenter.suggest.SuggestType
|
||||
import com.lightgame.utils.Util_System_ClipboardManager
|
||||
import com.lightgame.utils.Utils
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
/**
|
||||
* 跳转用的方法
|
||||
*/
|
||||
object DirectUtils {
|
||||
|
||||
/**
|
||||
* 跳转到特定页面,根据 [type] 决定跳转页面,[path] 为跳转前的页面名称
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToSpecificPage(context: Context, type: String, link: String, text: String? = "", entrance: String? = null, path: String? = null) {
|
||||
when (type) {
|
||||
EntranceUtils.HOST_ARTICLE -> directToArticle(context, id = link, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_GAME -> directToGameDetail(context, id = link, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_GAME_DOWNLOAD -> directToGameDetail(context, id = link, entrance = entrance, autoDownload = true)
|
||||
|
||||
EntranceUtils.HOST_COLUMN -> directToSubject(context, id = link, subjectName = text, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_QUESTION -> directToQuestionDetail(context, id = link, entrance = entrance, path = path)
|
||||
|
||||
EntranceUtils.HOST_ANSWER -> directToAnswerDetail(context, id = link, entrance = entrance, path = path)
|
||||
|
||||
EntranceUtils.HOST_WEB -> directToWebView(context, url = link, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_DOWNLOAD -> directToDownloadManagerAndStartDownload(context, gameId = link, packageName = text, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_UPDATE -> directToDownloadManagerAndStartUpdate(context, gameId = link, packageName = text, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_LIBAO -> directToGiftDetail(context, giftId = link, entrance = entrance)
|
||||
|
||||
EntranceUtils.HOST_COMMUNITY -> directToCommunity(context, CommunityEntity(link, text!!))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到文章详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToArticle(context: Context, id: String, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, NewsDetailActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_NEWSID, id)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到游戏详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, GameDetailActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
// 专栏
|
||||
@JvmStatic
|
||||
fun directToSubject(context: Context, id: String, subjectName: String? = "", entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
|
||||
bundle.putParcelable(EntranceUtils.KEY_SUBJECT_DATA, SubjectData(id, subjectName, false, null, null, null, null))
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
// 反馈
|
||||
@JvmStatic
|
||||
fun directToFeedback(context: Context, content: String? = null, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, SuggestionActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_CONTENT, content)
|
||||
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN)
|
||||
bundle.putSerializable(EntranceUtils.KEY_SUGGESTTYPE, SuggestType.gameQuestion)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToDownloadManager(context: Context, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到下载管理器并开始下载 [gameId] 和 [packageName] 用于唯一确定一个下载文件
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToDownloadManagerAndStartDownload(context: Context, gameId: String? = "", packageName: String? = "", entrance: String? = null) {
|
||||
DownloadHelper.createABrandNewDownloadTaskQuietly(gameId, packageName) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
|
||||
bundle.putString(KEY_GAMEID, gameId)
|
||||
bundle.putString(KEY_PACKAGENAME, packageName)
|
||||
bundle.putBoolean(KEY_AUTO_DOWNLOAD, true)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToDownloadManagerAndStartUpdate(context: Context, gameId: String? = "", packageName: String? = "", entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
|
||||
bundle.putString(KEY_GAMEID, gameId)
|
||||
bundle.putString(KEY_PACKAGENAME, packageName)
|
||||
bundle.putInt(BaseFragment_TabLayout.PAGE_INDEX, INDEX_UPDATE)
|
||||
bundle.putBoolean(KEY_AUTO_UPDATE, true)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToAnswerDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, AnswerDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_ANSWER_ID, id)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToQuestionDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, QuestionsDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_QUESTIONS_ID, id)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToWebView(context: Context, url: String, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(EntranceUtils.KEY_TO, WebActivity::class.java.simpleName)
|
||||
bundle.putString(EntranceUtils.KEY_URL, url)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
// 个人-系统消息
|
||||
@JvmStatic
|
||||
fun directToOfficialNotification(context: Context, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(EntranceUtils.KEY_TO, MessageKeFuActivity::class.java.simpleName)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
// 跳转 QQ
|
||||
@JvmStatic
|
||||
fun directToQqConversation(context: Context, qqNumber: String? = null) {
|
||||
var qq = qqNumber
|
||||
|
||||
if (TextUtils.isEmpty(qq)) {
|
||||
qq = "2586716223"
|
||||
}
|
||||
if (ShareUtils.isQQClientAvailable(context)) {
|
||||
// 安装了 QQ 直接调用QQ,打开手机QQ进行会话 默认 QQ 号:2586716223
|
||||
val chatType: String
|
||||
if (qq!!.startsWith("400") || qq.startsWith("800")) {
|
||||
chatType = "crm"
|
||||
} else {
|
||||
chatType = "wpa"
|
||||
}
|
||||
val str = "mqqwpa://im/chat?chat_type=$chatType&uin=$qq&version=1&src_type=web"
|
||||
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(str)))
|
||||
} else {
|
||||
// 没有安装QQ 复制账号
|
||||
Util_System_ClipboardManager.setText(context, qq)
|
||||
Utils.toast(context, "已复制 QQ $qq")
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转 QQ 群
|
||||
@JvmStatic
|
||||
fun directToQqGroup(context: Context, groupNumber: String? = null): Boolean {
|
||||
val intent = Intent()
|
||||
intent.data = Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$groupNumber")
|
||||
// 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
// 未安装手Q或安装的版本不支持
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到 礼包详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGiftDetail(context: Context, giftId: String, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(EntranceUtils.KEY_TO, LibaoDetailActivity::class.java.simpleName)
|
||||
bundle.putString(EntranceUtils.KEY_ID, giftId)
|
||||
EntranceUtils.jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到社区页面
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToCommunity(context: Context, community: CommunityEntity?) {
|
||||
if (MainActivity::class.java.name != RunningUtils.getTopActivity(context)) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
context.startActivity(intent)
|
||||
}
|
||||
UserManager.getInstance().setCommunityData(community)
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_GAMEFRAGMENT, 1))
|
||||
EventBus.getDefault().post(EBReuse(AskFragment.EB_RETRY_PAGE))
|
||||
}
|
||||
}
|
||||
51
app/src/main/java/com/gh/common/util/DownloadHelper.kt
Normal file
51
app/src/main/java/com/gh/common/util/DownloadHelper.kt
Normal file
@ -0,0 +1,51 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import retrofit2.HttpException
|
||||
|
||||
/**
|
||||
* 不想写这个类的,但是与其在一个糟糕的类里插入同样的代码,我想独立写一个类相较而已还没那么糟糕
|
||||
*/
|
||||
object DownloadHelper {
|
||||
|
||||
/**
|
||||
* 根据 game_id 和 packageName 悄悄地开启一个下载任务,如果可以的话
|
||||
* @param block 成功添加下载任务后执行的代码块
|
||||
*/
|
||||
fun createABrandNewDownloadTaskQuietly(gameId: String? = "", packageName: String? = "", block: () -> Unit) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api
|
||||
.getGameDigest(gameId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<GameEntity>() {
|
||||
override fun onResponse(response: GameEntity?) {
|
||||
response?.let {
|
||||
if (response.getApk().size > 1) {
|
||||
for (apk in response.getApk()) {
|
||||
if (packageName == apk.packageName) {
|
||||
DownloadManager.createDownload(HaloApp.getInstance().application,
|
||||
apk, response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", null)
|
||||
block.invoke()
|
||||
}
|
||||
}
|
||||
} else if (response.getApk().size == 1) {
|
||||
DownloadManager.createDownload(HaloApp.getInstance().application,
|
||||
response, "", EntranceUtils.ENTRANCE_RECOMMEND, "", null)
|
||||
block.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
e?.printStackTrace()
|
||||
block.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@ -413,9 +413,9 @@ public class DownloadItemUtils {
|
||||
@Nullable ExposureEvent traceEvent) {
|
||||
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
|
||||
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "下载");
|
||||
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
|
||||
|
||||
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, downloadExposureEvent);
|
||||
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
|
||||
@ -435,9 +435,9 @@ public class DownloadItemUtils {
|
||||
String location, @Nullable ExposureEvent traceEvent) {
|
||||
String msg = FileUtils.isCanDownload(context, gameEntity.getApk().get(0).getSize());
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始");
|
||||
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "插件化");
|
||||
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.PLUGIN_DOWNLOAD);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.PLUGIN_DOWNLOAD);
|
||||
|
||||
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, downloadExposureEvent);
|
||||
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
|
||||
@ -475,7 +475,7 @@ public class DownloadItemUtils {
|
||||
//更新
|
||||
private static void update(Context context, GameEntity gameEntity, String entrance, String location, @Nullable ExposureEvent traceEvent) {
|
||||
DataUtils.onGameUpdateEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), "下载开始");
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.INSTANCE.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.UPDATE);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.UPDATE);
|
||||
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, downloadExposureEvent);
|
||||
}
|
||||
|
||||
|
||||
@ -26,21 +26,30 @@ public class EntranceUtils {
|
||||
public static final String KEY_GAMENAME = "gameName";
|
||||
public static final String HOST_ARTICLE = "article";
|
||||
public static final String HOST_GAME = "game";
|
||||
public static final String HOST_GAME_DOWNLOAD = "game_download";
|
||||
public static final String HOST_COLUMN = "column";
|
||||
public static final String HOST_WEB = "web";
|
||||
public static final String HOST_QQ = "qq";
|
||||
public static final String HOST_DOWNLOAD = "download";
|
||||
public static final String HOST_UPDATE = "update";
|
||||
public static final String HOST_LIBAO = "libao";
|
||||
public static final String HOST_COMMUNITY = "community";
|
||||
public static final String HOST_SUGGESTION = "suggestion";
|
||||
public static final String HOST_ANSWER = "answer";
|
||||
public static final String HOST_QUESTION = "question";
|
||||
public static final String KEY_DATA = "data";
|
||||
public static final String KEY_MESSAGE = "message";
|
||||
public static final String KEY_TYPE = "type";
|
||||
public static final String KEY_NAME = "name";
|
||||
public static final String KEY_ENTRANCE = "entrance";
|
||||
public static final String KEY_TARGET = "target";
|
||||
public static final String ENTRANCE_BROWSER = "(浏览器)";
|
||||
public static final String ENTRANCE_WELCOME = "(启动弹窗)";
|
||||
public static final String ENTRANCE_UMENG = "(友盟推送)";
|
||||
public static final String ENTRANCE_MIPUSH = "(小米推送)";
|
||||
public static final String ENTRANCE_DOWNLOAD = "(下载跳转)";
|
||||
public static final String ENTRANCE_RECOMMEND = "(落地页)";
|
||||
public static final String ENTRANCE_BLOCK_RECOMMEND = "(推荐入口)";
|
||||
public static final String KEY_SUGGEST_HINT_TYPE = "suggestHintType";
|
||||
public static final String KEY_PACKAGENAME = "packageName";
|
||||
public static final String KEY_PLATFORM = "platform";
|
||||
@ -70,6 +79,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_MESSAGE_TYPE = "messageType";
|
||||
public static final String KEY_QUESTIONS_SEARCH_KEY = "questionsSearchKey";
|
||||
public static final String KEY_SHOW_ANSWER_COMMENT = "showAnswerComment";
|
||||
public static final String KEY_RECOMMENDS_ANSWER = "isRecommendsAnswer";
|
||||
public static final String KEY_VERSION_UPDATE = "versionUpdate";
|
||||
public static final String KEY_CHECK_QUESTION_CONCERN = "check_question_concern";
|
||||
public static final String KEY_DRAFT_ID = "draft_id";
|
||||
@ -80,9 +90,18 @@ public class EntranceUtils {
|
||||
public static final String KEY_BLOCK_DATA = "blockData";
|
||||
public static final String KEY_ASK_TAG = "askTag";
|
||||
public static final String KEY_ASK_COLUMN_TAG = "askColumnTag";
|
||||
public static final String KEY_COMMUNITY_ID = "community_id";
|
||||
public static final String KEY_COMMUNITY_NAME = "community_name";
|
||||
public static final String KEY_COMMUNITY_DATA = "communityData";
|
||||
public static final String KEY_TRACE_EVENT = "trace_event";
|
||||
public static final String KEY_SUBJECT_DATA = "subjectData";
|
||||
public static final String KEY_SHOW_SELECT_COMMUNITY = "show_select_community";
|
||||
public static final String KEY_USER_ID = "user_id";
|
||||
public static final String KEY_QUESTION_TAG = "question_tag";
|
||||
public static final String KEY_COLUMN_ID = "column_id";
|
||||
public static final String KEY_AUTO_DOWNLOAD = "auto_download";
|
||||
public static final String KEY_AUTO_UPDATE = "auto_update";
|
||||
public static final String KEY_SEARCH_SUGGEST_HINT = "search_suggest_hint";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ class GsonUtils private constructor() {
|
||||
val mGson: Gson = Gson()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): GsonUtils {
|
||||
return Inner.anotherSingle
|
||||
}
|
||||
@ -32,4 +33,13 @@ class GsonUtils private constructor() {
|
||||
fun toJson(any: Any): String {
|
||||
return mGson.toJson(any)
|
||||
}
|
||||
}
|
||||
|
||||
// Use Kotlin Extension to do the same trick.
|
||||
inline fun <reified T : Any> String.fromObject(): T {
|
||||
return GsonUtils.getInstance().mGson.fromJson(this, T::class.java)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> T.toJson(): String {
|
||||
return GsonUtils.getInstance().mGson.toJson(this)
|
||||
}
|
||||
@ -7,7 +7,6 @@ import android.graphics.drawable.ColorDrawable
|
||||
import android.net.Uri
|
||||
import android.support.annotation.DrawableRes
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.text.TextUtils
|
||||
import com.facebook.common.executors.CallerThreadExecutor
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.controller.BaseControllerListener
|
||||
@ -21,32 +20,118 @@ import com.facebook.imagepipeline.request.ImageRequest
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.lightgame.config.CommonDebug
|
||||
import com.lightgame.download.FileUtils
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import rx.Observable
|
||||
import rx.Observer
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
class ImageUtils private constructor() {
|
||||
|
||||
|
||||
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, listener: BaseControllerListener<ImageInfo>) {
|
||||
object ImageUtils {
|
||||
|
||||
private const val PIC_MAX_FILE_SIZE: Long = 10 * 1024 * 1024
|
||||
|
||||
@JvmStatic
|
||||
fun getUploadFileMaxSize(): Long {
|
||||
val uploadLimitSize = Config.getSettings()?.image?.uploadLimitSize
|
||||
if (uploadLimitSize != null) {
|
||||
return uploadLimitSize
|
||||
}
|
||||
return PIC_MAX_FILE_SIZE
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDefaultGifRule(): String? {
|
||||
val gifConfig = Config.getSettings()?.image?.oss?.gif
|
||||
if (gifConfig != null) {
|
||||
return gifConfig
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getWatermarkWidthGifRule(width: Int?): String? {
|
||||
val gifConfig = Config.getSettings()?.image?.oss?.gitThumb
|
||||
val gifWaterMark = Config.getSettings()?.image?.oss?.gifWaterMark
|
||||
if (gifConfig != null && gifWaterMark != null) {
|
||||
return "$gifConfig,w_$width$gifWaterMark"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun getLimitWidthRule(width: Int?): String? {
|
||||
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
|
||||
if (jpegConfig != null) {
|
||||
return "$jpegConfig,w_$width"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addLimitWidth(imageUrl: String?, width: Int?): String? {
|
||||
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
|
||||
if (jpegConfig != null) {
|
||||
return "$imageUrl$jpegConfig,w_$width"
|
||||
}
|
||||
return imageUrl
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addLimitHeight(imageUrl: String, height: Int): String {
|
||||
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
|
||||
if (jpegConfig != null) {
|
||||
return "$imageUrl$jpegConfig,h_$height"
|
||||
}
|
||||
return imageUrl
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addLimitWidthAndHeight(imageUrl: String, width: Int, height: Int): String {
|
||||
val jpegConfig = Config.getSettings()?.image?.oss?.jpeg
|
||||
if (jpegConfig != null) {
|
||||
return "$imageUrl$jpegConfig,w_$width,h_$height"
|
||||
}
|
||||
return imageUrl
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getGitStaticImage(imageUrl: String): String {
|
||||
val gifThumb = Config.getSettings()?.image?.oss?.gitThumb
|
||||
if (gifThumb != null) {
|
||||
return "$imageUrl$gifThumb"
|
||||
}
|
||||
return imageUrl
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun addLimitWidthAndLoad(draweeView: SimpleDraweeView?, imageUrl: String, width: Int) {
|
||||
val newUrl = addLimitWidth(imageUrl, width)
|
||||
draweeView?.setImageURI(newUrl)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addLimitWidthAndLoad(draweeView: SimpleDraweeView?, imageUrl: String?, width: Int?, onLoadListener: OnImageloadListener?) {
|
||||
val newUrl = getTransformLimitUrl(imageUrl, width, draweeView?.context)
|
||||
val listener = object : BaseControllerListener<ImageInfo>() {
|
||||
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
|
||||
onLoadListener?.onLoadFinal(imageInfo)
|
||||
}
|
||||
}
|
||||
|
||||
draweeView?.controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(newUrl)
|
||||
.setControllerListener(listener)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, width: Int?, listener: BaseControllerListener<ImageInfo>) {
|
||||
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(url)
|
||||
.setUri(getTransformLimitUrl(url, width, simpleDraweeView?.context))
|
||||
.setControllerListener(listener)
|
||||
.build()
|
||||
}
|
||||
|
||||
// 自适应图片宽高
|
||||
@JvmStatic
|
||||
fun display(simpleDraweeView: SimpleDraweeView?, url: String?, width: Int) {
|
||||
val listener = object : BaseControllerListener<ImageInfo>() {
|
||||
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
|
||||
@ -60,15 +145,17 @@ class ImageUtils private constructor() {
|
||||
}
|
||||
}
|
||||
simpleDraweeView?.controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(url)
|
||||
.setControllerListener(listener)
|
||||
.setUri(getTransformLimitUrl(url, width, simpleDraweeView?.context))
|
||||
.build()
|
||||
}
|
||||
|
||||
// 自适应图片宽高
|
||||
@JvmStatic
|
||||
fun displayScale(simpleDraweeView: SimpleDraweeView?, url: String?, height: Int) {
|
||||
val listener = object : BaseControllerListener<ImageInfo>() {
|
||||
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
|
||||
|
||||
if (imageInfo == null) {
|
||||
return
|
||||
}
|
||||
@ -85,7 +172,8 @@ class ImageUtils private constructor() {
|
||||
}
|
||||
|
||||
// 设置缩放类型,设置按压状态下的叠加图
|
||||
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?,
|
||||
@JvmStatic
|
||||
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?, width: Int,
|
||||
scaleType: ScalingUtils.ScaleType?, url: String?) {
|
||||
if (simpleDraweeView == null) return
|
||||
val context = simpleDraweeView.context ?: return
|
||||
@ -96,11 +184,11 @@ class ImageUtils private constructor() {
|
||||
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
|
||||
.setActualImageScaleType(scaleType)
|
||||
.build()
|
||||
// simpleDraweeView.setImageURI(url);
|
||||
display(simpleDraweeView, url)
|
||||
simpleDraweeView.setImageURI(getTransformLimitUrl(url, width, context))
|
||||
}
|
||||
|
||||
// 设置占位符
|
||||
@JvmStatic
|
||||
fun display(resources: Resources?, simpleDraweeView: SimpleDraweeView?, url: String?, placeholderImage: Int) {
|
||||
if (simpleDraweeView == null) return
|
||||
val context = simpleDraweeView.context ?: return
|
||||
@ -110,7 +198,6 @@ class ImageUtils private constructor() {
|
||||
.setBackground(ColorDrawable(ContextCompat.getColor(context, R.color.placeholder_bg)))
|
||||
.setPlaceholderImage(placeholderImage)
|
||||
.build()
|
||||
// simpleDraweeView.setImageURI(url);
|
||||
display(simpleDraweeView, url)
|
||||
}
|
||||
|
||||
@ -125,6 +212,7 @@ class ImageUtils private constructor() {
|
||||
}
|
||||
|
||||
// 获取bitmap
|
||||
@JvmStatic
|
||||
fun display(context: Context?, url: String?, dataSubscriber: BaseBitmapDataSubscriber) {
|
||||
val imageRequest = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(url))
|
||||
@ -136,113 +224,68 @@ class ImageUtils private constructor() {
|
||||
.subscribe(dataSubscriber, CallerThreadExecutor.getInstance())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val RESPONSE403: String = "RESPONSE403"
|
||||
|
||||
fun getInstance(): ImageUtils {
|
||||
return Inner.anotherSingle
|
||||
/**
|
||||
* 规则 width>0 Wifi/4G:x2 traffic:x1
|
||||
* 第一种方案:通过LayoutParams获取 可以快速(无延迟)获取宽高,但是无法获取wrap_content和match_parent的View
|
||||
* 第二种方案(备用方案):有延迟,View的宽高需要在Measure过程后才能确定,能够在这里获取到正确的宽高
|
||||
*/
|
||||
@JvmStatic
|
||||
fun display(view: SimpleDraweeView?, url: String?) {
|
||||
val width = view?.layoutParams?.width
|
||||
if (width != null && width > 0) {
|
||||
view.setImageURI(getTransformLimitUrl(url, width, view.context))
|
||||
} else {
|
||||
view?.post {
|
||||
view.setImageURI(getTransformLimitUrl(url, view.width, view.context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object Inner {
|
||||
val anotherSingle = ImageUtils()
|
||||
}
|
||||
|
||||
fun display(simpleDraweeView: SimpleDraweeView, url: String?) {
|
||||
simpleDraweeView.setImageURI(url)
|
||||
}
|
||||
|
||||
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {
|
||||
draweeView.setImageURI("res:///" + res)
|
||||
}
|
||||
|
||||
fun postImageArr(context: Context, imgArr: List<String>, listener: OnPostArrImageListener) {
|
||||
val imgMap: HashMap<String, String> = HashMap()
|
||||
|
||||
Observable.create(Observable.OnSubscribe<JSONObject> { subscriber ->
|
||||
var path: String
|
||||
var index = 0
|
||||
for (s in imgArr) {
|
||||
path = context.getCacheDir().path + File.separator + System.currentTimeMillis() + index + ".jpg"
|
||||
if (BitmapUtils.savePicture(path, s, 1024 * 1024)) {
|
||||
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", path, s, UserManager.getInstance().token))
|
||||
index++
|
||||
} else {
|
||||
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", s, s, UserManager.getInstance().token))
|
||||
}
|
||||
}
|
||||
subscriber.onCompleted()
|
||||
}).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<JSONObject> {
|
||||
override fun onCompleted() {
|
||||
Utils.log("图片上传完成")
|
||||
listener.postSuccess(imgMap)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
Utils.log("图片上传失败" + e.toString())
|
||||
listener.postError()
|
||||
}
|
||||
|
||||
override fun onNext(result: JSONObject?) {
|
||||
if (result != null) {
|
||||
try {
|
||||
val statusCode = result.getInt("statusCode")
|
||||
if (statusCode == HttpURLConnection.HTTP_OK) {
|
||||
imgMap.put(result.getString("realPath"), result.getString("icon"))
|
||||
} else if (statusCode == 403) {
|
||||
imgMap.put(result.getString("realPath"), RESPONSE403)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun postImage(context: Context?, picturePath: String?, listener: OnPostImageListener): Subscription? {
|
||||
if (context == null || TextUtils.isEmpty(picturePath)) return null
|
||||
return Observable.create(Observable.OnSubscribe<JSONObject> { subscriber ->
|
||||
val path = context.getCacheDir().path + File.separator + System.currentTimeMillis() + ".jpg"
|
||||
if (BitmapUtils.savePicture(path, picturePath, 1024 * 1024)) {
|
||||
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", path, UserManager.getInstance().token))
|
||||
// Wifi/4G:x2 traffic:x1
|
||||
private fun getTransformLimitUrl(url: String?, width: Int?, context: Context?): String? {
|
||||
var transformUrl: String? = url
|
||||
if (width != null && width > 0) {
|
||||
val transformUrlX2 = addLimitWidth(url, width * 2)
|
||||
val transformUrlX1 = addLimitWidth(url, width)
|
||||
if (NetworkUtils.isWifiOr4GConnected(context)) {
|
||||
transformUrl = transformUrlX2
|
||||
} else {
|
||||
// 检查X2大图是否被缓存
|
||||
if (Fresco.getImagePipeline().isInBitmapMemoryCache(Uri.parse(transformUrlX2)) ||
|
||||
Fresco.getImagePipeline().isInDiskCacheSync(Uri.parse(transformUrlX2))) {
|
||||
transformUrl = transformUrlX2
|
||||
} else {
|
||||
subscriber.onNext(FileUtils.uploadFile(Config.API_HOST + "images?type=community", picturePath, UserManager.getInstance().token))
|
||||
transformUrl = transformUrlX1
|
||||
}
|
||||
}).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<JSONObject>() {
|
||||
override fun onResponse(response: JSONObject?) {
|
||||
if (CommonDebug.IS_DEBUG) {
|
||||
Utils.log("postImage:onResponse=>" + response.toString())
|
||||
}
|
||||
listener.postSuccess(response)
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
listener.postError()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// Utils.log("displayPost::viewWidth->$width----transformUrl->$transformUrl")
|
||||
return transformUrl
|
||||
}
|
||||
|
||||
// 规则 width>0 Wifi/4G:x2 traffic:x2
|
||||
@JvmStatic
|
||||
fun displayIcon(view: SimpleDraweeView?, url: String?) {
|
||||
val width = view?.layoutParams?.width
|
||||
if (width != null && width > 0) {
|
||||
view.setImageURI(addLimitWidth(url, width * 2))
|
||||
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
|
||||
} else {
|
||||
view?.post {
|
||||
view.setImageURI(addLimitWidth(url, view.width * 2))
|
||||
// Utils.log("displayIcon::viewWidth->" + view.width + "---transformUrl->" + transformUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface OnPostImageListener {
|
||||
fun postSuccess(response: JSONObject?)
|
||||
|
||||
fun postError()
|
||||
@JvmStatic
|
||||
fun display(draweeView: SimpleDraweeView, @DrawableRes res: Int?) {
|
||||
draweeView.setImageURI("res:///" + res)
|
||||
}
|
||||
|
||||
interface OnPostArrImageListener {
|
||||
/**
|
||||
* key: 图片本地路径
|
||||
* value: 图片提交成功后的链接
|
||||
*/
|
||||
fun postSuccess(imgMap: HashMap<String, String>)
|
||||
|
||||
fun postError()
|
||||
public interface OnImageloadListener {
|
||||
fun onLoadFinal(imageInfo: ImageInfo?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -38,11 +38,11 @@ import org.json.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.HttpException;
|
||||
import rx.Observable;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/12/16.
|
||||
@ -398,6 +398,8 @@ public class LibaoUtils {
|
||||
Utils.toast(context, "礼包处理异常" + ex.toString());
|
||||
}
|
||||
return;
|
||||
} else if (exception.code() == 401) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Utils.toast(context, "发生异常");
|
||||
@ -529,6 +531,8 @@ public class LibaoUtils {
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else if (exception.code() == 401) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Utils.toast(context, "发生异常");
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.loghub.LogHubUtils;
|
||||
@ -18,7 +18,59 @@ import org.json.JSONObject;
|
||||
/**
|
||||
* Created by khy on 2/01/18.
|
||||
*/
|
||||
public class AskLogUtils {
|
||||
public class LogUtils {
|
||||
|
||||
public static void uploadDevice(LunchType launchType) {
|
||||
JSONObject object = new JSONObject();
|
||||
Application application = HaloApp.getInstance().getApplication();
|
||||
try {
|
||||
object.put("subject", "halo_device");
|
||||
object.put("launch_time", Utils.getTime(application));
|
||||
object.put("launch_type", launchType.name());
|
||||
object.put("network", DeviceUtils.getNetwork(application));
|
||||
object.put("device_model", android.os.Build.MODEL);
|
||||
object.put("device_system", android.os.Build.VERSION.RELEASE);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
upload(application, object);
|
||||
}
|
||||
|
||||
public static void uploadAnswerReadTime(String tracers, int readTime, String answerId, Questions questions) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("subject", "answer");
|
||||
object.put("community_id", UserManager.getInstance().getCommunity().getId());
|
||||
object.put("community_name", UserManager.getInstance().getCommunity().getName());
|
||||
object.put("question_id", questions.getId());
|
||||
object.put("question_name", questions.getTitle());
|
||||
object.put("tracers", tracers);
|
||||
object.put("answer_id", answerId);
|
||||
object.put("read", readTime);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
upload(HaloApp.getInstance().getApplication(), object);
|
||||
}
|
||||
|
||||
public static void uploadQuestionReadTime(String tracers, int readTime, Questions questions) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("subject", "question");
|
||||
object.put("community_id", UserManager.getInstance().getCommunity().getId());
|
||||
object.put("community_name", UserManager.getInstance().getCommunity().getName());
|
||||
object.put("question_id", questions.getId());
|
||||
object.put("question_name", questions.getTitle());
|
||||
object.put("tracers", tracers);
|
||||
object.put("read", readTime);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
upload(HaloApp.getInstance().getApplication(), object);
|
||||
}
|
||||
|
||||
|
||||
public static void uploadQuestions(Context context, String tracers, Questions questions) {
|
||||
@ -73,16 +125,25 @@ public class AskLogUtils {
|
||||
}
|
||||
|
||||
|
||||
public static void communityRefresh(Context context, int dataCount) {
|
||||
public static void communityRefresh(Context context, int dataCount, boolean manualRefresh) {
|
||||
if (context == null) return;
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("subject", "community_refresh");
|
||||
object.put("community_id", UserManager.getInstance().getCommunity().getId());
|
||||
object.put("refresh_type", "recommend");
|
||||
object.put("refresh_way", manualRefresh ? "manual" : "auto");
|
||||
object.put("data_count", dataCount);
|
||||
object.put("user_id", UserManager.getInstance().getUserId());
|
||||
object.put("network", DeviceUtils.getNetwork(context));
|
||||
object.put("version", PackageUtils.getPatchVersionName());
|
||||
object.put("channel", HaloApp.getInstance().getChannel());
|
||||
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
|
||||
object.put("imei", Util_System_Phone_State.getDeviceId(context));
|
||||
object.put("device_system", android.os.Build.VERSION.RELEASE);
|
||||
object.put("device_model", android.os.Build.MODEL);
|
||||
object.put("time", Utils.getTime(context));
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -108,7 +169,7 @@ public class AskLogUtils {
|
||||
private static void upload(Context context, JSONObject object) {
|
||||
if (context == null) return;
|
||||
try {
|
||||
object.put("version", BuildConfig.PATCH_VERSION_NAME);
|
||||
object.put("version", PackageUtils.getPatchVersionName());
|
||||
object.put("channel", HaloApp.getInstance().getChannel());
|
||||
object.put("android_id", Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID));
|
||||
object.put("imei", Util_System_Phone_State.getDeviceId(context));
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.retrofit.JSONObjectResponse;
|
||||
@ -11,12 +12,12 @@ import com.lightgame.utils.Utils;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.HttpException;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by khy on 7/07/17.
|
||||
@ -25,50 +26,6 @@ import rx.schedulers.Schedulers;
|
||||
// TODO: 1/12/17 逐步整理 删除
|
||||
public class LoginUtils {
|
||||
|
||||
// public static void checkPhoneNum(final Context context, final String phoneName, final onCaptchaCallBackListener listener) { // 老用户登录检查手机是否登录过
|
||||
// RetrofitManager.getInstance(context).getApi()
|
||||
// .checkPhoneNum(phoneName)
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .observeOn(AndroidSchedulers.mainThread())
|
||||
// .subscribe(new Response<ResponseBody>() {
|
||||
// @Override
|
||||
// public void onResponse(ResponseBody response) {
|
||||
// super.onResponse(response);
|
||||
// try {
|
||||
// JSONObject content = new JSONObject(response.string());
|
||||
// String status = content.getString("status");
|
||||
// if ("ok".equals(status)) {
|
||||
// getPhoneCaptcha(context, phoneName, listener);
|
||||
// } else {
|
||||
// DialogUtils.showWarningDialog(context, null, "手机号已存在,请使用未登录过的手机号,以保证数据正常同步到新账号上"
|
||||
// , null, "我知道了", null, null);
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(HttpException e) {
|
||||
// super.onFailure(e);
|
||||
// if (e == null) {
|
||||
// Utils.toast(context, "请检查网络是否可用");
|
||||
// return;
|
||||
// }
|
||||
// try {
|
||||
// ResponseBody responseBody = e.response().errorBody();
|
||||
// String string = responseBody.string();
|
||||
// JSONObject content = new JSONObject(string);
|
||||
// int code = content.getInt("code");
|
||||
// outputErrorHint(context, code);
|
||||
// } catch (Exception e1) {
|
||||
// e1.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// }
|
||||
|
||||
// 获取验证码
|
||||
public static void getPhoneCaptcha(final Context context, String phoneNum, final onCaptchaCallBackListener listener) {
|
||||
JSONObject content = new JSONObject();
|
||||
@ -147,39 +104,54 @@ public class LoginUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean userPostErrorToast(Throwable throwable, Context context, boolean isComment) {
|
||||
if (throwable instanceof HttpException) {
|
||||
HttpException exception = (HttpException) throwable;
|
||||
if (exception.code() == 403) {
|
||||
try {
|
||||
JSONObject errorJson = new JSONObject(exception.response().errorBody().string());
|
||||
int errorCode = errorJson.getInt("code");
|
||||
switch (errorCode) {
|
||||
case 403019:
|
||||
if (isComment) {
|
||||
Utils.toast(context, R.string.comment_failed_userblocked);
|
||||
} else {
|
||||
Utils.toast(context, R.string.comment_failed_userbanned);
|
||||
}
|
||||
break;
|
||||
case 403020:
|
||||
Utils.toast(context, R.string.comment_failed_toofrequent);
|
||||
break;
|
||||
case 403021:
|
||||
Utils.toast(context, R.string.comment_failed_illegal);
|
||||
break;
|
||||
default:
|
||||
Utils.toast(context, R.string.comment_failed_unknown);
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Utils.toast(context, "无法识别错误类型");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static void userPostErrorToast(String errorString, Context context, boolean isQuestion) {
|
||||
if (TextUtils.isEmpty(errorString)) {
|
||||
Utils.toast(context, R.string.post_failure_hint);
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject errorJson = new JSONObject(errorString);
|
||||
int errorCode = errorJson.getInt("code");
|
||||
switch (errorCode) {
|
||||
case 403018:
|
||||
Utils.toast(context, R.string.comment_failed_unable);
|
||||
case 403050:
|
||||
case 403048:
|
||||
case 403049:
|
||||
Utils.toast(context, R.string.comment_failed_userbanned);
|
||||
break;
|
||||
case 403051:
|
||||
Utils.toast(context, R.string.comment_failed_userblocked);
|
||||
break;
|
||||
case 403020:
|
||||
if (isQuestion) {
|
||||
DialogUtils.showAlertDialog(context, "限制提醒"
|
||||
, "提问过于频繁,请先休息一下哦", "知道了"
|
||||
, null, null, null);
|
||||
} else {
|
||||
Utils.toast(context, R.string.comment_failed_toofrequent);
|
||||
}
|
||||
break;
|
||||
case 403021:
|
||||
Utils.toast(context, R.string.comment_failed_illegal);
|
||||
break;
|
||||
case 403045:
|
||||
Utils.toast(context, R.string.deny_edit_question);
|
||||
break;
|
||||
case 403046:
|
||||
Utils.toast(context, R.string.deny_edit_answer);
|
||||
break;
|
||||
case 403047:
|
||||
Utils.toast(context, R.string.deny_vote_answer);
|
||||
break;
|
||||
default:
|
||||
Utils.toast(context, R.string.post_failure_hint);
|
||||
break;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Utils.toast(context, R.string.post_failure_hint);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void captchaErrorHint(Context context, JSONObject content) {
|
||||
|
||||
@ -44,6 +44,14 @@ public class NetworkUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isWifiOr4GConnected(Context context) {
|
||||
String network = DeviceUtils.getNetwork(context);
|
||||
if ("WIFI".equals(network) || "4G".equals(network)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断MOBILE网络是否可用
|
||||
*
|
||||
|
||||
@ -15,9 +15,9 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.ResponseBody;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class NewsUtils {
|
||||
|
||||
@ -156,7 +156,7 @@ public class NewsUtils {
|
||||
} else {
|
||||
textView.setText(String.format(Locale.getDefault(), "%d小时前", hour));
|
||||
}
|
||||
} else if (day >= today - 86400 * 1000 && day < today) {
|
||||
} else if (day >= today - 86400 * 1000 * 100 && day < today) {
|
||||
format.applyPattern("HH:mm");
|
||||
textView.setText("昨天 ");
|
||||
} else {
|
||||
|
||||
19
app/src/main/java/com/gh/common/util/NumberUtils.kt
Normal file
19
app/src/main/java/com/gh/common/util/NumberUtils.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
object NumberUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun transSimpleCount(count: Int): String {
|
||||
val s: String
|
||||
if (count > 10000) {
|
||||
val number = count / 10000f
|
||||
val bd = BigDecimal(number.toDouble())
|
||||
s = bd.setScale(1, BigDecimal.ROUND_DOWN).toString() + "W"
|
||||
} else {
|
||||
s = count.toString()
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.Signature;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@ -44,7 +45,7 @@ public class PackageUtils {
|
||||
for (ApkEntity apkEntity : gameEntity.getApk()) {
|
||||
// 判断是否gh_version是否存在
|
||||
String gh_version = (String) PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_version");
|
||||
if (gh_version != null) {
|
||||
if (gh_version != null && apkEntity.getGhVersion() != null) {
|
||||
gh_version = gh_version.substring(2);
|
||||
if (Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity.getForce()) {
|
||||
GameUpdateEntity updateEntity = new GameUpdateEntity();
|
||||
@ -168,7 +169,9 @@ public class PackageUtils {
|
||||
public static Intent getInstallIntent(Context context, String path) {
|
||||
Uri uri = Uri.fromFile(new File(path));
|
||||
Intent installIntent = new Intent(Intent.ACTION_VIEW);
|
||||
// installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if ("smartisan".equals(Build.MANUFACTURER)) {
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
|
||||
InstallUtils.getInstance(context).addInstall(getPackageNameByPath(context, path));
|
||||
return installIntent;
|
||||
|
||||
@ -30,9 +30,9 @@ import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class PlatformUtils {
|
||||
|
||||
|
||||
@ -11,13 +11,13 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.HttpException;
|
||||
import rx.Observable;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/11/9.
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.lightgame.utils.Util_System_ClipboardManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/3/30.
|
||||
*/
|
||||
public class QQUtils {
|
||||
|
||||
public static void startQQSession(Context context, String qq) {
|
||||
if (TextUtils.isEmpty(qq)) {
|
||||
qq = "2586716223";
|
||||
}
|
||||
if (ShareUtils.isQQClientAvailable(context)) {
|
||||
//安装了QQ会直接调用QQ,打开手机QQ进行会话 QQ号:2586716223
|
||||
String chatType;
|
||||
if (qq.startsWith("400") || qq.startsWith("800")) {
|
||||
chatType = "crm";
|
||||
} else {
|
||||
chatType = "wpa";
|
||||
}
|
||||
String str = "mqqwpa://im/chat?chat_type=" + chatType + "&uin=" + qq + "&version=1&src_type=web";
|
||||
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(str)));
|
||||
} else {
|
||||
//没有安装QQ 复制账号
|
||||
// ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
// cmb.setText(qq);
|
||||
Util_System_ClipboardManager.setText(context, qq);
|
||||
Utils.toast(context, "已复制" + qq);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean joinQQGroup(Context context, String key) {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D" + key));
|
||||
// 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
// 未安装手Q或安装的版本不支持
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -20,10 +20,11 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableEmitter;
|
||||
import io.reactivex.ObservableOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/12/1.
|
||||
@ -32,15 +33,15 @@ public class QRCodeUtils {
|
||||
|
||||
public static void setQRCode(final Context context, final String qrBody, final ImageView mShareQrCodeDv) {
|
||||
Observable
|
||||
.create(new Observable.OnSubscribe<String>() {
|
||||
.create(new ObservableOnSubscribe<String>() {
|
||||
@Override
|
||||
public void call(Subscriber<? super String> subscriber) {
|
||||
public void subscribe(ObservableEmitter<String> emitter) {
|
||||
String filePath = context.getExternalCacheDir().getPath() + "/ShareImg/ShareQRCode.jpg";
|
||||
boolean success = QRCodeUtils.createQRImage(qrBody, 200, 200, filePath, context);
|
||||
if (success) {
|
||||
subscriber.onNext(filePath);
|
||||
emitter.onNext(filePath);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
emitter.onComplete();
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
@ -137,7 +137,7 @@ public class ShareUtils {
|
||||
if (pinfo != null) {
|
||||
for (int i = 0; i < pinfo.size(); i++) {
|
||||
String pn = pinfo.get(i).packageName;
|
||||
if ("com.tencent.mobileqq".equals(pn)) {
|
||||
if ("com.tencent.mobileqq".equals(pn) || "com.tencent.tim".equals(pn)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -282,7 +282,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
private void loadBitMap(final String iconUrl, final WXMediaMessage msg, final SendMessageToWX.Req req) {
|
||||
ImageUtils.Companion.getInstance().display(mContext, iconUrl, new BaseBitmapDataSubscriber() {
|
||||
ImageUtils.display(mContext, iconUrl, new BaseBitmapDataSubscriber() {
|
||||
@Override
|
||||
protected void onNewResultImpl(Bitmap bitmap) {
|
||||
Bitmap compressBp = compressBitmap(bitmap);
|
||||
|
||||
50
app/src/main/java/com/gh/common/util/SharedPreferences.kt
Normal file
50
app/src/main/java/com/gh/common/util/SharedPreferences.kt
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
|
||||
/**
|
||||
* Allows editing of this preference instance with a call to [apply][SharedPreferences.Editor.apply]
|
||||
* or [commit][SharedPreferences.Editor.commit] to persist the changes.
|
||||
* Default behaviour is [apply][SharedPreferences.Editor.apply].
|
||||
* ```
|
||||
* prefs.edit {
|
||||
* putString("key", value)
|
||||
* }
|
||||
* ```
|
||||
* To [commit][SharedPreferences.Editor.commit] changes:
|
||||
* ```
|
||||
* prefs.edit(commit = true) {
|
||||
* putString("key", value)
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@SuppressLint("ApplySharedPref")
|
||||
inline fun SharedPreferences.edit(
|
||||
commit: Boolean = false,
|
||||
action: SharedPreferences.Editor.() -> Unit
|
||||
) {
|
||||
val editor = edit()
|
||||
action(editor)
|
||||
if (commit) {
|
||||
editor.commit()
|
||||
} else {
|
||||
editor.apply()
|
||||
}
|
||||
}
|
||||
57
app/src/main/java/com/gh/common/util/SpUtils.kt
Normal file
57
app/src/main/java/com/gh/common/util/SpUtils.kt
Normal file
@ -0,0 +1,57 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object SPUtils {
|
||||
private var mSp: SharedPreferences? = null
|
||||
|
||||
private val sp: SharedPreferences
|
||||
get() {
|
||||
if (mSp == null) {
|
||||
mSp = HaloApp.getInstance().application.getSharedPreferences("Halo", Context.MODE_PRIVATE)
|
||||
}
|
||||
return mSp!!
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setString(key: String, value: String) {
|
||||
sp.edit().putString(key, value).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getString(key: String): String {
|
||||
return sp.getString(key, "")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getString(key: String, defaultValue: String): String? {
|
||||
return sp.getString(key, defaultValue)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setInt(key: String, value: Int) {
|
||||
sp.edit().putInt(key, value).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getInt(key: String): Int {
|
||||
return sp.getInt(key, 0)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getInt(key: String, defaultValue: Int): Int {
|
||||
return sp.getInt(key, defaultValue)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setBoolean(key: String, value: Boolean) {
|
||||
sp.edit().putBoolean(key, value).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBoolean(key: String): Boolean {
|
||||
return sp.getBoolean(key, false)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/5/2.
|
||||
*/
|
||||
@ -21,4 +24,42 @@ public class StringUtils {
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将两个字符串拼接起来,以 "displayName(description)" 的形式返回
|
||||
*
|
||||
* @param displayName 若传入的 displayName 长度大于 30 截取 30 并补充 "..." PS: 仅使用 displayName 中的纯文本部分
|
||||
* @param description 不需额外处理的入参
|
||||
* @return "display(description)"
|
||||
*/
|
||||
public static String combineTwoString(String displayName, String description) {
|
||||
if (TextUtils.isEmpty(displayName) || TextUtils.isEmpty(description)) return "";
|
||||
|
||||
displayName = Html.fromHtml(displayName).toString();
|
||||
|
||||
displayName = displayName.replace("\n", "");
|
||||
|
||||
if (displayName.length() > 30) {
|
||||
|
||||
displayName = displayName.substring(0, 30) + "...";
|
||||
}
|
||||
|
||||
return displayName + "(" + description + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取字符串部分长度,超出的以 "..." 代替
|
||||
*
|
||||
* @param text 字符串内容
|
||||
* @param maxLength 最大长度
|
||||
* @return 修饰后的字符串
|
||||
*/
|
||||
public static String shrinkStringWithDot(String text, int maxLength) {
|
||||
if (TextUtils.isEmpty(text)) return "";
|
||||
|
||||
if (text.length() > maxLength) {
|
||||
text = text.substring(0, maxLength) + "...";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class TagUtils {
|
||||
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.gamecenter.retrofit.StringResponse;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class TokenUtils {
|
||||
|
||||
// TODO VERSION:3.0 之后不存在deviceId
|
||||
@Deprecated
|
||||
public static synchronized String getDeviceId(Context context) {
|
||||
return Util_System_Phone_State.getDeviceId(context); // 暂时用IMEI代替
|
||||
}
|
||||
|
||||
// 获取服务器时间
|
||||
public static synchronized void getTime(Context context) {
|
||||
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
RetrofitManager.getInstance(context).getApi().getTime()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new StringResponse() {
|
||||
@Override
|
||||
public void onResponse(String response) {
|
||||
if (response.matches("^[0-9]{10}$")) {
|
||||
try {
|
||||
Editor editor = sp.edit();
|
||||
editor.putLong("server_time", Long.parseLong(response));
|
||||
editor.putLong("client_time", System.currentTimeMillis() / 1000);
|
||||
editor.apply();
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
203
app/src/main/java/com/gh/common/util/UploadImageUtils.kt
Normal file
203
app/src/main/java/com/gh/common/util/UploadImageUtils.kt
Normal file
@ -0,0 +1,203 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.FileRequestBody
|
||||
import com.gh.gamecenter.retrofit.RetrofitCallback
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableOnSubscribe
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
|
||||
object UploadImageUtils {
|
||||
|
||||
enum class UploadType {
|
||||
question,
|
||||
answer,
|
||||
suggestion,
|
||||
icon
|
||||
}
|
||||
|
||||
// 不处理图片,只是单纯的上次
|
||||
fun uploadImage(type: UploadType, imgPath: String, listener: OnUploadImageListener): Disposable {
|
||||
return Single.just(imgPath)
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.flatMap {
|
||||
val compressFile = File(imgPath) // compress
|
||||
val requestBody = FileRequestBody<ResponseBody>(compressFile, object : RetrofitCallback<ResponseBody>() {
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
listener.onProgress(total, progress)
|
||||
}
|
||||
})
|
||||
val part = MultipartBody.Part.createFormData("Filedata", getFileName(compressFile), requestBody)
|
||||
|
||||
return@flatMap RetrofitManager.getInstance(HaloApp.getInstance().application).uploadApi.uploadImage(part, type.name)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val string = data.string()
|
||||
if (!string.isNullOrEmpty()) {
|
||||
val url = JSONObject(string).getString("url")
|
||||
if (!url.isNullOrEmpty()) {
|
||||
listener.onSuccess(url)
|
||||
return
|
||||
}
|
||||
}
|
||||
onFailure(IllegalAccessException("HeHe"))
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
listener.onError(exception)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 社区图片上传 后续统一其他
|
||||
fun compressAndUploadImage(type: UploadType, imgPath: String, compressGif: Boolean, listener: OnUploadImageListener): Disposable {
|
||||
return Single.just(imgPath)
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.flatMap {
|
||||
val compressFile = compressImage(it, compressGif) // compress
|
||||
val requestBody = FileRequestBody<ResponseBody>(compressFile, object : RetrofitCallback<ResponseBody>() {
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
listener.onProgress(total, progress)
|
||||
}
|
||||
})
|
||||
val part = MultipartBody.Part.createFormData("Filedata", getFileName(compressFile), requestBody)
|
||||
|
||||
return@flatMap RetrofitManager.getInstance(HaloApp.getInstance().application).uploadApi.uploadImage(part, type.name)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val string = data.string()
|
||||
if (!string.isNullOrEmpty()) {
|
||||
val url = JSONObject(string).getString("url")
|
||||
if (!url.isNullOrEmpty()) {
|
||||
listener.onSuccess(url)
|
||||
return
|
||||
}
|
||||
}
|
||||
onFailure(IllegalAccessException("HeHe"))
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
listener.onError(exception)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun compressAndUploadImageList(type: UploadType, imgs: List<String>, compressGif: Boolean, listener: OnUploadImageListListener) {
|
||||
val postImageList = HashMap<String, String>()
|
||||
|
||||
Observable.create(ObservableOnSubscribe<Map<String, String>> {
|
||||
val compressList = compressImageList(imgs, compressGif)
|
||||
var listTotal = 0L // 总大小
|
||||
var listProgress = 0L // 已上传的大小
|
||||
for (img in compressList) {
|
||||
listTotal += img.length()
|
||||
}
|
||||
for (img in compressList) {
|
||||
val requestBody = FileRequestBody<ResponseBody>(img, object : RetrofitCallback<ResponseBody>() {
|
||||
override fun onProgress(total: Long, progress: Long) {
|
||||
listener.onProgress(listTotal, listProgress + progress)
|
||||
}
|
||||
})
|
||||
val part = MultipartBody.Part.createFormData("Filedata", getFileName(img), requestBody)
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.uploadApi.uploadImage(part, type.name)
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val string = data.string()
|
||||
if (!string.isNullOrEmpty()) {
|
||||
val url = JSONObject(string).getString("url")
|
||||
if (!url.isNullOrEmpty()) {
|
||||
val map = HashMap<String, String>()
|
||||
map[img.path] = url
|
||||
it.onNext(map)
|
||||
return
|
||||
}
|
||||
}
|
||||
onFailure(IllegalAccessException("HeHe"))
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
it.onError(exception)
|
||||
}
|
||||
})
|
||||
listProgress += img.length()
|
||||
}
|
||||
it.onComplete()
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<Map<String, String>> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
if (postImageList.size == 0) {
|
||||
listener.onError()
|
||||
} else {
|
||||
listener.onSuccess(postImageList)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNext(t: Map<String, String>) {
|
||||
postImageList.putAll(t)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 同步调用->避免在主线程调用以免阻塞主线程
|
||||
private fun compressImageList(imgs: List<String>, compressGif: Boolean): List<File> {
|
||||
val compressList: MutableList<File> = ArrayList()
|
||||
for (img in imgs) {
|
||||
compressList.add(CompressImageUtils.compressImageAndSaveToFile(File(img), compressGif))
|
||||
}
|
||||
return compressList
|
||||
}
|
||||
|
||||
// 同步调用->避免在主线程调用以免阻塞主线程
|
||||
private fun compressImage(imgPath: String, compressGif: Boolean): File {
|
||||
return CompressImageUtils.compressImageAndSaveToFile(File(imgPath), compressGif)
|
||||
}
|
||||
|
||||
// 防止GIF图片文件后缀不是GIF,这个FileName只是告诉服务端后缀格式,没有其他用处
|
||||
private fun getFileName(file: File): String {
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(file.absolutePath, options)
|
||||
if (options.outMimeType.contains("gif") && !file.name.toLowerCase().contains(".gif".toLowerCase())) {
|
||||
return System.currentTimeMillis().toString() + ".gif"
|
||||
}
|
||||
return file.name
|
||||
}
|
||||
|
||||
interface OnUploadImageListener {
|
||||
fun onSuccess(imageUrl: String)
|
||||
fun onError(e: Throwable?)
|
||||
fun onProgress(total: Long, progress: Long)
|
||||
}
|
||||
|
||||
interface OnUploadImageListListener {
|
||||
fun onSuccess(imageUrl: Map<String, String>) // key:sourceImage value:compressImage
|
||||
fun onError() // 全部上传失败时回调
|
||||
fun onProgress(total: Long, progress: Long)
|
||||
}
|
||||
}
|
||||
@ -59,7 +59,7 @@ public class Concern_LinearLayout extends LinearLayout {
|
||||
|
||||
public Concern_LinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
height = DisplayUtils.dip2px(context, 150);
|
||||
height = DisplayUtils.dip2px(context, 300);
|
||||
distance = DisplayUtils.dip2px(context, 8);
|
||||
}
|
||||
|
||||
@ -80,4 +80,15 @@ public class Concern_LinearLayout extends LinearLayout {
|
||||
removeCallbacks(show);
|
||||
post(hide);
|
||||
}
|
||||
|
||||
public void hideRecyclerViewNoAnimation() {
|
||||
removeCallbacks(show);
|
||||
removeCallbacks(hide);
|
||||
LayoutParams lparams = new LayoutParams(LayoutParams.MATCH_PARENT, height);
|
||||
lparams.height = 0;
|
||||
concern_rv_recommend.setLayoutParams(lparams);
|
||||
concern_rv_recommend.setVisibility(View.GONE);
|
||||
concern_iv_delete.setImageResource(R.drawable.concern_up);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,15 +2,17 @@ package com.gh.common.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CropImageCustom extends RelativeLayout {
|
||||
|
||||
@ -59,23 +61,26 @@ public class CropImageCustom extends RelativeLayout {
|
||||
}
|
||||
|
||||
public boolean savePicture(String path) {
|
||||
float limitSize = 900;
|
||||
int quality = 90;
|
||||
Bitmap bitmap = mZoomImageView.clip();
|
||||
File file = new File(path);
|
||||
int quality = 80;
|
||||
do {
|
||||
try {
|
||||
BufferedOutputStream bos = new BufferedOutputStream(
|
||||
new FileOutputStream(file));
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
|
||||
bos.flush();
|
||||
bos.close();
|
||||
} catch (IOException e) {
|
||||
file.delete();
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
quality -= 10;
|
||||
} while (file.length() > 81920);
|
||||
|
||||
if (bitmap.getHeight() > limitSize || bitmap.getWidth() > limitSize) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setScale(limitSize / bitmap.getWidth(), limitSize / bitmap.getHeight());
|
||||
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
try {
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
|
||||
bitmap.compress(Bitmap.CompressFormat.WEBP, quality, bos);
|
||||
bos.flush();
|
||||
bos.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -129,17 +129,20 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
mDefaultColor = Color.WHITE;
|
||||
break;
|
||||
}
|
||||
setProgress(0);
|
||||
break;
|
||||
case PLUGIN:
|
||||
case INSTALL_PLUGIN:
|
||||
setProgressDrawable(getResources().getDrawable(mDownloadStyle == DOWNLOAD_RECT_STYLE
|
||||
? R.drawable.detail_download_plugin_install_rect_style : R.drawable.game_item_btn_plugin_style));
|
||||
mDefaultColor = Color.WHITE;
|
||||
setProgress(0);
|
||||
break;
|
||||
case NONE:
|
||||
setProgressDrawable(getResources().getDrawable(mDownloadStyle == DOWNLOAD_RECT_STYLE
|
||||
? R.drawable.detail_download_none_rect_style : R.drawable.news_detail_comment));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.hint);
|
||||
setProgress(0);
|
||||
break;
|
||||
case LAUNCH_OR_OPEN:
|
||||
switch (mDownloadStyle) {
|
||||
@ -156,6 +159,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme);
|
||||
break;
|
||||
}
|
||||
setProgress(0);
|
||||
break;
|
||||
case DOWNLOADING_NORMAL:
|
||||
switch (mDownloadStyle) {
|
||||
|
||||
52
app/src/main/java/com/gh/common/view/EmptyDrawable.java
Normal file
52
app/src/main/java/com/gh/common/view/EmptyDrawable.java
Normal file
@ -0,0 +1,52 @@
|
||||
package com.gh.common.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* 一个空的类 主要是用来回调 onLevelChange(加载进度)的内容
|
||||
*/
|
||||
|
||||
public class EmptyDrawable extends Drawable {
|
||||
private OnLoadingListener mLoadingListener;
|
||||
|
||||
public EmptyDrawable(OnLoadingListener listener) {
|
||||
this.mLoadingListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Default Max:10000
|
||||
@Override
|
||||
protected boolean onLevelChange(int level) {
|
||||
if (mLoadingListener != null) mLoadingListener.onProgress(level);
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface OnLoadingListener {
|
||||
void onProgress(int progress);
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ public class Gh_ViewPager extends ViewPager {
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestory() {
|
||||
public void onDestroy() {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,8 @@ public class GridDivider extends RecyclerView.ItemDecoration {
|
||||
private int mDividerHight = 1;
|
||||
private int mGridCount;
|
||||
|
||||
private boolean mIsFilterLast;
|
||||
|
||||
/*
|
||||
int dividerHight 分割线的线宽
|
||||
int dividerColor 分割线的颜色
|
||||
@ -32,6 +34,15 @@ public class GridDivider extends RecyclerView.ItemDecoration {
|
||||
mColorPaint.setColor(dividerColor);
|
||||
}
|
||||
|
||||
public GridDivider(Context context, int dividerHight, int gridCount, int dividerColor, boolean isFilterLast) {
|
||||
this(context);
|
||||
mDividerHight = dividerHight;
|
||||
mGridCount = gridCount;
|
||||
mColorPaint = new Paint();
|
||||
mColorPaint.setColor(dividerColor);
|
||||
mIsFilterLast = isFilterLast;
|
||||
}
|
||||
|
||||
public GridDivider(Context context) {
|
||||
final TypedArray ta = context.obtainStyledAttributes(ATRRS);
|
||||
this.mDividerDarwable = ta.getDrawable(0);
|
||||
@ -60,6 +71,7 @@ public class GridDivider extends RecyclerView.ItemDecoration {
|
||||
|
||||
final int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if (mIsFilterLast && i == childCount - 1) continue;
|
||||
final View child = parent.getChildAt(i);
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
|
||||
@ -8,13 +8,14 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import com.gh.common.util.AskUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.RichEditorUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
@ -43,6 +44,12 @@ import java.util.Locale;
|
||||
*/
|
||||
|
||||
public class RichEditor extends WebView {
|
||||
// 和 rich_editor.js 同步
|
||||
public static String IMAGE_FLAG_DEFAULT = ",default";
|
||||
public static String IMAGE_FLAG_THUMBNAIL = ",thumbnail";
|
||||
|
||||
private int mDefaultImageWidth;
|
||||
private int mThumbnailImageWidth;
|
||||
|
||||
public enum Type {
|
||||
BOLD,
|
||||
@ -95,6 +102,14 @@ public class RichEditor extends WebView {
|
||||
|
||||
public RichEditor(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, android.R.attr.webViewStyle);
|
||||
|
||||
int widthPixels = getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
|
||||
mThumbnailImageWidth = widthPixels / 3;
|
||||
if (NetworkUtils.isWifiConnected(getContext())) {
|
||||
mDefaultImageWidth = widthPixels * 2;
|
||||
} else {
|
||||
mDefaultImageWidth = widthPixels * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@ -186,30 +201,37 @@ public class RichEditor extends WebView {
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
// 如果是编辑状态就不要用缩略图的方案显示(会出现异常数据)
|
||||
public void setHtml(String contents, boolean isLoadTbImage) {
|
||||
if (contents == null) {
|
||||
contents = "";
|
||||
}
|
||||
// getSettings().setBlockNetworkImage(true); // 先不加载网络图片,因为后面有资源替换操作防止流量无故丢失
|
||||
|
||||
// contents = contents.replace("src=", "class=\"lazy\" data-src=");
|
||||
try {
|
||||
exec("javascript:RE.setHtml('" + URLEncoder.encode(contents, "UTF-8") + "');");
|
||||
|
||||
if (isLoadTbImage && !NetworkUtils.isWifiConnected(getContext())) {
|
||||
exec("javascript:RE.replaceTbImage()");
|
||||
if (isLoadTbImage) {
|
||||
if (!NetworkUtils.isWifiOr4GConnected(getContext())) {
|
||||
exec("javascript:RE.replaceTbImage('" +
|
||||
ImageUtils.getLimitWidthRule(mThumbnailImageWidth) + IMAGE_FLAG_THUMBNAIL + "','" +
|
||||
ImageUtils.getWatermarkWidthGifRule(mThumbnailImageWidth) + IMAGE_FLAG_THUMBNAIL + "');");
|
||||
} else {
|
||||
replaceAllDfImageExcludeGif();
|
||||
}
|
||||
exec("javascript:RE.ImageClickListener()");
|
||||
// exec("javascript:RE.lazyLoad()");
|
||||
}
|
||||
|
||||
exec("javascript:RE.ImageClickListener()");
|
||||
|
||||
callback(contents);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// No handling
|
||||
}
|
||||
mContents = contents;
|
||||
// getSettings().setBlockNetworkImage(false); // 重新加载图片
|
||||
}
|
||||
|
||||
// public void replaceTbImage() {
|
||||
// exec("javascript:RE.replaceTbImage()");
|
||||
// }
|
||||
|
||||
public String getHtml() {
|
||||
return mContents;
|
||||
}
|
||||
@ -287,8 +309,17 @@ public class RichEditor extends WebView {
|
||||
exec("javascript:RE.setInputEnabled(" + inputEnabled + ")");
|
||||
}
|
||||
|
||||
public void replaceAllDfImageExcludeGif() {
|
||||
exec("javascript:RE.replaceAllDfImage('" +
|
||||
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
|
||||
ImageUtils.getWatermarkWidthGifRule(mThumbnailImageWidth) + IMAGE_FLAG_THUMBNAIL + "')");
|
||||
}
|
||||
|
||||
|
||||
public void replaceAllDfImage() {
|
||||
exec("javascript:RE.replaceAllDfImage()");
|
||||
exec("javascript:RE.replaceAllDfImage('" +
|
||||
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
|
||||
ImageUtils.getDefaultGifRule() + IMAGE_FLAG_DEFAULT + "')");
|
||||
}
|
||||
|
||||
public void setFocusByEnd() {
|
||||
@ -296,7 +327,9 @@ public class RichEditor extends WebView {
|
||||
}
|
||||
|
||||
public void replaceDfImageByUrl(String imgUrl) {
|
||||
exec("javascript:RE.replaceDfImageByUrl('" + imgUrl + "');");
|
||||
exec("javascript:RE.replaceDfImageByUrl('" + imgUrl + "','" +
|
||||
ImageUtils.getLimitWidthRule(mDefaultImageWidth) + IMAGE_FLAG_DEFAULT + "','" +
|
||||
ImageUtils.getDefaultGifRule() + IMAGE_FLAG_DEFAULT + "');");
|
||||
}
|
||||
|
||||
public void loadCSS(String cssFile) {
|
||||
@ -312,37 +345,6 @@ public class RichEditor extends WebView {
|
||||
exec("javascript:" + jsCSSImport + "");
|
||||
}
|
||||
|
||||
public void undo() {
|
||||
exec("javascript:RE.undo();");
|
||||
}
|
||||
|
||||
public void redo() {
|
||||
exec("javascript:RE.redo();");
|
||||
}
|
||||
|
||||
public void setBold() {
|
||||
exec("javascript:RE.setBold();");
|
||||
}
|
||||
|
||||
public void setItalic() {
|
||||
exec("javascript:RE.setItalic();");
|
||||
}
|
||||
|
||||
public void setSubscript() {
|
||||
exec("javascript:RE.setSubscript();");
|
||||
}
|
||||
|
||||
public void setSuperscript() {
|
||||
exec("javascript:RE.setSuperscript();");
|
||||
}
|
||||
|
||||
public void setStrikeThrough() {
|
||||
exec("javascript:RE.setStrikeThrough();");
|
||||
}
|
||||
|
||||
public void setUnderline() {
|
||||
exec("javascript:RE.setUnderline();");
|
||||
}
|
||||
|
||||
public void setTextColor(int color) {
|
||||
exec("javascript:RE.prepareInsert();");
|
||||
@ -351,73 +353,14 @@ public class RichEditor extends WebView {
|
||||
exec("javascript:RE.setTextColor('" + hex + "');");
|
||||
}
|
||||
|
||||
public void setTextBackgroundColor(int color) {
|
||||
exec("javascript:RE.prepareInsert();");
|
||||
|
||||
String hex = convertHexColorString(color);
|
||||
exec("javascript:RE.setTextBackgroundColor('" + hex + "');");
|
||||
}
|
||||
|
||||
public void setFontSize(int fontSize) {
|
||||
if (fontSize > 7 || fontSize < 1) {
|
||||
Log.e("RichEditor", "Font size should have a value between 1-7");
|
||||
}
|
||||
exec("javascript:RE.setFontSize('" + fontSize + "');");
|
||||
}
|
||||
|
||||
public void removeFormat() {
|
||||
exec("javascript:RE.removeFormat();");
|
||||
}
|
||||
|
||||
public void setHeading(int heading) {
|
||||
exec("javascript:RE.setHeading('" + heading + "');");
|
||||
}
|
||||
|
||||
public void setIndent() {
|
||||
exec("javascript:RE.setIndent();");
|
||||
}
|
||||
|
||||
public void setOutdent() {
|
||||
exec("javascript:RE.setOutdent();");
|
||||
}
|
||||
|
||||
public void setAlignLeft() {
|
||||
exec("javascript:RE.setJustifyLeft();");
|
||||
}
|
||||
|
||||
public void setAlignCenter() {
|
||||
exec("javascript:RE.setJustifyCenter();");
|
||||
}
|
||||
|
||||
public void setAlignRight() {
|
||||
exec("javascript:RE.setJustifyRight();");
|
||||
}
|
||||
|
||||
public void setBlockquote() {
|
||||
exec("javascript:RE.setBlockquote();");
|
||||
}
|
||||
|
||||
public void setBullets() {
|
||||
exec("javascript:RE.setBullets();");
|
||||
}
|
||||
|
||||
public void setNumbers() {
|
||||
exec("javascript:RE.setNumbers();");
|
||||
}
|
||||
|
||||
public void insertImage(String url) {
|
||||
exec("javascript:RE.prepareInsert();");
|
||||
exec("javascript:RE.insertImage('" + url + "');");
|
||||
}
|
||||
|
||||
public void insertLink(String href, String title) {
|
||||
public void insertHtml(String html) {
|
||||
exec("javascript:RE.prepareInsert();");
|
||||
exec("javascript:RE.insertLink('" + href + "', '" + title + "');");
|
||||
}
|
||||
|
||||
public void insertTodo() {
|
||||
exec("javascript:RE.prepareInsert();");
|
||||
exec("javascript:RE.setTodo('" + RichEditorUtils.getCurrentTime() + "');");
|
||||
exec("javascript:RE.insertHTML('" + html + "');");
|
||||
}
|
||||
|
||||
public void focusEditor() {
|
||||
@ -425,10 +368,6 @@ public class RichEditor extends WebView {
|
||||
exec("javascript:RE.focus();");
|
||||
}
|
||||
|
||||
public void clearFocusEditor() {
|
||||
exec("javascript:RE.blurFocus();");
|
||||
}
|
||||
|
||||
|
||||
public String getText() {
|
||||
return AskUtils.stripHtml(mContents);
|
||||
|
||||
@ -14,7 +14,8 @@ import com.gh.gamecenter.R;
|
||||
public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
|
||||
private Paint paint;
|
||||
private int mInterval = 0;
|
||||
private int mInterval;
|
||||
private int mIntervalLR;
|
||||
private boolean mIsShowIntervalTop;
|
||||
|
||||
public VerticalItemDecoration(Context context, int interval, boolean isShowIntervalTop) {
|
||||
@ -24,6 +25,14 @@ public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
mIsShowIntervalTop = isShowIntervalTop;
|
||||
}
|
||||
|
||||
public VerticalItemDecoration(Context context, int interval, boolean isShowIntervalTop, int intervalLR) {
|
||||
paint = new Paint();
|
||||
paint.setColor(ContextCompat.getColor(context, R.color.background));
|
||||
mInterval = DisplayUtils.dip2px(context, interval);
|
||||
mIsShowIntervalTop = isShowIntervalTop;
|
||||
mIntervalLR = DisplayUtils.dip2px(context, intervalLR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
int left = parent.getPaddingLeft();
|
||||
@ -36,9 +45,9 @@ public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
int bottom = top + mInterval;
|
||||
|
||||
if (i == 0 && mIsShowIntervalTop) {
|
||||
c.drawRect(left, 0, right, bottom, paint);
|
||||
c.drawRect(left + mIntervalLR, 0, right - mIntervalLR, bottom, paint);
|
||||
} else {
|
||||
c.drawRect(left, top, right, bottom, paint);
|
||||
c.drawRect(left + mIntervalLR, top, right - mIntervalLR, bottom, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
116
app/src/main/java/com/gh/common/view/WelcomeDialog.kt
Normal file
116
app/src/main/java/com/gh/common/view/WelcomeDialog.kt
Normal file
@ -0,0 +1,116 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.databinding.DataBindingUtil
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.TimeElapsedHelper
|
||||
import com.gh.common.constant.Constants.SP_LAST_OPENING_ID
|
||||
import com.gh.common.constant.Constants.SP_LAST_OPENING_TIME
|
||||
import com.gh.common.util.DataUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.edit
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogWelcomeBinding
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.WelcomeDialogEntity
|
||||
|
||||
class WelcomeDialog : BaseDialogFragment() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(welcomeEntity: WelcomeDialogEntity?) = WelcomeDialog().apply { mWelcomeEntity = welcomeEntity }
|
||||
}
|
||||
|
||||
private var mWelcomeEntity: WelcomeDialogEntity? = null
|
||||
private var mTimeHelper: TimeElapsedHelper? = null
|
||||
|
||||
private var mDismissByClickImage = false
|
||||
|
||||
lateinit var binding: DialogWelcomeBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mTimeHelper = TimeElapsedHelper(this)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
binding = DataBindingUtil.inflate(inflater, R.layout.dialog_welcome, container, false)
|
||||
binding.ivOpeningCover.setOnClickListener {
|
||||
when (mWelcomeEntity?.type) {
|
||||
EntranceUtils.HOST_ARTICLE -> {
|
||||
DirectUtils.directToArticle(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_GAME -> {
|
||||
DirectUtils.directToGameDetail(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_COLUMN -> {
|
||||
DirectUtils.directToSubject(context!!, mWelcomeEntity?.link!!, null, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_QUESTION -> {
|
||||
DirectUtils.directToQuestionDetail(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
|
||||
}
|
||||
EntranceUtils.HOST_ANSWER -> {
|
||||
DirectUtils.directToAnswerDetail(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
|
||||
}
|
||||
EntranceUtils.HOST_WEB -> {
|
||||
DirectUtils.directToWebView(context!!, mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_QQ -> {
|
||||
DirectUtils.directToQqConversation(context!!, mWelcomeEntity?.link!!)
|
||||
}
|
||||
EntranceUtils.HOST_COMMUNITY -> {
|
||||
DirectUtils.directToCommunity(context!!, CommunityEntity( mWelcomeEntity?.link!!, mWelcomeEntity?.text!!))
|
||||
}
|
||||
}
|
||||
|
||||
mDismissByClickImage = true
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.ivOpeningCover.loadingCallback = object : WrapContentDraweeView.LoadingCallback {
|
||||
override fun loaded() {
|
||||
binding.ivClose.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
binding.ivClose.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
binding.welcome = mWelcomeEntity
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
try {
|
||||
mDismissByClickImage = false
|
||||
super.dismiss()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
val type = if (mDismissByClickImage) {
|
||||
"点击图片"
|
||||
} else {
|
||||
"点击关闭"
|
||||
}
|
||||
|
||||
DataUtils.trackTimeEvent(context, "启动弹窗",
|
||||
mTimeHelper?.elapsedTime!!,
|
||||
type, "No parameter.")
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(context?.applicationContext).edit {
|
||||
putString(SP_LAST_OPENING_ID, mWelcomeEntity?.id)
|
||||
putLong(SP_LAST_OPENING_TIME, mWelcomeEntity?.time!!)
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.net.Uri
|
||||
import android.support.annotation.Nullable
|
||||
import android.util.AttributeSet
|
||||
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder
|
||||
import com.facebook.drawee.controller.BaseControllerListener
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
|
||||
class WrapContentDraweeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : SimpleDraweeView(context, attrs, defStyleAttr) {
|
||||
|
||||
var loadingCallback: LoadingCallback? = null
|
||||
|
||||
// we set a listener and update the view's aspect ratio depending on the loaded image
|
||||
private val listener = object : BaseControllerListener<ImageInfo>() {
|
||||
override fun onIntermediateImageSet(id: String?, @Nullable imageInfo: ImageInfo?) {
|
||||
updateViewSize(imageInfo)
|
||||
loadingCallback?.loaded()
|
||||
}
|
||||
|
||||
override fun onFinalImageSet(id: String?, @Nullable imageInfo: ImageInfo?, @Nullable animatable: Animatable?) {
|
||||
updateViewSize(imageInfo)
|
||||
loadingCallback?.loaded()
|
||||
}
|
||||
|
||||
override fun onFailure(id: String?, throwable: Throwable?) {
|
||||
loadingCallback?.loaded()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setImageURI(uri: Uri?, callerContext: Any?) {
|
||||
val controller = (controllerBuilder as PipelineDraweeControllerBuilder)
|
||||
.setControllerListener(listener)
|
||||
.setCallerContext(callerContext)
|
||||
.setUri(uri)
|
||||
.setOldController(controller)
|
||||
.build()
|
||||
setController(controller)
|
||||
}
|
||||
|
||||
internal fun updateViewSize(@Nullable imageInfo: ImageInfo?) {
|
||||
if (imageInfo != null) {
|
||||
aspectRatio = imageInfo.width.toFloat() / imageInfo.height
|
||||
}
|
||||
}
|
||||
|
||||
interface LoadingCallback {
|
||||
fun loaded()
|
||||
}
|
||||
}
|
||||
@ -1,35 +1,27 @@
|
||||
package com.gh.gamecenter;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.base.fragment.WaitingDialogFragment;
|
||||
import com.gh.common.util.BitmapUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.UploadImageUtils;
|
||||
import com.gh.common.view.CropImageCustom;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
@ -37,13 +29,13 @@ import java.lang.ref.SoftReference;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
import rx.functions.Action1;
|
||||
import rx.functions.Func1;
|
||||
import rx.schedulers.Schedulers;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableOnSubscribe;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
|
||||
public class CropImageActivity extends BaseActivity {
|
||||
|
||||
@ -54,24 +46,23 @@ public class CropImageActivity extends BaseActivity {
|
||||
|
||||
private SharedPreferences sp;
|
||||
|
||||
private UserManager mUserManager;
|
||||
|
||||
private Handler handler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case 0:
|
||||
toast("上传成功");
|
||||
break;
|
||||
case 1:
|
||||
toast("上传失败");
|
||||
break;
|
||||
case 2:
|
||||
toast("修改太频繁,请稍后再试");
|
||||
break;
|
||||
}
|
||||
@Override
|
||||
protected void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case 0:
|
||||
toast("上传成功");
|
||||
break;
|
||||
case 1:
|
||||
toast("上传失败");
|
||||
break;
|
||||
case 2:
|
||||
toast("修改太频繁,请稍后再试");
|
||||
break;
|
||||
case 3:
|
||||
toast("图片违规");
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, String picturePath, String entrance) {
|
||||
@ -89,130 +80,113 @@ public class CropImageActivity extends BaseActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setNavigationTitle(getString(R.string.title_crop_image));
|
||||
setToolbarMenu(R.menu.menu_positive);
|
||||
|
||||
sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
}
|
||||
|
||||
mUserManager = UserManager.getInstance();
|
||||
|
||||
RelativeLayout reuse_actionbar = (RelativeLayout) findViewById(R.id.reuse_actionbar);
|
||||
|
||||
TextView confirm = new TextView(this);
|
||||
confirm.setText("确定");
|
||||
confirm.setTextColor(ContextCompat.getColor(this, R.color.title));
|
||||
confirm.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
|
||||
int padding = DisplayUtils.dip2px(getApplicationContext(), 10);
|
||||
confirm.setPadding(padding, padding, padding, padding);
|
||||
confirm.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final Dialog dialog = DialogUtils.showWaitDialog(CropImageActivity.this, "上传中...");
|
||||
final String path = getCacheDir() + File.separator + System.currentTimeMillis() + ".jpg";
|
||||
Observable.create(new Observable.OnSubscribe<Boolean>() {
|
||||
@Override
|
||||
public void call(Subscriber<? super Boolean> subscriber) {
|
||||
subscriber.onNext(mCropimageCustom.savePicture(path));
|
||||
subscriber.onCompleted();
|
||||
}
|
||||
}).flatMap(new Func1<Boolean, Observable<String>>() {
|
||||
@Override
|
||||
public Observable<String> call(Boolean status) {
|
||||
if (status == null || !status) {
|
||||
dialog.dismiss();
|
||||
handler.sendEmptyMessage(1);
|
||||
return null;
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getItemId() == R.id.layout_menu_positive) {
|
||||
final WaitingDialogFragment postDialog = WaitingDialogFragment.newInstance(getString(R.string.post_img));
|
||||
postDialog.show(getSupportFragmentManager(), null);
|
||||
final String path = getCacheDir() + File.separator + System.currentTimeMillis() + ".jpg";
|
||||
Observable.create((ObservableOnSubscribe<String>) emitter -> {
|
||||
boolean isSuccess = mCropimageCustom.savePicture(path);
|
||||
if (isSuccess) {
|
||||
UploadImageUtils.INSTANCE.uploadImage(UploadImageUtils.UploadType.icon, path, new UploadImageUtils.OnUploadImageListener() {
|
||||
@Override
|
||||
public void onSuccess(@NotNull String imageUrl) {
|
||||
emitter.onNext(imageUrl);
|
||||
emitter.onComplete();
|
||||
}
|
||||
return Observable.just(mUserManager.getToken());
|
||||
}
|
||||
}).flatMap(new Func1<String, Observable<JSONObject>>() {
|
||||
@Override
|
||||
public Observable<JSONObject> call(String token) {
|
||||
if (token != null) {
|
||||
return Observable.just(FileUtils.uploadFile(Config.API_HOST + "images?type=icon", path, token));
|
||||
|
||||
@Override
|
||||
public void onError(@Nullable Throwable e) {
|
||||
if (e != null) {
|
||||
emitter.onError(e);
|
||||
} else {
|
||||
emitter.onError(new IllegalStateException("upload image error"));
|
||||
}
|
||||
}
|
||||
dialog.dismiss();
|
||||
handler.sendEmptyMessage(1);
|
||||
return null;
|
||||
}
|
||||
}).flatMap(new Func1<JSONObject, Observable<JSONObject>>() {
|
||||
@Override
|
||||
public Observable<JSONObject> call(JSONObject result) {
|
||||
if (result != null) {
|
||||
|
||||
@Override
|
||||
public void onProgress(long total, long progress) {
|
||||
int percent = (int) (100 * (progress / (float) total));
|
||||
if (percent >= 100) percent = 99;
|
||||
if (postDialog != null) {
|
||||
postDialog.uploadWaitingHint("图片上传中 " + percent + "%");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}).subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(new Response<String>() {
|
||||
@Override
|
||||
public void onResponse(String url) {
|
||||
try {
|
||||
if (result.getInt("statusCode") == 401) {
|
||||
return Observable.just(FileUtils.uploadFile(Config.API_HOST + "images?type=icon", path,mUserManager.getToken()));
|
||||
if (postDialog != null) postDialog.dismissAllowingStateLoss();
|
||||
mBaseHandler.sendEmptyMessage(0);
|
||||
|
||||
String iconCount = sp.getString("updateIconCount", null);
|
||||
|
||||
long l = System.currentTimeMillis();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.CHINA);
|
||||
String time = format.format(new Date(l));
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", time);
|
||||
|
||||
if (TextUtils.isEmpty(iconCount)) {
|
||||
jsonObject.put("count", 1);
|
||||
} else {
|
||||
JSONObject json = new JSONObject(iconCount);
|
||||
String lastTime = json.getString("time");
|
||||
if (lastTime.equals(time)) {
|
||||
jsonObject.put("count", json.getInt("count") + 1);
|
||||
} else {
|
||||
jsonObject.put("count", 1);
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
||||
sp.edit().putString("updateIconCount", jsonObject.toString()).apply();
|
||||
|
||||
Intent data = new Intent();
|
||||
data.putExtra(EntranceUtils.KEY_URL, url);
|
||||
setResult(RESULT_OK, data);
|
||||
finish();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Observable.just(result);
|
||||
}
|
||||
dialog.dismiss();
|
||||
handler.sendEmptyMessage(1);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(new Action1<JSONObject>() {
|
||||
@Override
|
||||
public void call(JSONObject result) {
|
||||
if (result != null) {
|
||||
try {
|
||||
int statusCode = result.getInt("statusCode");
|
||||
if (statusCode == HttpURLConnection.HTTP_OK) {
|
||||
handler.sendEmptyMessage(0);
|
||||
|
||||
String iconCount = sp.getString("updateIconCount", null);
|
||||
|
||||
long l = System.currentTimeMillis();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
|
||||
String time = format.format(new Date(l));
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", time);
|
||||
|
||||
if (TextUtils.isEmpty(iconCount)) {
|
||||
jsonObject.put("count", 1);
|
||||
} else {
|
||||
JSONObject json = new JSONObject(iconCount);
|
||||
String lastTime = json.getString("time");
|
||||
if (lastTime.equals(time)) {
|
||||
jsonObject.put("count", json.getInt("count") + 1);
|
||||
} else {
|
||||
jsonObject.put("count", 1);
|
||||
}
|
||||
}
|
||||
|
||||
sp.edit().putString("updateIconCount", jsonObject.toString()).apply();
|
||||
|
||||
Intent data = new Intent();
|
||||
data.putExtra(EntranceUtils.KEY_URL, result.getString("url"));
|
||||
setResult(RESULT_OK, data);
|
||||
finish();
|
||||
|
||||
} else if (statusCode == HttpURLConnection.HTTP_FORBIDDEN
|
||||
&& "too frequent".equals(result.getString("detail"))) {
|
||||
handler.sendEmptyMessage(2);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@Override
|
||||
public void onFailure(HttpException e) {
|
||||
if (postDialog != null) postDialog.dismissAllowingStateLoss();
|
||||
try {
|
||||
if (e != null && e.code() == HttpURLConnection.HTTP_FORBIDDEN && e.response().errorBody() != null) {
|
||||
JSONObject object = new JSONObject(e.response().errorBody().string());
|
||||
String detail = object.getString("detail");
|
||||
if ("too frequent".equals(detail)) {
|
||||
mBaseHandler.sendEmptyMessage(2);
|
||||
} else if ("INVALID PICTURE".equals(detail)) {
|
||||
mBaseHandler.sendEmptyMessage(3);
|
||||
} else {
|
||||
mBaseHandler.sendEmptyMessage(1);
|
||||
}
|
||||
} else {
|
||||
handler.sendEmptyMessage(1);
|
||||
mBaseHandler.sendEmptyMessage(1);
|
||||
}
|
||||
dialog.dismiss();
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
mBaseHandler.sendEmptyMessage(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
RelativeLayout.LayoutParams rparams = new RelativeLayout.LayoutParams(
|
||||
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
rparams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
rparams.addRule(RelativeLayout.CENTER_VERTICAL);
|
||||
confirm.setLayoutParams(rparams);
|
||||
reuse_actionbar.addView(confirm);
|
||||
}
|
||||
});
|
||||
}
|
||||
return super.onMenuItemClick(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -221,8 +195,6 @@ public class CropImageActivity extends BaseActivity {
|
||||
if (reference != null && reference.get() != null) {
|
||||
reference.get().recycle();
|
||||
}
|
||||
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -5,6 +5,7 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.DefaultItemAnimator;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
@ -107,8 +108,8 @@ public class InstallActivity extends BaseActivity implements InstallFragmentAdap
|
||||
}
|
||||
});
|
||||
|
||||
mInstallRv.setHasFixedSize(true);
|
||||
mInstallRv.setLayoutManager(new LinearLayoutManager(this));
|
||||
((DefaultItemAnimator) mInstallRv.getItemAnimator()).setSupportsChangeAnimations(false);
|
||||
mAdapter = new InstallFragmentAdapter(this);
|
||||
mInstallRv.addItemDecoration(new VerticalItemDecoration(this, 1, true));
|
||||
mInstallRv.setAdapter(mAdapter);
|
||||
|
||||
@ -20,7 +20,7 @@ import com.gh.common.util.ApkActiveUtils;
|
||||
import com.gh.common.util.DetailDownloadUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.LibaoUtils;
|
||||
import com.gh.common.util.TokenUtils;
|
||||
import com.gh.common.util.DeviceTokenUtils;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.view.VerticalItemDecoration;
|
||||
import com.gh.download.DownloadManager;
|
||||
@ -52,9 +52,9 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
import static com.gh.gamecenter.R.id.reuse_tv_none_data;
|
||||
|
||||
@ -286,7 +286,7 @@ public class LibaoDetailActivity extends BaseActivity implements LibaoDetailAdap
|
||||
}
|
||||
mAdapter.notifyItemChanged(0);
|
||||
|
||||
TokenUtils.getTime(LibaoDetailActivity.this);
|
||||
DeviceTokenUtils.syncServerTime(LibaoDetailActivity.this);
|
||||
handler.sendEmptyMessageDelayed(0, 5000);
|
||||
}
|
||||
}
|
||||
@ -360,6 +360,7 @@ public class LibaoDetailActivity extends BaseActivity implements LibaoDetailAdap
|
||||
public void onResponse(GameEntity response) {
|
||||
ApkActiveUtils.filterHideApk(response);
|
||||
mGameEntity = response;
|
||||
mAdapter.setGameEntity(mGameEntity);
|
||||
|
||||
mDownloadAddWord = mGameEntity.getDownloadAddWord();
|
||||
mDownloadOffText = mGameEntity.getDownloadOffText();
|
||||
|
||||
@ -3,7 +3,6 @@ package com.gh.gamecenter;
|
||||
import android.app.Dialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@ -17,6 +16,7 @@ import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
@ -32,16 +32,20 @@ import com.gh.base.fragment.BaseFragment_ViewPager;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.exposure.meta.MetaUtil;
|
||||
import com.gh.common.im.ImManager;
|
||||
import com.gh.common.util.ClassUtils;
|
||||
import com.gh.common.util.ConcernUtils;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DataLogUtils;
|
||||
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.DirectUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.GameUtils;
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
@ -51,9 +55,11 @@ import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.db.info.GameInfo;
|
||||
import com.gh.gamecenter.db.info.InstallInfo;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.CommunityEntity;
|
||||
import com.gh.gamecenter.entity.GameDigestEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity;
|
||||
import com.gh.gamecenter.entity.InnerMetaInfoEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.eventbus.EBNetworkState;
|
||||
import com.gh.gamecenter.eventbus.EBPackage;
|
||||
@ -72,6 +78,7 @@ import com.gh.gamecenter.normal.NormalFragment;
|
||||
import com.gh.gamecenter.retrofit.ObservableUtil;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.halo.assistant.HaloApp;
|
||||
@ -92,7 +99,10 @@ import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
@ -105,14 +115,13 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.HttpException;
|
||||
import rx.Observable;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.functions.Action1;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TO;
|
||||
import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL;
|
||||
@ -127,6 +136,8 @@ public class MainActivity extends BaseActivity {
|
||||
public final static String EB_MAINACTIVITY_TAG = "MainActivity";
|
||||
public final static String EB_SKIP_GAMEFRAGMENT = "GameFragment";
|
||||
|
||||
public final static String SHOULD_INIT_IM = "should_init_im";
|
||||
|
||||
private MainWrapperFragment mMainWrapperFragment;
|
||||
|
||||
private SharedPreferences sp;
|
||||
@ -135,6 +146,7 @@ public class MainActivity extends BaseActivity {
|
||||
private static final int SKIP_SETTING_REQUEST = 14;
|
||||
private boolean isSkipped;
|
||||
public static boolean isNewFirstLaunch;
|
||||
public static boolean openCommunityWithDefaultIdForTheFirsTime; // 是否根据 META-INFO 里的 JSON 自动选择默认的社区 ID
|
||||
|
||||
Runnable skipRun = new Runnable() {
|
||||
@Override
|
||||
@ -190,11 +202,30 @@ public class MainActivity extends BaseActivity {
|
||||
toast("该链接已失效!请联系管理员。");
|
||||
|
||||
EventBus.getDefault().post(new EBShowDialog("notfound", downloadEntity.getName()));
|
||||
DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "下载失败弹窗",
|
||||
"游戏", downloadEntity.getName(),
|
||||
"平台", downloadEntity.getPlatform(),
|
||||
"光环版本", BuildConfig.VERSION_NAME,
|
||||
"网络状态", DeviceUtils.getNetwork(getApplication()),
|
||||
"IMEI", Util_System_Phone_State.getDeviceId(getApplication()),
|
||||
"机型", Build.MODEL,
|
||||
"厂商", Build.MANUFACTURER,
|
||||
"Android版本", Build.VERSION.RELEASE);
|
||||
return;
|
||||
} else if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|
||||
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())) {
|
||||
toast("网络不稳定,下载任务已暂停");
|
||||
DataLogUtils.uploadNeterrorLog(MainActivity.this, downloadEntity);
|
||||
|
||||
DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "下载自动暂停",
|
||||
"游戏", downloadEntity.getName(),
|
||||
"平台", downloadEntity.getPlatform(),
|
||||
"光环版本", BuildConfig.VERSION_NAME,
|
||||
"网络状态", DeviceUtils.getNetwork(getApplication()),
|
||||
"IMEI", Util_System_Phone_State.getDeviceId(getApplication()),
|
||||
"机型", Build.MODEL,
|
||||
"厂商", Build.MANUFACTURER,
|
||||
"Android版本", Build.VERSION.RELEASE);
|
||||
}
|
||||
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
if (downloadEntity.getName().contains(getString(R.string.app_name))) {
|
||||
@ -249,6 +280,17 @@ public class MainActivity extends BaseActivity {
|
||||
, "网络状态", DeviceUtils.getNetwork(getApplication())
|
||||
, "用户机型", Build.MODEL
|
||||
, "设备IMEI", Util_System_Phone_State.getDeviceId(getApplication()));
|
||||
|
||||
DataUtils.onMtaEvent(
|
||||
getApplication(),
|
||||
"解析包错误_新",
|
||||
"游戏", downloadEntity.getName() + "-" + PlatformUtils.getInstance(getApplicationContext()).getPlatformName(downloadEntity.getPlatform()),
|
||||
"光环版本", BuildConfig.VERSION_NAME,
|
||||
"网络状态", DeviceUtils.getNetwork(getApplication()),
|
||||
"IMEI", Util_System_Phone_State.getDeviceId(getApplication()),
|
||||
"机型", Build.MODEL,
|
||||
"厂商", Build.MANUFACTURER,
|
||||
"Android版本", Build.VERSION.RELEASE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -295,7 +337,6 @@ public class MainActivity extends BaseActivity {
|
||||
DataUtils.onEvent(MainActivity.this, "游戏更新", downloadEntity.getName(), kv1);
|
||||
} else {
|
||||
type = ExposureUtils.DownloadType.DOWNLOAD;
|
||||
DataUtils.onEvent(MainActivity.this, "游戏下载", downloadEntity.getName(), kv1);
|
||||
}
|
||||
|
||||
Map<String, Object> kv2 = new HashMap<>();
|
||||
@ -313,9 +354,16 @@ public class MainActivity extends BaseActivity {
|
||||
kv3.put("位置", downloadEntity.getEntrance());
|
||||
type = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD;
|
||||
DataUtils.onEvent(MainActivity.this, "插件化", downloadEntity.getName(), kv3);
|
||||
|
||||
DataUtils.onMtaEvent(this,
|
||||
"插件化_新",
|
||||
"位置", downloadEntity.getEntrance(),
|
||||
"游戏", downloadEntity.getName() + "-" + downloadEntity.getPlatform(),
|
||||
"操作", "下载完成",
|
||||
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
}
|
||||
|
||||
ExposureUtils.INSTANCE.logADownloadCompleteExposureEvent(new GameEntity(downloadEntity.getGameId()), downloadEntity.getPlatform(), downloadEntity.getExposureTrace(), type);
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(new GameEntity(downloadEntity.getGameId()), downloadEntity.getPlatform(), downloadEntity.getExposureTrace(), type);
|
||||
|
||||
DataCollectionUtils.uploadDownload(this, downloadEntity, "完成");
|
||||
}
|
||||
@ -360,23 +408,12 @@ public class MainActivity extends BaseActivity {
|
||||
msg = "《" + downloadEntity.getName() + "》已下载完但还未安装,是否立即安装?";
|
||||
}
|
||||
final String path = downloadEntity.getPath();
|
||||
DialogUtils.showWarningDialog(this, "提示", msg, "直接退出", "立即安装",
|
||||
new DialogUtils.ConfirmListener() {
|
||||
@Override
|
||||
public void onConfirm() {
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PackageUtils.launchSetup(MainActivity.this, path);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
}, new DialogUtils.CancelListener() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
DialogUtils.showWarningDialog(this,
|
||||
"提示", msg,
|
||||
"直接退出",
|
||||
"立即安装",
|
||||
() -> handler.postDelayed(() -> PackageUtils.launchSetup(MainActivity.this, path), 200),
|
||||
this::finish);
|
||||
return true;
|
||||
}
|
||||
System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
|
||||
@ -443,12 +480,7 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
final CountDownLatch latch = ObservableUtil.latch(localList.size(), new Action1<Object>() {
|
||||
@Override
|
||||
public void call(Object o) {
|
||||
updateInstall();
|
||||
}
|
||||
});
|
||||
final CountDownLatch latch = ObservableUtil.latch(localList.size(), o -> updateInstall(), new Object());
|
||||
|
||||
for (int i = 0, size = localList.size(); i < size; i++) {
|
||||
final String packageName = localList.get(i);
|
||||
@ -501,7 +533,7 @@ public class MainActivity extends BaseActivity {
|
||||
for (String id : concernIdList) {
|
||||
sequences.add(RetrofitManager.getInstance(this).getApi().getGameDigest(id));
|
||||
}
|
||||
Observable.merge(sequences)
|
||||
Observable.mergeDelayError(sequences)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<GameEntity>() {
|
||||
@ -524,7 +556,12 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
public void onFailure(@Nullable HttpException e) {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
update();
|
||||
}
|
||||
});
|
||||
@ -574,12 +611,7 @@ public class MainActivity extends BaseActivity {
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(new Response<ResponseBody>());
|
||||
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DataCollectionUtils.uploadUser(MainActivity.this);
|
||||
}
|
||||
}, 1000);
|
||||
handler.postDelayed(() -> DataCollectionUtils.uploadUser(MainActivity.this), 1000);
|
||||
|
||||
// 检查游戏更新
|
||||
checkGameUpdate();
|
||||
@ -608,7 +640,7 @@ public class MainActivity extends BaseActivity {
|
||||
for (InstallInfo info : mInstallManager.getAllInstall()) {
|
||||
sequences.add(RetrofitManager.getInstance(this).getApi().getGameDigest(info.getId()));
|
||||
}
|
||||
Observable.merge(sequences)
|
||||
Observable.mergeDelayError(sequences)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<GameEntity>() {
|
||||
@ -618,7 +650,12 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
public void onFailure(@Nullable HttpException e) {
|
||||
processPluginData(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
processPluginData(list);
|
||||
}
|
||||
});
|
||||
@ -708,6 +745,7 @@ public class MainActivity extends BaseActivity {
|
||||
UpdateManager.getInstance(this).checkUpdate(true, null);
|
||||
|
||||
if (isNewFirstLaunch) {
|
||||
LogUtils.uploadDevice(DeviceTokenUtils.getLaunchType());
|
||||
getPluginUpdate();
|
||||
sp.edit().putBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(this), false).apply();
|
||||
|
||||
@ -734,7 +772,7 @@ public class MainActivity extends BaseActivity {
|
||||
, "暂不", "马上反馈", new DialogUtils.ConfirmListener() {
|
||||
@Override
|
||||
public void onConfirm() {
|
||||
SuggestionActivity.startSuggestionActivity(MainActivity.this, 3, null, null);
|
||||
SuggestionActivity.startSuggestionActivity(MainActivity.this, SuggestType.crash, null, null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
@ -743,6 +781,12 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
checkRetryDownload();
|
||||
|
||||
// 初始化 IM,只有在 APP 刚启动时执行
|
||||
if (HaloApp.get(SHOULD_INIT_IM, false) != null) {
|
||||
HaloApp.put(SHOULD_INIT_IM, false);
|
||||
handler.postDelayed(ImManager::attachIm, 1000);
|
||||
}
|
||||
|
||||
// 执行跳转事件
|
||||
handler.postDelayed(skipRun, 500);
|
||||
}
|
||||
@ -764,13 +808,6 @@ public class MainActivity extends BaseActivity {
|
||||
GsonUtils.Companion.getInstance().toJson(response.getSuggestion()));
|
||||
edit.apply();
|
||||
|
||||
// // 设置默认社区
|
||||
// if (TextUtils.isEmpty(UserManager.getInstance().getCommunity().getId()) &&
|
||||
// response.getCommunity() != null) {
|
||||
// CommunityEntity community = response.getCommunity();
|
||||
// UserManager.getInstance().setCommunityData(community);
|
||||
// }
|
||||
|
||||
if (!sp.getBoolean("isFixDownload", false) && Config.isShow()) {
|
||||
sp.edit().putBoolean("isFixDownload", true).apply();
|
||||
}
|
||||
@ -848,25 +885,10 @@ public class MainActivity extends BaseActivity {
|
||||
positiveTv.setText("知道了");
|
||||
negativeTv.setText(null);
|
||||
|
||||
negativeTv.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
negativeTv.setOnClickListener(view -> dialog.dismiss());
|
||||
|
||||
positiveTv.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
sp.edit().putString(Config.PATCHES, gson.toJson(tinkerIdMap)).apply();
|
||||
}
|
||||
});
|
||||
positiveTv.setOnClickListener(view -> dialog.dismiss());
|
||||
dialog.setOnDismissListener(dialog1 -> sp.edit().putString(Config.PATCHES, gson.toJson(tinkerIdMap)).apply());
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
@ -944,36 +966,62 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
// 获取META-INF中的plugin_update 文件,判断是否从游戏插件中下载的app,是则获取游戏id,启动游戏更新,下载该游戏
|
||||
private void getPluginUpdate() {
|
||||
ApplicationInfo appinfo = getApplicationInfo();
|
||||
String sourceDir = appinfo.sourceDir;
|
||||
ZipFile zipfile = null;
|
||||
try {
|
||||
zipfile = new ZipFile(sourceDir);
|
||||
Enumeration<?> entries = zipfile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = ((ZipEntry) entries.nextElement());
|
||||
String entryName = entry.getName();
|
||||
if (entryName.contains("gh_assist")) { // TODO: 20/09/17 统一入口
|
||||
String packageName = entryName.substring(entryName.lastIndexOf("_") + 1);
|
||||
Intent intent = new Intent(MainActivity.this, DownloadManagerActivity.class);
|
||||
intent.putExtra("currentItem", 1);
|
||||
intent.putExtra("packageName", packageName);
|
||||
intent.putExtra(EntranceUtils.KEY_ENTRANCE, "(游戏插件)");
|
||||
startActivity(intent);
|
||||
break;
|
||||
HaloApp.getInstance().getMainExecutor().execute(() -> {
|
||||
ApplicationInfo appinfo = getApplicationInfo();
|
||||
String sourceDir = appinfo.sourceDir;
|
||||
ZipFile zipfile = null;
|
||||
|
||||
try {
|
||||
zipfile = new ZipFile(sourceDir);
|
||||
Enumeration<?> entries = zipfile.entries();
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = ((ZipEntry) entries.nextElement());
|
||||
String entryName = entry.getName();
|
||||
if (entryName.contains("gh_assist")) { // TODO: 20/09/17 统一入口
|
||||
String packageName = entryName.substring(entryName.lastIndexOf("_") + 1);
|
||||
Intent intent = new Intent(MainActivity.this, DownloadManagerActivity.class);
|
||||
intent.putExtra("currentItem", 1);
|
||||
intent.putExtra("packageName", packageName);
|
||||
intent.putExtra(EntranceUtils.KEY_ENTRANCE, "(游戏插件)");
|
||||
startActivity(intent);
|
||||
break;
|
||||
} else if (entryName.contains("halo_skip.json")) {
|
||||
InputStream in = zipfile.getInputStream(entry);
|
||||
if (in != null) {
|
||||
final Gson gson = new Gson();
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
InnerMetaInfoEntity info = gson.fromJson(reader, InnerMetaInfoEntity.class);
|
||||
if (info != null) {
|
||||
if (EntranceUtils.HOST_COMMUNITY.equals(info.getType())) {
|
||||
openCommunityWithDefaultIdForTheFirsTime = true;
|
||||
UserManager.getInstance().setCommunityData(new CommunityEntity(info.getLink(), info.getText()));
|
||||
runOnUiThread(() -> mMainWrapperFragment.setCurrentItem(MainWrapperFragment.INDEX_ASK));
|
||||
} else {
|
||||
DirectUtils.directToSpecificPage(this,
|
||||
info.getType(),
|
||||
info.getLink(),
|
||||
info.getText(),
|
||||
EntranceUtils.KEY_PLUGIN,
|
||||
"特定包启动跳转");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (zipfile != null) {
|
||||
try {
|
||||
zipfile.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (zipfile != null) {
|
||||
try {
|
||||
zipfile.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 连接上网络事件
|
||||
@ -1012,6 +1060,13 @@ public class MainActivity extends BaseActivity {
|
||||
Map<String, Object> kv6 = new HashMap<>();
|
||||
kv6.put("安装或卸载", "安装完成");
|
||||
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
|
||||
|
||||
DataUtils.onMtaEvent(this,
|
||||
"插件化_新",
|
||||
"位置", mDownloadEntity.getEntrance(),
|
||||
"游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
|
||||
"操作", "安装完成",
|
||||
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
}
|
||||
DownloadManager.getInstance(getApplicationContext()).cancel(
|
||||
mDownloadEntity.getUrl(), false); // 默认不删除安装包 sp.getBoolean("autodelete", true)
|
||||
@ -1067,6 +1122,13 @@ public class MainActivity extends BaseActivity {
|
||||
kv6.put("安装或卸载", "卸载完成");
|
||||
DataUtils.onEvent(this, "插件化", mDownloadEntity.getName(), kv6);
|
||||
|
||||
DataUtils.onMtaEvent(this,
|
||||
"插件化_新",
|
||||
"位置", mDownloadEntity.getEntrance(),
|
||||
"游戏", mDownloadEntity.getName() + "-" + mDownloadEntity.getPlatform(),
|
||||
"操作", "卸载完成",
|
||||
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
|
||||
startActivity(PackageUtils.getInstallIntent(this, mDownloadEntity.getPath()));
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,11 @@ import com.gh.gamecenter.message.KeFuFragment;
|
||||
|
||||
public class MessageKeFuActivity extends NormalActivity {
|
||||
|
||||
@Override
|
||||
protected Intent provideNormalIntent() {
|
||||
return getTargetIntent(this, MessageKeFuActivity.class, KeFuFragment.class);
|
||||
}
|
||||
|
||||
public static Intent getIntent(Context context) {
|
||||
return getTargetIntent(context, MessageKeFuActivity.class, KeFuFragment.class);
|
||||
}
|
||||
|
||||
@ -22,12 +22,13 @@ import com.gh.common.util.CommentUtils
|
||||
import com.gh.common.util.DeviceUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableOnSubscribe
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotterknife.bindView
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
@ -63,8 +64,7 @@ class NetworkDiagnosisActivity : BaseActivity() {
|
||||
WebView.enableSlowWholeDocumentDraw()
|
||||
}
|
||||
|
||||
Observable
|
||||
.create(Observable.OnSubscribe<ProgressAndDetail> {
|
||||
Observable.create(ObservableOnSubscribe<ProgressAndDetail> {
|
||||
|
||||
var progress = 0
|
||||
|
||||
@ -143,16 +143,16 @@ class NetworkDiagnosisActivity : BaseActivity() {
|
||||
it.onNext(ProgressAndDetail(progress, builder.toString()))
|
||||
}
|
||||
|
||||
it.onCompleted()
|
||||
it.onComplete()
|
||||
}).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<ProgressAndDetail>() {
|
||||
override fun onNext(response: ProgressAndDetail?) {
|
||||
mResult.text = response?.detail
|
||||
setResultProgress(response?.progress ?: 0)
|
||||
override fun onNext(response: ProgressAndDetail) {
|
||||
mResult.text = response.detail
|
||||
setResultProgress(response.progress ?: 0)
|
||||
}
|
||||
|
||||
override fun onCompleted() {
|
||||
override fun onComplete() {
|
||||
initWebView()
|
||||
}
|
||||
})
|
||||
|
||||
@ -58,9 +58,9 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import butterknife.BindView;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
146
app/src/main/java/com/gh/gamecenter/PersonalHomeActivity.kt
Normal file
146
app/src/main/java/com/gh/gamecenter/PersonalHomeActivity.kt
Normal file
@ -0,0 +1,146 @@
|
||||
package com.gh.gamecenter
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.arch.lifecycle.ViewModelProviders
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
import com.gh.common.util.DataUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.baselist.ListActivity
|
||||
import com.gh.gamecenter.baselist.LoadStatus
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.message.MessageUnreadViewModel
|
||||
import com.gh.gamecenter.personalhome.PersonalHomeAdapter
|
||||
import com.gh.gamecenter.personalhome.PersonalHomeViewModel
|
||||
import com.gh.gamecenter.user.UserViewModel
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
/**
|
||||
* 个人主页内部相关的页面不要直接使用 UserManager.getInstance().userId 获取用户ID
|
||||
*/
|
||||
class PersonalHomeActivity : ListActivity<PersonalHistoryEntity, PersonalHomeViewModel>() {
|
||||
|
||||
private var mAdapter: PersonalHomeAdapter? = null
|
||||
private var mUnreadViewModel: MessageUnreadViewModel? = null
|
||||
private var mUserViewModel: UserViewModel? = null
|
||||
|
||||
private var mPath: String? = ""
|
||||
private var mUserId: String? = ""
|
||||
|
||||
override fun provideListAdapter(): PersonalHomeAdapter {
|
||||
if (mAdapter == null) mAdapter = PersonalHomeAdapter(this, mListViewModel)
|
||||
return mAdapter!!
|
||||
}
|
||||
|
||||
override fun provideListViewModel(): PersonalHomeViewModel {
|
||||
val factory = PersonalHomeViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
intent.getStringExtra(EntranceUtils.KEY_USER_ID))
|
||||
return ViewModelProviders.of(this, factory).get(PersonalHomeViewModel::class.java)
|
||||
}
|
||||
|
||||
override fun isAutomaticLoad(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setNavigationTitle("个人主页")
|
||||
|
||||
val factory = MessageUnreadViewModel.Factory(application)
|
||||
mUnreadViewModel = ViewModelProviders.of(this, factory).get(MessageUnreadViewModel::class.java)
|
||||
mUnreadViewModel?.liveData?.observe(this, Observer {
|
||||
mAdapter?.setMessageUnreadData(it)
|
||||
})
|
||||
mListViewModel.personalDataLD.observe(this, Observer {
|
||||
if (mListViewModel.userId == UserManager.getInstance().userId) {
|
||||
val data = mUserViewModel?.loginObsUserinfo?.value?.data
|
||||
it?.icon = data?.icon!!
|
||||
it?.name = data.name!!
|
||||
it?.introduce = data.introduce
|
||||
}
|
||||
mAdapter?.personalData = it
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
})
|
||||
|
||||
val userFactory = UserViewModel.Factory(application)
|
||||
mUserViewModel = ViewModelProviders.of(this, userFactory).get(UserViewModel::class.java)
|
||||
mUserViewModel?.editObsUserinfo?.observe(this, Observer {
|
||||
val data = it?.data
|
||||
if (data != null) {
|
||||
val personalData = mAdapter?.personalData
|
||||
if (personalData != null) {
|
||||
personalData.icon = data.icon!!
|
||||
personalData.name = data.name!!
|
||||
personalData.introduce = data.introduce!!
|
||||
mAdapter?.personalData = personalData
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
val topView = mLayoutManager.findViewByPosition(0)
|
||||
val personalData = mAdapter?.personalData
|
||||
if (personalData != null) {
|
||||
|
||||
if (topView == null || -topView.top > 150) {
|
||||
setNavigationTitle(personalData.name)
|
||||
} else {
|
||||
setNavigationTitle("个人主页")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
trackMtaEvent()
|
||||
}
|
||||
|
||||
private fun trackMtaEvent() {
|
||||
DataUtils.onMtaEvent(this, "个人主页", mPath, mUserId)
|
||||
}
|
||||
|
||||
override fun onLoadRefresh() {
|
||||
mReuseNoConn.visibility = View.GONE
|
||||
mReuseNoData.visibility = View.GONE
|
||||
mListLoading.visibility = View.VISIBLE
|
||||
mListRv.visibility = View.GONE
|
||||
mBaseHandler.postDelayed({ mListViewModel.initData() }, 500)
|
||||
}
|
||||
|
||||
override fun onLoadError() {
|
||||
if (mListViewModel.personalDataLD.value != null) {
|
||||
mAdapter?.loadChange(LoadStatus.LIST_FAILED)
|
||||
super.onLoadDone()
|
||||
} else {
|
||||
super.onLoadError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadEmpty() {
|
||||
if (mListViewModel.personalDataLD.value != null) {
|
||||
mAdapter?.loadChange(LoadStatus.LIST_OVER)
|
||||
super.onLoadDone()
|
||||
} else {
|
||||
super.onLoadEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun startTargetActivity(context: Context, userId: String?, path: String?) {
|
||||
if (!userId.isNullOrEmpty()) {
|
||||
val intent = Intent(context, PersonalHomeActivity::class.java)
|
||||
intent.putExtra(EntranceUtils.KEY_USER_ID, userId)
|
||||
intent.putExtra(EntranceUtils.KEY_PATH, path)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,14 +2,11 @@ package com.gh.gamecenter;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import com.gh.base.GHUmengNotificationClickHandler;
|
||||
import com.gh.base.GHUmengNotificationService;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.umeng.message.UmengNotifyClickActivity;
|
||||
import com.umeng.message.entity.UMessage;
|
||||
|
||||
import org.android.agoo.common.AgooConstants;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Created by khy on 17/11/17.
|
||||
@ -22,20 +19,16 @@ public class PushProxyActivity extends UmengNotifyClickActivity {
|
||||
/**
|
||||
* 相当于代理类
|
||||
* 如果后台进程被杀,消息栏消息触发的事件将由本类处理
|
||||
*
|
||||
* @param intent
|
||||
*/
|
||||
@Override
|
||||
public void onMessage(Intent intent) {
|
||||
super.onMessage(intent); //此方法必须调用,否则无法统计打开数
|
||||
String body = intent.getStringExtra(AgooConstants.MESSAGE_BODY);
|
||||
Utils.log(TAG, body);
|
||||
try {
|
||||
GHUmengNotificationClickHandler handler = new GHUmengNotificationClickHandler();
|
||||
handler.launchApp(this, new UMessage(new JSONObject(body)));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Intent i = new Intent(PushProxyActivity.this, GHUmengNotificationService.class);
|
||||
i.putExtra(AgooConstants.MESSAGE_BODY, body);
|
||||
i.putExtra(GHUmengNotificationService.MESSAGE_FROM_SYSTEM, true);
|
||||
PushProxyActivity.this.startService(i);
|
||||
finishActivity();
|
||||
}
|
||||
|
||||
|
||||
@ -1,22 +1,19 @@
|
||||
package com.gh.gamecenter;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
@ -27,11 +24,15 @@ import com.gh.gamecenter.search.SearchGameDetailFragment;
|
||||
import com.gh.gamecenter.search.SearchGameListFragment;
|
||||
import com.gh.gamecenter.search.SearchHistoryFragment;
|
||||
import com.lightgame.utils.Util_System_Keyboard;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
|
||||
|
||||
public class SearchActivity extends BaseActivity {
|
||||
|
||||
@ -51,13 +52,7 @@ public class SearchActivity extends BaseActivity {
|
||||
private int currentTab;
|
||||
|
||||
private boolean isSearchDetail;
|
||||
|
||||
@Override
|
||||
protected void handleMessage(Message msg) {
|
||||
if (msg.what == 1) {
|
||||
search("auto", searchKey);
|
||||
}
|
||||
}
|
||||
private PublishSubject<String> mPublishSubject;
|
||||
|
||||
@NonNull
|
||||
public static Intent getIntent(Context context, boolean clicked, String hint, String entrance) {
|
||||
@ -81,11 +76,23 @@ public class SearchActivity extends BaseActivity {
|
||||
return R.layout.activity_search;
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
dao = new SearchHistoryDao(this);
|
||||
mPublishSubject = PublishSubject.create();
|
||||
|
||||
mPublishSubject
|
||||
.debounce(300, TimeUnit.MILLISECONDS)
|
||||
.distinctUntilChanged()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(s -> {
|
||||
if (searchInput.getText().length() != 0) {
|
||||
search("auto", s);
|
||||
}
|
||||
});
|
||||
|
||||
boolean isFromHome = getIntent().getBooleanExtra(KEY_CLICKED, false);
|
||||
String hint = getIntent().getStringExtra(EntranceUtils.KEY_HINT);
|
||||
@ -117,34 +124,25 @@ public class SearchActivity extends BaseActivity {
|
||||
|
||||
public void setActionBarLayout() {
|
||||
|
||||
searchInput = (EditText) findViewById(R.id.etSearch);
|
||||
searchInput.setOnEditorActionListener(new OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(SearchActivity.this);
|
||||
search("initiative", null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
searchButton = (TextView) findViewById(R.id.btnSearch);
|
||||
searchCancel = (ImageView) findViewById(R.id.ivDeleteText);
|
||||
|
||||
searchButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
searchInput = findViewById(R.id.etSearch);
|
||||
searchInput.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(SearchActivity.this);
|
||||
search("initiative", null);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
searchButton = findViewById(R.id.btnSearch);
|
||||
searchCancel = findViewById(R.id.ivDeleteText);
|
||||
|
||||
searchButton.setOnClickListener(v -> {
|
||||
Util_System_Keyboard.hideSoftKeyboard(SearchActivity.this);
|
||||
search("initiative", null);
|
||||
});
|
||||
|
||||
searchCancel.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
searchCancel.setVisibility(View.GONE);
|
||||
searchInput.setText("");
|
||||
}
|
||||
searchCancel.setOnClickListener(v -> {
|
||||
searchCancel.setVisibility(View.GONE);
|
||||
searchInput.setText("");
|
||||
});
|
||||
|
||||
searchInput.addTextChangedListener(new TextWatcher() {
|
||||
@ -165,24 +163,15 @@ public class SearchActivity extends BaseActivity {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
String newSearchKey = s.toString().trim();
|
||||
if (!newSearchKey.equals(searchKey)) {
|
||||
mBaseHandler.removeMessages(1);
|
||||
searchKey = newSearchKey;
|
||||
if (searchKey.length() < 1) {
|
||||
setResultPresentModel(0);
|
||||
} else if (!isSearchDetail) {
|
||||
mBaseHandler.sendEmptyMessageDelayed(1, 300);
|
||||
}
|
||||
if (newSearchKey.length() < 1) {
|
||||
setResultPresentModel(0);
|
||||
} else if (!isSearchDetail) {
|
||||
mPublishSubject.onNext(newSearchKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.btnGoBack).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.btnGoBack).setOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
private void search(String type, String key) {
|
||||
|
||||
@ -94,7 +94,7 @@ public class ShareCardActivity extends BaseActivity {
|
||||
mShareGameNameTv.setText(gameName);
|
||||
mShareContentTv.setText(Html.fromHtml(shareContent));
|
||||
// mShareGameIconDv.setImageURI(gameIconUrl);
|
||||
ImageUtils.Companion.display(mShareGameIconDv, gameIconUrl);
|
||||
ImageUtils.display(mShareGameIconDv, gameIconUrl);
|
||||
mShareQrCodeDv.setImageResource(R.drawable.test_qrcode);
|
||||
|
||||
// 延迟操作,等待截图部分绘制完成
|
||||
|
||||
@ -43,7 +43,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
import rx.functions.Action1;
|
||||
import io.reactivex.functions.Consumer;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/11/7.
|
||||
@ -141,9 +141,9 @@ public class ShareCardPicActivity extends BaseActivity {
|
||||
|
||||
mActionbar.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), android.R.color.black));
|
||||
|
||||
latch = ObservableUtil.latch(shareArrImg.size(), new Action1<Object>() {
|
||||
latch = ObservableUtil.latch(shareArrImg.size(), new Consumer<Object>() {
|
||||
@Override
|
||||
public void call(Object o) {
|
||||
public void accept(Object o) {
|
||||
ShareCardPicActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -152,7 +152,7 @@ public class ShareCardPicActivity extends BaseActivity {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, new Object());
|
||||
|
||||
for (int i = 0; i < shareArrImg.size(); i++) {
|
||||
checkUrl(shareArrImg.get(i), shareArrImg.size(), i);
|
||||
@ -161,7 +161,7 @@ public class ShareCardPicActivity extends BaseActivity {
|
||||
mShareGameNameTv.setText(gameName);
|
||||
mShareContentTv.setText(Html.fromHtml(shareContent));
|
||||
// mShareGameIconDv.setImageURI(gameIconUrl);
|
||||
ImageUtils.Companion.display(mShareGameIconDv, gameIconUrl);
|
||||
ImageUtils.display(mShareGameIconDv, gameIconUrl);
|
||||
mShareQrCodeDv.setImageResource(R.drawable.test_qrcode);
|
||||
|
||||
if (shareArrImg.size() > 1) {
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
package com.gh.gamecenter;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.DirectUtils;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity;
|
||||
import com.gh.gamecenter.entity.CommunityEntity;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
@ -17,24 +15,15 @@ import static com.gh.common.util.EntranceUtils.ENTRANCE_BROWSER;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_ANSWER;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_ARTICLE;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COLUMN;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_DOWNLOAD;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_GAME;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_QUESTION;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_SUGGESTION;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ANSWER_ID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_CONTENT;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_GAMEID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_GAME_NAME;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_ID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_NAME;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_NEWSID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_PACKAGENAME;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_PLATFORM;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_PLUGIN;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_QUESTIONS_ID;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_SUGGEST_HINT_TYPE;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TO;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_VERSION;
|
||||
|
||||
/**
|
||||
@ -60,60 +49,46 @@ public class SkipActivity extends BaseActivity {
|
||||
}
|
||||
String host = uri.getHost();
|
||||
String id = uri.getPath();
|
||||
String name = uri.getQueryParameter("name");
|
||||
if (!TextUtils.isEmpty(id)) {
|
||||
id = id.substring(1);
|
||||
}
|
||||
Intent intent = new Intent();
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_ENTRANCE, ENTRANCE_BROWSER);
|
||||
if (host != null) {
|
||||
switch (host) {
|
||||
case HOST_ARTICLE:
|
||||
bundle.putString(KEY_TO, NewsDetailActivity.class.getSimpleName());
|
||||
bundle.putString(KEY_NEWSID, id);
|
||||
DirectUtils.directToArticle(this, id, ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_GAME:
|
||||
bundle.putString(KEY_TO, GameDetailActivity.class.getSimpleName());
|
||||
bundle.putString(KEY_GAMEID, id);
|
||||
DirectUtils.directToGameDetail(this, id, ENTRANCE_BROWSER, false);
|
||||
break;
|
||||
case HOST_COLUMN:
|
||||
bundle.putString(KEY_TO, SubjectActivity.class.getSimpleName());
|
||||
bundle.putString(KEY_ID, id);
|
||||
bundle.putString(KEY_NAME, uri.getQueryParameter(KEY_NAME));
|
||||
DirectUtils.directToSubject(this, id, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_SUGGESTION:
|
||||
String platform = uri.getQueryParameter(KEY_PLATFORM);
|
||||
String platformName = PlatformUtils.getInstance(this).getPlatformName(platform);
|
||||
String content = String.format("【%s-%s-V%s】",
|
||||
uri.getQueryParameter(KEY_GAME_NAME),
|
||||
PlatformUtils.getInstance(this).getPlatformName(uri.getQueryParameter(KEY_PLATFORM)),
|
||||
TextUtils.isEmpty(platformName) ? platform : platformName,
|
||||
uri.getQueryParameter(KEY_VERSION));
|
||||
bundle.putString(KEY_TO, SuggestionActivity.class.getSimpleName());
|
||||
bundle.putString(KEY_CONTENT, content);
|
||||
bundle.putString(KEY_SUGGEST_HINT_TYPE, KEY_PLUGIN);
|
||||
bundle.putInt(EntranceUtils.KEY_SUGGESTTYPE, 4);
|
||||
DirectUtils.directToFeedback(this, content, ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_DOWNLOAD:
|
||||
bundle.putString(KEY_TO, DownloadManagerActivity.TAG);
|
||||
bundle.putString(KEY_GAMEID, id);
|
||||
bundle.putString(KEY_PACKAGENAME, uri.getQueryParameter(KEY_PACKAGENAME));
|
||||
DirectUtils.directToDownloadManagerAndStartUpdate(this, id, uri.getQueryParameter(KEY_PACKAGENAME), ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_ANSWER:
|
||||
bundle.putString(KEY_TO, AnswerDetailActivity.TAG);
|
||||
bundle.putString(KEY_ANSWER_ID, id);
|
||||
bundle.putString(KEY_PACKAGENAME, uri.getQueryParameter(KEY_PACKAGENAME));
|
||||
DirectUtils.directToAnswerDetail(this, id, ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
case HOST_QUESTION:
|
||||
bundle.putString(KEY_TO, QuestionsDetailActivity.TAG);
|
||||
bundle.putString(KEY_QUESTIONS_ID, id);
|
||||
DirectUtils.directToQuestionDetail(this, id, ENTRANCE_BROWSER,"浏览器");
|
||||
break;
|
||||
case HOST_COMMUNITY:
|
||||
DirectUtils.directToCommunity(this, new CommunityEntity(id, name));
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
EntranceUtils.jumpActivity(this, bundle);
|
||||
}
|
||||
finish();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user