Compare commits
483 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3fab1b3f6 | |||
| 5340a41298 | |||
| caf2a379d9 | |||
| c59b79427c | |||
| e54fcca53e | |||
| ad416c6a5d | |||
| 4a65c1a5c8 | |||
| 878529f646 | |||
| d01bc1e2d1 | |||
| d63f5f5ab2 | |||
| ad0fb7a55a | |||
| b0258eef77 | |||
| 86d4df8ad9 | |||
| bb11d984f9 | |||
| d3f3d2ca98 | |||
| 0c1e712c79 | |||
| e193a40651 | |||
| 03f36476cb | |||
| a721637be3 | |||
| 722fb1ad64 | |||
| 52a05c3aa4 | |||
| bcbdac6afc | |||
| a9507af3f4 | |||
| 68601ca8be | |||
| a7adc27896 | |||
| d19d0eb571 | |||
| d8e365fe08 | |||
| b34f61ce0d | |||
| 1f24d16f95 | |||
| 738074ec00 | |||
| c8eee33475 | |||
| badf9f9c20 | |||
| 0398cc4ffc | |||
| b88abf6b9a | |||
| a0d193bc52 | |||
| 6ac635f8c6 | |||
| 30c7d71114 | |||
| 0223b3ab22 | |||
| c9663662d5 | |||
| 12bed97638 | |||
| a857af970d | |||
| 7da621583f | |||
| 46a32b62c2 | |||
| 45bcc95e7d | |||
| 7d7bcfaa1d | |||
| 3a9a561c77 | |||
| e8d344256a | |||
| 1a7c1119bf | |||
| 0b6a2503aa | |||
| 459b9f65a9 | |||
| 6c1ebe531e | |||
| 604450292b | |||
| e42361e84a | |||
| a974652f7f | |||
| 309ab54e90 | |||
| 486d680c26 | |||
| 61a5f3a275 | |||
| c865417a4b | |||
| b142feaaae | |||
| 7380854133 | |||
| 8a0f185eda | |||
| bd9604a53e | |||
| 1aeab51f94 | |||
| b16a6fedc6 | |||
| b97c381ed4 | |||
| acb8c723a3 | |||
| 4492307e23 | |||
| e31224b332 | |||
| 6933d6c590 | |||
| 3d58841ce5 | |||
| 0654b0a25f | |||
| 44dde3f91b | |||
| abad30595f | |||
| c4df411560 | |||
| 2974fa4562 | |||
| b086b1cb0c | |||
| 22cf026335 | |||
| 90bd53fe61 | |||
| 9c580a356e | |||
| 7198c28e6f | |||
| 7bf074fddc | |||
| bea1a336e9 | |||
| 97a9e03192 | |||
| 244d57b6bc | |||
| 3cbd484147 | |||
| 8b81819c30 | |||
| 1873ac5d4e | |||
| cf70c1e7fe | |||
| 6f6b26ea4d | |||
| e2708d9078 | |||
| fb5a40c6e4 | |||
| e2a10c1410 | |||
| 5461d3d548 | |||
| c47365e626 | |||
| 3476f8df3a | |||
| f812c1e5c8 | |||
| 391f196005 | |||
| 097dbca26e | |||
| a147118381 | |||
| e6bdde8273 | |||
| 747757faa7 | |||
| 6f21b9d0ae | |||
| e505554aac | |||
| 3323cce890 | |||
| ffd468db1e | |||
| e98e0d1522 | |||
| 13a4f2014c | |||
| 8cbfe6450a | |||
| bcc866888e | |||
| 60911d5dcb | |||
| 7e77d5749e | |||
| 6c3be5627d | |||
| f6a9585700 | |||
| 06fddb7dcd | |||
| 3a3f9a625b | |||
| 3702b104fc | |||
| 3e023089a1 | |||
| 7455674f6b | |||
| c93c0f2fc6 | |||
| 727f02e571 | |||
| 784fae1f5d | |||
| 42ef075912 | |||
| 15307c5223 | |||
| aad3b48883 | |||
| d65d8f1c4c | |||
| c581496975 | |||
| d5481a8888 | |||
| e0a61278fc | |||
| 2c36283833 | |||
| 1b5a8f3a7e | |||
| 95c918b4e3 | |||
| f32cc1673c | |||
| f0fc2f06da | |||
| b6c6abaa5b | |||
| 6ed67c911c | |||
| 1eda223a1e | |||
| 316c0c28ab | |||
| 895d4d5cf1 | |||
| 877df95e02 | |||
| 801f0b95e7 | |||
| 9019f555b5 | |||
| 106b03a316 | |||
| d8faa554be | |||
| 93080a74a7 | |||
| 3ea2ede0cb | |||
| 1242848b6f | |||
| 24d44a2c90 | |||
| 971779a529 | |||
| 14f561c237 | |||
| 3a38e746f6 | |||
| dd3bc9d39d | |||
| 39a8062aef | |||
| 55b6ccb760 | |||
| a8a55eb9bd | |||
| 3eb73439aa | |||
| 466e118579 | |||
| b38032074b | |||
| 9ee771e528 | |||
| 9253ed47e6 | |||
| bc82263286 | |||
| 11979240ab | |||
| 255e6182a9 | |||
| f170abb7ea | |||
| eb80deb413 | |||
| 10ba5a9ba5 | |||
| 94c49cba8b | |||
| 354dca8b04 | |||
| 034488ff34 | |||
| 59c70e23dd | |||
| 7d98a842f1 | |||
| 5f8006dc5a | |||
| 239bd69580 | |||
| bc96f102a1 | |||
| e2ef3f4d01 | |||
| 5c20bbf5e4 | |||
| b07edd256a | |||
| 1478d37889 | |||
| 7151b56de3 | |||
| 220fd9528b | |||
| 1c26c35571 | |||
| 78eb6b7b02 | |||
| 9dc9add896 | |||
| 2d09f8c008 | |||
| 166e1e77ec | |||
| ea782d002b | |||
| f525a3c46d | |||
| bef6cbb212 | |||
| 5e0af8654a | |||
| 032a89e0cd | |||
| c9afb6df02 | |||
| b8092447ff | |||
| bff20bea49 | |||
| 87f2d9c85f | |||
| 154dfc8538 | |||
| 59c4176983 | |||
| fddcdfb3aa | |||
| cdbf7d39a5 | |||
| 6a55821d4d | |||
| a305db7b13 | |||
| 58b1cd4b12 | |||
| 5e7559e43f | |||
| 2a74e35388 | |||
| 5b9bef79da | |||
| e89750c364 | |||
| 9da6cbf097 | |||
| f83f719283 | |||
| 4a1c81ffb4 | |||
| be26f5168b | |||
| 4e6c75995c | |||
| df693ce0c2 | |||
| f0236d7ad5 | |||
| 1d3e2b5c16 | |||
| 545d257135 | |||
| f5164d2102 | |||
| 9af83be9a7 | |||
| 49b0b982f5 | |||
| ad7543e7bc | |||
| 1bd0db013b | |||
| ef6a2c58ff | |||
| 2aa41661a2 | |||
| e63a374da1 | |||
| e326f072d2 | |||
| f53cc18ab6 | |||
| 723a504d7c | |||
| dab48607e8 | |||
| 3ee69146bb | |||
| ca86a66b14 | |||
| c92bdd3014 | |||
| 0be23f26f2 | |||
| 6ce4592e5e | |||
| 92caedb011 | |||
| f796411fa8 | |||
| d45f185f77 | |||
| 6564de8a72 | |||
| 10028dfebc | |||
| fa06795cef | |||
| c1eb324d79 | |||
| cdf9528583 | |||
| 5f5a621bd1 | |||
| b8d54dfa59 | |||
| b4f39d09e4 | |||
| d57ac57f43 | |||
| a3aea6259c | |||
| 73e4c90956 | |||
| c1432159f3 | |||
| 45f47d98ba | |||
| 2e9638b8c5 | |||
| 7ea30c1d0e | |||
| 034e04944a | |||
| 99326596d5 | |||
| 1cc2b85816 | |||
| 942291d7c5 | |||
| f4cd9419a4 | |||
| a24b9d92c7 | |||
| 8e7e83ad72 | |||
| cd810f0048 | |||
| fa050039cd | |||
| 935fb1149f | |||
| 951817455a | |||
| de597bdd36 | |||
| e71e7f6163 | |||
| 09be5e157d | |||
| 1f5e59fc1d | |||
| e58861afa4 | |||
| 44e51ecb0a | |||
| 794c17a1bb | |||
| 1b287962f0 | |||
| 8bdf98b9d8 | |||
| e1aeb61c9b | |||
| a39a70ac2d | |||
| 4fdcaaf591 | |||
| b4502638ff | |||
| 05502d56b1 | |||
| 90e1e8a40f | |||
| b10293da50 | |||
| 83cf0687e6 | |||
| f56b03716a | |||
| 61a41e6039 | |||
| 20ae9fe0ec | |||
| 74fdec9d72 | |||
| 3437265cc1 | |||
| 271993a876 | |||
| 3a8b7bb920 | |||
| fd85f3889d | |||
| 556ecea749 | |||
| 8a97844676 | |||
| f152296e7a | |||
| 4ccc789c7c | |||
| 747b02eb7a | |||
| a73c033c03 | |||
| 939db8c820 | |||
| 8601440d97 | |||
| 7a1fa90175 | |||
| 46722ba69d | |||
| 70d9d461bf | |||
| 91944df6a4 | |||
| ef86c1158c | |||
| 0f3b6ed34b | |||
| 8b50620ddc | |||
| 8b2a9eb6ca | |||
| 7297f5480e | |||
| 3bee8cc034 | |||
| 584a16e111 | |||
| 6460c7f8d6 | |||
| feb99c9f78 | |||
| 68ac809bcb | |||
| de207f66d9 | |||
| 054fcd2049 | |||
| 497fc998fe | |||
| 03f76453ab | |||
| 0a87bd354a | |||
| 1baceaef15 | |||
| 9719a7fa28 | |||
| 1718a66126 | |||
| b317ef3a39 | |||
| 8b0cd69ae6 | |||
| c7126e9836 | |||
| f3d01335a4 | |||
| 88e029b129 | |||
| 2bc72328c1 | |||
| 81179b1f72 | |||
| 9a7d4997c2 | |||
| 3b6ac881c2 | |||
| 6b5fb7d8bc | |||
| 1551b0a358 | |||
| 6540af8386 | |||
| 9badcdc382 | |||
| 0ba94fa56f | |||
| 52c1343ade | |||
| 7a0e633b79 | |||
| 9b68b05d7d | |||
| 9e7f6b0854 | |||
| cf20ad6fc2 | |||
| cb7bdba338 | |||
| f1fc06ca84 | |||
| 18f9fe7fcf | |||
| 18816a8a4e | |||
| 8d379501cb | |||
| 8f4c6abfd3 | |||
| a24d0a9618 | |||
| 8cdd66cd89 | |||
| 3fd34576e8 | |||
| 78d5cbcc42 | |||
| 803f2bef75 | |||
| 40c7e8f9e6 | |||
| b3c5ca6112 | |||
| 31067ea66d | |||
| 4e7626ff41 | |||
| e62822505e | |||
| cbc705d1eb | |||
| aa2e147a51 | |||
| 6249726839 | |||
| 8f4bc5a164 | |||
| eee459d08a | |||
| 81b4e40dbf | |||
| 261068e286 | |||
| 84364a7c66 | |||
| 3beb47a8be | |||
| ca76af4474 | |||
| bc33673533 | |||
| c5d038a173 | |||
| b1e492df1b | |||
| 9d9c213af7 | |||
| d3f97ea527 | |||
| 0a5fb4cb1d | |||
| 6905f7191a | |||
| bad7fb4922 | |||
| 250fa7eb7b | |||
| f0cd8567cb | |||
| f6dd35e4b8 | |||
| 2dc299e7f4 | |||
| 366e8ded14 | |||
| 8175742143 | |||
| fc858f1272 | |||
| 84b668714b | |||
| 5ea5346ee8 | |||
| c2eb0b267c | |||
| 7fb502e87e | |||
| 98726ddc3a | |||
| 75ff76acf4 | |||
| ba552812a3 | |||
| 83bfeb0abc | |||
| 70f1b7a678 | |||
| 455d53fee0 | |||
| 39e4b5bf55 | |||
| 40a729b6f8 | |||
| 9643176e06 | |||
| 1a70c33bef | |||
| 888ebe5f54 | |||
| cb02dbae57 | |||
| 2683d02dcd | |||
| ceb924e8f1 | |||
| bd91609a80 | |||
| 2fd74a4698 | |||
| e9e0d3b43e | |||
| 17e09ddad3 | |||
| 65427c55d6 | |||
| e1fc23a1bb | |||
| 2d551a3f73 | |||
| 7f99f75c6f | |||
| 548aea8d13 | |||
| a177137744 | |||
| 3c6443d78f | |||
| ba81ed9cb0 | |||
| 6a1cbd10c6 | |||
| 9b205366f7 | |||
| 7e9ac0c4f1 | |||
| fe889639b3 | |||
| 848e43af28 | |||
| c7a3893fae | |||
| f7d633188c | |||
| e1e7d2d3d6 | |||
| 2b8a280768 | |||
| 6efe96eb0d | |||
| 3562fe9273 | |||
| 739ef44a8b | |||
| 879b42dbf2 | |||
| fae626bb98 | |||
| cebd639d78 | |||
| 17a99a1cda | |||
| 2a03683e1e | |||
| a579b3fe10 | |||
| 9c75dd18df | |||
| cdc9c86852 | |||
| fab1851436 | |||
| a6704e46a9 | |||
| e188f70eb6 | |||
| 02dd115886 | |||
| 5cbfc7b461 | |||
| b4742b5645 | |||
| 5ec25475ea | |||
| c58040ef83 | |||
| 75701b6875 | |||
| 2155a33689 | |||
| 68a9d5d771 | |||
| ebf6107faf | |||
| e4bc36a743 | |||
| 7a64251811 | |||
| 65409d75a7 | |||
| d40081d58b | |||
| f276e981ed | |||
| e50db66b47 | |||
| fc84022852 | |||
| b593f2f3ea | |||
| e782d0542c | |||
| 1a085cad98 | |||
| 1c33a0c4c5 | |||
| 3c4a7961c2 | |||
| 712f9b84cf | |||
| 2efb7b76cc | |||
| 5c4d93ce15 | |||
| 7addd92058 | |||
| 82c5898b9a | |||
| cced6b7035 | |||
| ae0b5b3738 | |||
| 6fdf9cbe5d | |||
| 009244c65d | |||
| 73a720bb9c | |||
| fd9df9904f | |||
| e75fb3a40d | |||
| 0bef1a2aa8 | |||
| 395eb641e5 | |||
| 9019242ffb | |||
| 9433bb72ca | |||
| 500f751152 | |||
| 9ebe3f4a0e | |||
| 8c92fc9a42 | |||
| 2a7cb34218 | |||
| e1a42b49c1 | |||
| 5a825debf5 | |||
| e46b0a42b0 | |||
| eb0c442a5e | |||
| eb6460236b | |||
| ef051daffd | |||
| b6acb302d2 | |||
| 5cfc5a3971 | |||
| 04de97af16 | |||
| 6367f90589 | |||
| bc8f9d07bb | |||
| e205abd120 | |||
| 5da8fccef7 | |||
| c7e78142ee | |||
| 354c7d1f85 |
@ -42,7 +42,7 @@ android {
|
||||
}
|
||||
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
abiFilters "armeabi-v7a"
|
||||
}
|
||||
|
||||
// 由于app只针对中文用户,所以仅保留zh资源,其他删掉
|
||||
@ -68,6 +68,13 @@ android {
|
||||
buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\""
|
||||
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
|
||||
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
|
||||
|
||||
resValue "string", "huawei_push_appid", "appid=${HUAWEI_PUSH_APPID}"
|
||||
|
||||
/**
|
||||
* Build Time 供区分 jenkins 打包时间用
|
||||
*/
|
||||
@ -95,7 +102,7 @@ android {
|
||||
signingConfig signingConfigs.debug
|
||||
|
||||
buildConfigField "String", "EXPOSURE_REPO", "\"test\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E3\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E4\""
|
||||
|
||||
multiDexKeepProguard file("tinker_multidexkeep.pro")
|
||||
}
|
||||
@ -107,7 +114,7 @@ android {
|
||||
signingConfig signingConfigs.release
|
||||
|
||||
buildConfigField "String", "EXPOSURE_REPO", "\"exposure\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E3\""
|
||||
buildConfigField "String", "EXPOSURE_VERSION", "\"E4\""
|
||||
|
||||
multiDexKeepProguard file("tinker_multidexkeep.pro")
|
||||
}
|
||||
@ -124,13 +131,10 @@ android {
|
||||
dimension "nonsense"
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${SENSITIVE_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${MEIZUPUSH_APPKEY}\""
|
||||
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${BUGLY_APPID}\""
|
||||
}
|
||||
// internal test dev host
|
||||
@ -140,14 +144,11 @@ android {
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${DEBUG_MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${DEBUG_MIPUSH_APPKEY}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPID", "\"${DEBUG_MEIZUPUSH_APPID}\""
|
||||
buildConfigField "String", "MEIZUPUSH_APPKEY", "\"${DEBUG_MEIZUPUSH_APPKEY}\""
|
||||
buildConfigField "String", "SENSITIVE_API_HOST", "\"${DEV_API_HOST}\""
|
||||
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${DEBUG_BUGLY_APPID}\""
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEV_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEV_UMENG_MESSAGE_SECRET}\""
|
||||
buildConfigField "String", "BUGLY_APPID", "\"${DEV_BUGLY_APPID}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -171,7 +172,7 @@ rebuildChannel {
|
||||
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs','libs/aars'
|
||||
dirs 'libs', 'libs/aars'
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,13 +264,12 @@ dependencies {
|
||||
implementation "com.squareup.picasso:picasso:${picasso}"
|
||||
|
||||
// for video streaming
|
||||
implementation ("com.shuyu:gsyVideoPlayer-java:$gsyVideo",{
|
||||
implementation("com.shuyu:gsyVideoPlayer-java:$gsyVideo", {
|
||||
exclude module: "gsyvideoplayer-androidvideocache"
|
||||
exclude group: "tv.danmaku.ijk.media"
|
||||
})
|
||||
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
|
||||
|
||||
implementation "com.github.wendux:DSBridge-Android:$dsBridge"
|
||||
|
||||
implementation "android.arch.work:work-runtime:${workManager}"
|
||||
|
||||
implementation "com.llew.huawei:verifier:${verifier}"
|
||||
@ -289,9 +289,14 @@ dependencies {
|
||||
|
||||
implementation "com.airbnb.android:lottie:$lottie"
|
||||
|
||||
implementation "net.lingala.zip4j:zip4j:${zip4j}"
|
||||
|
||||
implementation("com.github.piasy:BigImageViewer:$bigImageViewer", {
|
||||
exclude group: 'com.squareup.okhttp3'
|
||||
exclude group: 'androidx.swiperefreshlayout'
|
||||
exclude group: 'com.github.bumptech.glide'
|
||||
})
|
||||
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
implementation project(':libraries:MTA')
|
||||
@ -301,7 +306,6 @@ dependencies {
|
||||
// implementation project(':libraries:WechatShare')
|
||||
implementation project(':libraries:im')
|
||||
implementation project(':libraries:Matisse')
|
||||
implementation project(path: ':libraries:gsyVideoPlayer-proxy_cache')
|
||||
}
|
||||
File propFile = file('sign.properties')
|
||||
if (propFile.exists()) {
|
||||
|
||||
BIN
app/libs/AVMPSDK-external-release-5.4.1002.aar
Normal file
BIN
app/libs/AVMPSDK-external-release-5.4.1002.aar
Normal file
Binary file not shown.
BIN
app/libs/SecurityBodySDK-external-release-5.4.112-preInstall.aar
Normal file
BIN
app/libs/SecurityBodySDK-external-release-5.4.112-preInstall.aar
Normal file
Binary file not shown.
Binary file not shown.
@ -248,4 +248,10 @@
|
||||
-keep class com.pgl.sys.ces.* {*;}
|
||||
|
||||
-keep class com.gyf.immersionbar.* {*;}
|
||||
-dontwarn com.gyf.immersionbar.**
|
||||
-dontwarn com.gyf.immersionbar.**
|
||||
|
||||
-keep class com.taobao.securityjni.**{*;}
|
||||
-keep class com.taobao.wireless.security.**{*;}
|
||||
-keep class com.ut.secbody.**{*;}
|
||||
-keep class com.taobao.dp.**{*;}
|
||||
-keep class com.alibaba.wireless.security.**{*;}
|
||||
@ -4,7 +4,6 @@ import android.app.Application;
|
||||
|
||||
import com.facebook.stetho.Stetho;
|
||||
import com.facebook.stetho.okhttp3.StethoInterceptor;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
@ -18,15 +17,6 @@ import okhttp3.logging.HttpLoggingInterceptor;
|
||||
public class Injection {
|
||||
|
||||
public static boolean appInit(Application application) {
|
||||
|
||||
// init leakcanary
|
||||
if (LeakCanary.isInAnalyzerProcess(application)) {
|
||||
// This process is dedicated to LeakCanary for heap analysis.
|
||||
// You should not init your app in this process.
|
||||
return false;
|
||||
}
|
||||
LeakCanary.install(application);
|
||||
|
||||
// init stetho
|
||||
Stetho.initializeWithDefaults(application);
|
||||
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
android:largeHeap="true"
|
||||
android:resizeableActivity="true"
|
||||
android:theme="@style/AppCompatTheme.APP"
|
||||
tools:replace="android:allowBackup"
|
||||
tools:targetApi="n">
|
||||
|
||||
<!--android:launchMode = "singleTask"-->
|
||||
@ -112,7 +113,9 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!--android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" 退出时屏幕抖动 -->
|
||||
<activity android:name="com.gh.gamecenter.ViewImageActivity" />
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ImageViewerActivity"
|
||||
android:theme="@style/Theme.Transparent" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.SearchActivity"
|
||||
@ -176,9 +179,9 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:name="com.gh.gamecenter.MessageDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.LibaoActivity"
|
||||
@ -207,8 +210,8 @@
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CommentDetailActivity"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:screenOrientation="portrait" />
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.mygame.MyGameActivity"
|
||||
@ -418,9 +421,9 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:name="com.gh.gamecenter.gamedetail.rating.RatingReplyActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.history.HistoryActivity"
|
||||
@ -513,11 +516,26 @@
|
||||
<activity
|
||||
android:name=".qa.answer.draft.AnswerDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".gamedetail.rating.RatingFoldActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".video.data.VideoDataActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".video.poster.PosterEditActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".video.poster.PosterClipActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.PushProxyActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@android:style/Theme.Translucent" />
|
||||
|
||||
<activity
|
||||
@ -580,7 +598,7 @@
|
||||
</receiver>
|
||||
|
||||
<!--魅族push应用定义消息receiver声明 -->
|
||||
<receiver android:name="com.gh.gamecenter.receiver.MeizuPushReceiver">
|
||||
<receiver android:name="com.gh.gamecenter.receiver.UmengMeizuPushReceiver">
|
||||
<intent-filter>
|
||||
<!-- 接收push消息 -->
|
||||
<action android:name="com.meizu.flyme.push.intent.MESSAGE" />
|
||||
@ -605,7 +623,13 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name="com.gh.base.GHUmengNotificationService" />
|
||||
<meta-data
|
||||
android:name="com.huawei.hms.client.appid"
|
||||
android:value="@string/huawei_push_appid" />
|
||||
|
||||
<service
|
||||
android:name="com.gh.base.GHUmengNotificationService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
|
||||
|
||||
|
||||
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2018 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 androidx.swiperefreshlayout.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RadialGradient;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.graphics.drawable.shapes.OvalShape;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
/**
|
||||
* Private class created to work around issues with AnimationListeners being
|
||||
* called before the animation is actually complete and support shadows on older
|
||||
* platforms.
|
||||
*/
|
||||
class CircleImageView extends ImageView {
|
||||
|
||||
private static final int KEY_SHADOW_COLOR = 0x1E000000;
|
||||
private static final int FILL_SHADOW_COLOR = 0x3D000000;
|
||||
// PX
|
||||
private static final float X_OFFSET = 0f;
|
||||
private static final float Y_OFFSET = 1.75f;
|
||||
private static final float SHADOW_RADIUS = 3.5f;
|
||||
private static final int SHADOW_ELEVATION = 4;
|
||||
|
||||
private Animation.AnimationListener mListener;
|
||||
int mShadowRadius;
|
||||
|
||||
CircleImageView(Context context, int color) {
|
||||
super(context);
|
||||
final float density = getContext().getResources().getDisplayMetrics().density;
|
||||
final int shadowYOffset = (int) (density * Y_OFFSET);
|
||||
final int shadowXOffset = (int) (density * X_OFFSET);
|
||||
|
||||
mShadowRadius = (int) (density * SHADOW_RADIUS);
|
||||
|
||||
ShapeDrawable circle;
|
||||
if (elevationSupported()) {
|
||||
circle = new ShapeDrawable(new OvalShape());
|
||||
ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
|
||||
} else {
|
||||
OvalShape oval = new OvalShadow(mShadowRadius);
|
||||
circle = new ShapeDrawable(oval);
|
||||
setLayerType(View.LAYER_TYPE_SOFTWARE, circle.getPaint());
|
||||
circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
|
||||
KEY_SHADOW_COLOR);
|
||||
final int padding = mShadowRadius;
|
||||
// set padding so the inner image sits correctly within the shadow.
|
||||
setPadding(padding, padding, padding, padding);
|
||||
}
|
||||
circle.getPaint().setColor(color);
|
||||
ViewCompat.setBackground(this, circle);
|
||||
}
|
||||
|
||||
private boolean elevationSupported() {
|
||||
return android.os.Build.VERSION.SDK_INT >= 21;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (!elevationSupported()) {
|
||||
setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight()
|
||||
+ mShadowRadius * 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnimationListener(Animation.AnimationListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart() {
|
||||
super.onAnimationStart();
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(getAnimation());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
super.onAnimationEnd();
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(getAnimation());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the background color of the circle image view.
|
||||
*
|
||||
* @param colorRes Id of a color resource.
|
||||
*/
|
||||
public void setBackgroundColorRes(int colorRes) {
|
||||
setBackgroundColor(ContextCompat.getColor(getContext(), colorRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(int color) {
|
||||
if (getBackground() instanceof ShapeDrawable) {
|
||||
((ShapeDrawable) getBackground()).getPaint().setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
private class OvalShadow extends OvalShape {
|
||||
private RadialGradient mRadialGradient;
|
||||
private Paint mShadowPaint;
|
||||
|
||||
OvalShadow(int shadowRadius) {
|
||||
super();
|
||||
mShadowPaint = new Paint();
|
||||
mShadowRadius = shadowRadius;
|
||||
updateRadialGradient((int) rect().width());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResize(float width, float height) {
|
||||
super.onResize(width, height);
|
||||
updateRadialGradient((int) width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
final int viewWidth = CircleImageView.this.getWidth();
|
||||
final int viewHeight = CircleImageView.this.getHeight();
|
||||
canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2, mShadowPaint);
|
||||
canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2 - mShadowRadius, paint);
|
||||
}
|
||||
|
||||
private void updateRadialGradient(int diameter) {
|
||||
mRadialGradient = new RadialGradient(diameter / 2, diameter / 2,
|
||||
mShadowRadius, new int[] { FILL_SHADOW_COLOR, Color.TRANSPARENT },
|
||||
null, Shader.TileMode.CLAMP);
|
||||
mShadowPaint.setShader(mRadialGradient);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,19 +3,32 @@ package com.gh.base;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.gh.base.fragment.BaseFragment;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.RunningUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.common.util.StringUtils;
|
||||
@ -36,9 +49,6 @@ import org.json.JSONObject;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import butterknife.ButterKnife;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
|
||||
@ -109,6 +119,15 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0) {
|
||||
view = getRootViewWithEnvIndicator(view);
|
||||
}
|
||||
super.setContentView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (useEventBus()) EventBus.getDefault().unregister(this);
|
||||
@ -128,21 +147,55 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
String icon,
|
||||
String shareTitle,
|
||||
String shareSummary,
|
||||
ShareUtils.ShareType shareType) {
|
||||
ShareUtils.ShareEntrance shareEntrance, String id) {
|
||||
ShareUtils.getInstance(this).showShareWindows(this,
|
||||
getWindow().getDecorView(),
|
||||
url,
|
||||
icon,
|
||||
shareTitle,
|
||||
shareSummary,
|
||||
shareType);
|
||||
if (shareType == ShareUtils.ShareType.game || shareType == ShareUtils.ShareType.plugin) {
|
||||
shareEntrance, id);
|
||||
if (shareEntrance == ShareUtils.ShareEntrance.game || shareEntrance == ShareUtils.ShareEntrance.plugin) {
|
||||
MtaHelper.onEvent("内容分享", "内容分享", shareTitle + shareSummary);
|
||||
} else {
|
||||
MtaHelper.onEvent("内容分享", "内容分享", shareTitle);
|
||||
}
|
||||
}
|
||||
|
||||
private View getRootViewWithEnvIndicator(View view) {
|
||||
RelativeLayout screenRootView = new RelativeLayout(this);
|
||||
screenRootView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
|
||||
LinearLayout ll = new LinearLayout(this);
|
||||
TextView tv = new TextView(this);
|
||||
String envText = "正式环境";
|
||||
if (BuildConfig.FLAVOR.equals("internal")) {
|
||||
envText = "测试环境";
|
||||
}
|
||||
tv.setText(envText);
|
||||
tv.setGravity(Gravity.CENTER);
|
||||
tv.setTextColor(Color.WHITE);
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
|
||||
tv.setBackground(ContextCompat.getDrawable(this, R.color.red));
|
||||
tv.measure(0, 0);
|
||||
tv.setAlpha(0.15F);
|
||||
int height = tv.getMeasuredHeight();
|
||||
int width = tv.getMeasuredWidth();
|
||||
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
|
||||
ll.setTranslationX(DisplayUtils.dip2px(20));
|
||||
ll.setRotation(45);
|
||||
ll.addView(tv);
|
||||
ll.setPadding(0, (width - height) / 2, 0, (width - height) / 2);
|
||||
|
||||
screenRootView.addView(view);
|
||||
screenRootView.addView(ll);
|
||||
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) ll.getLayoutParams();
|
||||
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
return screenRootView;
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(final EBShowDialog showDialog) {
|
||||
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)
|
||||
@ -154,7 +207,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
if (FileUtils.isEmptyFile(showDialog.getPath())) {
|
||||
toast(R.string.install_failure_hint);
|
||||
} else {
|
||||
startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath()));
|
||||
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
|
||||
}
|
||||
});
|
||||
} else if (LOGIN_EXCEPTION.equals(showDialog.getType())) {
|
||||
|
||||
@ -35,6 +35,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
|
||||
val mDraftBtn by bindView<TextView>(R.id.draft_btn)
|
||||
|
||||
private val mEditorTextNumTv by bindView<TextView>(R.id.editorTextNumTv)
|
||||
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
|
||||
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
|
||||
private val mEditorParagraph by bindView<CheckableImageView>(R.id.editor_paragraph)
|
||||
@ -89,6 +90,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
// 防止个别手机在Js里无法获取粘贴内容
|
||||
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
|
||||
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
|
||||
mRichEditor.addJavascriptInterface(OnEditorTextChangeListener(), "OnEditorTextChangeListener")
|
||||
mRichEditor.setInputEnabled(true)
|
||||
|
||||
mDraftBtn.text = if (this is AnswerEditActivity) {
|
||||
@ -258,6 +260,14 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnEditorTextChangeListener {
|
||||
@JavascriptInterface
|
||||
fun onTextChange(count: Int) {
|
||||
val num = if (count > MAX_INPUT_TEXT_NUM) MAX_INPUT_TEXT_NUM - count else count
|
||||
mEditorTextNumTv.text = num.toString()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun mtaEventName(): String
|
||||
|
||||
companion object {
|
||||
@ -273,5 +283,6 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
const val INSERT_ANSWER_CODE = 411
|
||||
const val INSERT_ARTICLE_CODE = 412
|
||||
const val INSERT_GAME_CODE = 413
|
||||
const val MAX_INPUT_TEXT_NUM = 10000
|
||||
}
|
||||
}
|
||||
@ -95,7 +95,7 @@ class GHUmengNotificationService : UmengMessageService() {
|
||||
|
||||
// 用户未登录的情况下不生成消息中心通知,避免用户掉登录了还收到跳转至消息中心的通知
|
||||
if (data != null
|
||||
&& data.link?.target == "system"
|
||||
&& data.link?.link == "system"
|
||||
&& !UserManager.getInstance().isLoggedIn) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -14,8 +14,14 @@ import android.view.Window;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
@ -32,13 +38,6 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
/**
|
||||
* 需要用到工具栏的页面使用
|
||||
* <p>
|
||||
@ -50,7 +49,7 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
@Nullable
|
||||
private PackageViewModel mPackageViewModel;
|
||||
|
||||
protected RelativeLayout mToolbarContainer;
|
||||
protected View mToolbarContainer;
|
||||
|
||||
protected Toolbar mToolbar;
|
||||
|
||||
@ -239,7 +238,7 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getItemId() == R.id.menu_download) {
|
||||
MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
|
||||
// MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
|
||||
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(this, mEntrance);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@ -9,6 +9,14 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.base.OnListClickListener;
|
||||
import com.gh.base.OnRequestCallBackListener;
|
||||
import com.gh.common.constant.Constants;
|
||||
@ -29,13 +37,6 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.ButterKnife;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
@ -210,6 +211,13 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
return mCachedView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
mCachedView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
@ -3,11 +3,10 @@ package com.gh.base.fragment
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.CheckedTextView
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager.widget.PagerAdapter
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import butterknife.BindView
|
||||
import com.gh.base.adapter.FragmentAdapter
|
||||
@ -15,7 +14,6 @@ import com.gh.common.view.TabIndicatorView
|
||||
import com.gh.gamecenter.R
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import com.lightgame.view.NoScrollableViewPager
|
||||
|
||||
@ -23,8 +21,10 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
|
||||
|
||||
@BindView(R.id.fragment_tab_layout)
|
||||
lateinit var mTabLayout: TabLayout
|
||||
|
||||
@BindView(R.id.fragment_view_pager)
|
||||
lateinit var mViewPager: NoScrollableViewPager
|
||||
|
||||
@BindView(R.id.fragment_tab_indicator)
|
||||
lateinit var mTabIndicatorView: TabIndicatorView
|
||||
|
||||
@ -66,6 +66,10 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
|
||||
if (arguments != null) mCheckedIndex = requireArguments().getInt(PAGE_INDEX, 0)
|
||||
}
|
||||
|
||||
open fun providePagerAdapter(): PagerAdapter? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
@ -74,7 +78,8 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
|
||||
|
||||
mViewPager.offscreenPageLimit = mFragmentsList.size
|
||||
mViewPager.addOnPageChangeListener(this)
|
||||
mViewPager.adapter = FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
|
||||
mViewPager.adapter = providePagerAdapter()
|
||||
?: FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
|
||||
mViewPager.currentItem = mCheckedIndex
|
||||
mTabLayout.setupWithViewPager(mViewPager)
|
||||
mTabIndicatorView.setupWithTabLayout(mTabLayout)
|
||||
@ -84,60 +89,10 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
|
||||
val tab = mTabLayout.getTabAt(i) ?: continue
|
||||
val tabTitle = if (tab.text != null) tab.text.toString() else ""
|
||||
var tabView = provideTabView(i, tabTitle)
|
||||
if (tabView == null) tabView = createDefaultTabCustomView(tabTitle)
|
||||
if (tabView == null) tabView = BaseFragment_TabLayout.createDefaultTabCustomView(tabTitle)
|
||||
tab.customView = tabView
|
||||
}
|
||||
initTabStyle(mTabLayout, mCheckedIndex)
|
||||
}
|
||||
|
||||
open fun initTabStyle(tabLayout: TabLayout?, currentItem: Int) { // 默认选择addOnTabSelectedListener不会回调
|
||||
val tabCount = tabLayout!!.tabCount
|
||||
if (tabCount > 0) {
|
||||
val tab = tabLayout.getTabAt(currentItem)
|
||||
if (tab != null) updateTabStyle(tab, true)
|
||||
}
|
||||
tabLayout.addOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
updateTabStyle(tab, true)
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab) {
|
||||
updateTabStyle(tab, false)
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab) {
|
||||
updateTabStyle(tab, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
open fun updateTabStyle(tab: TabLayout.Tab, isChecked: Boolean) {
|
||||
val tabView = tab.customView
|
||||
if (tabView == null) {
|
||||
Utils.log("TabLayout->Tab样式不是通用样式,请检查")
|
||||
return
|
||||
}
|
||||
val tabTitle: TextView?
|
||||
tabTitle = if (tabView is TextView) {
|
||||
tabView
|
||||
} else {
|
||||
tabView.findViewById(R.id.tab_title)
|
||||
}
|
||||
if (tabTitle == null) {
|
||||
Utils.log("TabLayout->Tab样式不是通用样式,请检查")
|
||||
return
|
||||
}
|
||||
tabTitle.typeface = if (isChecked) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
|
||||
}
|
||||
|
||||
// 如果不设置View的话,无法动态设置字体样式
|
||||
open fun createDefaultTabCustomView(title: String?): View {
|
||||
val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item, null)
|
||||
val tabTitle = view.findViewById<View>(R.id.tab_title)
|
||||
if (tabTitle is CheckedTextView) {
|
||||
tabTitle.text = title
|
||||
}
|
||||
return view
|
||||
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex)
|
||||
}
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
|
||||
@ -5,6 +5,7 @@ import android.os.Looper
|
||||
import com.gh.common.AppExecutor.ioExecutor
|
||||
import com.gh.common.AppExecutor.lightWeightIoExecutor
|
||||
import com.gh.common.AppExecutor.uiExecutor
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@ -25,6 +26,8 @@ object AppExecutor {
|
||||
@JvmStatic
|
||||
val ioExecutor = Executors.newCachedThreadPool() // 用 by lazy 可能影响初始化速度
|
||||
|
||||
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }
|
||||
|
||||
class MainThreadExecutor : Executor {
|
||||
private val mainThreadHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
||||
@ -4,11 +4,13 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.dsbridge.CompletionHandler
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.LoginActivity
|
||||
import com.gh.gamecenter.ViewImageActivity
|
||||
import com.gh.gamecenter.entity.Badge
|
||||
import com.gh.gamecenter.entity.MtaEvent
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
@ -23,7 +25,6 @@ import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import wendu.dsbridge.CompletionHandler
|
||||
|
||||
class DefaultJsApi(var context: Context) {
|
||||
|
||||
@ -70,7 +71,6 @@ class DefaultJsApi(var context: Context) {
|
||||
userInfoEntity.badge = null
|
||||
}
|
||||
UserManager.getInstance().userInfoEntity = userInfoEntity
|
||||
AppDatabase.getInstance(context).userInfoDao().updateUserInfo(userInfoEntity)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -139,7 +139,21 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
val context = CurrentActivityHolder.getCurrentActivity()
|
||||
|
||||
context?.startActivity(ViewImageActivity.getViewImageIntent(context, imageEvent.imageList, imageEvent.position, "浏览器"))
|
||||
context?.startActivity(ImageViewerActivity.getIntent(context, imageEvent.imageList, imageEvent.position, "浏览器"))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun isInstalled(event: Any): String {
|
||||
val localInstalledPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
|
||||
val packageNameList: ArrayList<String> = event.toString().toObject() ?: ArrayList()
|
||||
|
||||
for (packageName in packageNameList) {
|
||||
if (!localInstalledPackageList.contains(packageName)) {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
return "true"
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -148,7 +162,12 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
Base64ImageHolder.image = event.toString()
|
||||
|
||||
context?.startActivity(ViewImageActivity.getBase64ViewImageIntent(context, true))
|
||||
context?.startActivity(ImageViewerActivity.getBase64Intent(context, true))
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun openNotificationSetting(msg: Any){
|
||||
NotificationHelper.show(context as AppCompatActivity)
|
||||
}
|
||||
|
||||
@Keep
|
||||
|
||||
@ -4,21 +4,21 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
|
||||
import com.gh.common.util.DirectUtils.directToGameVideo
|
||||
import com.gh.common.util.DirectUtils.directToVideoDetail
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.entity.SubjectRecommendEntity
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
object DefaultWebViewUrlHandler {
|
||||
object DefaultUrlHandler {
|
||||
|
||||
@JvmStatic
|
||||
fun interceptUrl(context: Context, url: String, entrance: String): Boolean {
|
||||
@ -49,7 +49,7 @@ object DefaultWebViewUrlHandler {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
"qqqun" -> {
|
||||
EntranceUtils.HOST_QQ_QUN -> {
|
||||
val key = uri.getQueryParameter("key")
|
||||
if (!DirectUtils.directToQqGroup(context, key)) {
|
||||
Utils.toast(context, "请检查是否已经安装手机QQ")
|
||||
@ -124,11 +124,11 @@ object DefaultWebViewUrlHandler {
|
||||
val categoryId = uri.getQueryParameter("category_id") ?: ""
|
||||
val link = uri.getQueryParameter("link") ?: ""
|
||||
val linkEntity = VideoLinkEntity(title, categoryId, link)
|
||||
// if (!CheckLoginUtils.isLogin()) {
|
||||
// HaloApp.put(EntranceUtils.HOST_UPLOAD_VIDEO, linkEntity)
|
||||
// }
|
||||
val gameId = uri.getQueryParameter("gameId") ?: ""
|
||||
val gameName = uri.getQueryParameter("gameName") ?: ""
|
||||
val simpleGameEntity = SimpleGameEntity(gameId, gameName)
|
||||
CheckLoginUtils.checkLogin(context, null, true, EntranceUtils.ENTRANCE_BROWSER) {
|
||||
DirectUtils.directToVideoManager(context, linkEntity, EntranceUtils.ENTRANCE_BROWSER, "")
|
||||
DirectUtils.directToVideoManager(context, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "")
|
||||
}
|
||||
}
|
||||
EntranceUtils.HOST_USERHOME -> {
|
||||
@ -139,8 +139,17 @@ object DefaultWebViewUrlHandler {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
val type = uri.getQueryParameter("type") ?: ""
|
||||
val act = uri.getQueryParameter("act") ?: ""
|
||||
val loaction = if (TextUtils.isEmpty(act)) id else VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.value
|
||||
directToVideoDetail(context, id, loaction, false, "", entrance, "", referer, type, act)
|
||||
val gameId = uri.getQueryParameter("gameId") ?: ""
|
||||
val fieldId = uri.getQueryParameter("fieldId") ?: ""
|
||||
val sectionName = uri.getQueryParameter("sectionName") ?: ""
|
||||
val location = if (!TextUtils.isEmpty(act)) {
|
||||
VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.value
|
||||
} else if (!TextUtils.isEmpty(fieldId)) {
|
||||
VideoDetailContainerViewModel.Location.GAME_ZONE.value
|
||||
} else {
|
||||
id
|
||||
}
|
||||
directToVideoDetail(context, id, location, false, gameId, entrance, "", referer, type, act, fieldId, sectionName)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_SINGLE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
@ -178,7 +187,7 @@ object DefaultWebViewUrlHandler {
|
||||
val tag = uri.getQueryParameter("tag") ?: ""
|
||||
DirectUtils.directAskColumnLabelDetail(context, tag, community, entrance, "")
|
||||
}
|
||||
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL->{
|
||||
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = uri.getQueryParameter("community_id") ?: ""
|
||||
community.name = uri.getQueryParameter("community_name") ?: ""
|
||||
@ -186,11 +195,144 @@ object DefaultWebViewUrlHandler {
|
||||
DirectUtils.directAskColumnDetail(context, columnId, community, entrance, "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_BLOCK -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
val entity = SubjectRecommendEntity(link = id, name = name, text = name)
|
||||
DirectUtils.directToBlock(context, entity, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_SERVER_BLOCK -> {
|
||||
DirectUtils.directToGameServers(context, entrance = entrance, path = "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_AMWAY_BLOCK -> {
|
||||
DirectUtils.directToAmway(context, entrance = entrance, path = "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HELP -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
DirectUtils.directToQa(context, name, id)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HELP_COLLECTION -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
DirectUtils.directToQaCollection(context, name, id)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_UPLOAD -> {
|
||||
DirectUtils.directGameUpload(context, entrance = entrance, path = "")
|
||||
}
|
||||
EntranceUtils.HOST_GAME_ZONE -> {
|
||||
val zoneUrl = uri.getQueryParameter("url") ?: ""
|
||||
DirectUtils.directGameZone(context, id, zoneUrl, entrance)
|
||||
}
|
||||
|
||||
else -> DialogUtils.showLowVersionDialog(context)
|
||||
}
|
||||
return true
|
||||
} else if ("zhiqu" == uri.scheme) {
|
||||
if (PackageUtils.isInstalled(context, "com.beieryouxi.zqyxh")) {
|
||||
val intent = Intent()
|
||||
intent.data = Uri.parse(url)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
Utils.toast(context, "请安装指趣游戏盒")
|
||||
}
|
||||
}
|
||||
|
||||
if (url.startsWith("alipays:") || url.startsWith("alipay")) {
|
||||
try {
|
||||
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
|
||||
} catch (e: Exception) {
|
||||
ToastUtils.showToast("请安装支付宝客户端")
|
||||
}
|
||||
return true
|
||||
} else if (url.startsWith("weixin")) {
|
||||
try {
|
||||
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
|
||||
} catch (e: Exception) {
|
||||
ToastUtils.showToast("请安装微信客户端")
|
||||
}
|
||||
return true
|
||||
} else if (url.startsWith("mqqwpa")) {
|
||||
try {
|
||||
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
|
||||
} catch (e: Exception) {
|
||||
ToastUtils.showToast("请安装QQ客户端")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if ("http" != uri.scheme && "https" != uri.scheme) return true
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun transformNormalScheme(context: Context, url: String, entrance: String): Boolean {
|
||||
val uri = Uri.parse(url)
|
||||
if (uri.host == "www.ghzs666.com" || uri.host == "www.ghzs.com" || uri.host == "ask.ghzs.com" || uri.host == "m.ghzs.com") {
|
||||
Utils.log(uri.path)
|
||||
uri.path?.apply {
|
||||
when {
|
||||
contains("game") -> {
|
||||
val gameId = uri.getQueryParameter("gameId") ?: ""
|
||||
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, scrollToLibao = false, traceEvent = null)
|
||||
}
|
||||
contains("question") -> {
|
||||
val questionId = split("/")[2]
|
||||
val answerId = uri.getQueryParameter("answer")
|
||||
if (answerId.isNullOrEmpty()) {
|
||||
DirectUtils.directToQuestionDetail(context, questionId, entrance, "")
|
||||
} else {
|
||||
DirectUtils.directToAnswerDetail(context, answerId, entrance, "")
|
||||
}
|
||||
}
|
||||
contains("communities") && contains("article") -> {
|
||||
var communityId = ""
|
||||
var type = ""
|
||||
var typeId = ""
|
||||
val split = replace("/communities", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
for (text in split) {
|
||||
if (TextUtils.isEmpty(communityId)) {
|
||||
communityId = text
|
||||
continue
|
||||
}
|
||||
if (TextUtils.isEmpty(type)) {
|
||||
type = text
|
||||
continue
|
||||
}
|
||||
if (TextUtils.isEmpty(typeId)) {
|
||||
typeId = text
|
||||
}
|
||||
}
|
||||
if ("articles" == type) {
|
||||
DirectUtils.directToCommunityArticle(
|
||||
context, typeId, communityId,
|
||||
entrance, "文章链接")
|
||||
}
|
||||
}
|
||||
contains("article") -> {
|
||||
val articleId = split("/")[2].replace(".html", "")
|
||||
DirectUtils.directToArticle(context, articleId, entrance)
|
||||
}
|
||||
contains("columns") -> {
|
||||
val columnsId = split("/")[3]
|
||||
val id = uri.getQueryParameter("communityId") ?: ""
|
||||
val name = uri.getQueryParameter("communityName") ?: ""
|
||||
DirectUtils.directToCommunityColumn(context, CommunityEntity(id, name), columnsId, entrance, "")
|
||||
}
|
||||
contains("zone") -> {
|
||||
val gameId = split("/")[2]
|
||||
DirectUtils.directGameZone(context, gameId, url, entrance)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
67
app/src/main/java/com/gh/common/FixedRateJobHelper.kt
Normal file
67
app/src/main/java/com/gh/common/FixedRateJobHelper.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package com.gh.common
|
||||
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.util.doOnMainProcessOnly
|
||||
import com.gh.common.videolog.VideoRecordUtils
|
||||
import com.gh.gamecenter.entity.TimeEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
object FixedRateJobHelper {
|
||||
private const val CHECKER_PERIOD: Long = 60 * 1000L
|
||||
private const val TIME_PERIOD: Long = 600 * 1000L
|
||||
private const val LOGHUB_PERIOD: Long = 120 * 1000L
|
||||
private const val EXPOSURE_PERIOD: Long = 300 * 1000L
|
||||
private const val REGION_SETTING_PERIOD: Long = 300 * 1000L
|
||||
private const val VIDEO_RECORD_PERIOD: Long = 60 * 1000L
|
||||
|
||||
private var mExecuteCount: Int = 0
|
||||
|
||||
var timeDeltaBetweenServerAndClient: Long = 0
|
||||
|
||||
@JvmStatic
|
||||
fun begin() {
|
||||
doOnMainProcessOnly {
|
||||
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
|
||||
// 时间校对,10分钟一次
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
|
||||
.subscribeOn(AppExecutor.cachedScheduler)
|
||||
.subscribe(object : Response<TimeEntity>() {
|
||||
override fun onResponse(response: TimeEntity?) {
|
||||
val serverTime = response?.time
|
||||
serverTime?.let { timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis() }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 提交曝光数据
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % EXPOSURE_PERIOD == 0L) {
|
||||
ExposureManager.commitSavedExposureEvents(true)
|
||||
}
|
||||
|
||||
// 提交普通 loghub 数据
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % LOGHUB_PERIOD == 0L) {
|
||||
LoghubUtils.commitSavedLoghubEvents()
|
||||
}
|
||||
|
||||
// 更新游戏屏蔽信息
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % REGION_SETTING_PERIOD == 0L) {
|
||||
RegionSettingHelper.getRegionSetting()
|
||||
}
|
||||
|
||||
// 提交视频浏览记录数据
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % VIDEO_RECORD_PERIOD == 0L) {
|
||||
VideoRecordUtils.commitVideoRecord()
|
||||
}
|
||||
|
||||
// ExposureUtils.logADownloadCompleteExposureEvent(GameEntity(id = mExecuteCount.toString(), name = "测试曝光上传"), platform = "", trace = null, downloadType = ExposureUtils.DownloadType.DOWNLOAD)
|
||||
mExecuteCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,22 +38,17 @@ object PushManager {
|
||||
fun init(channel: String) {
|
||||
tryWithDefaultCatch {
|
||||
//初始化友盟推送
|
||||
UMConfigure.init(mApplication,
|
||||
Config.UMENG_APPKEY, channel,
|
||||
UMConfigure.DEVICE_TYPE_PHONE,
|
||||
Config.UMENG_MESSAGE_SECRET)
|
||||
UMConfigure.init(mApplication, Config.UMENG_APPKEY, channel, UMConfigure.DEVICE_TYPE_PHONE, Config.UMENG_MESSAGE_SECRET)
|
||||
|
||||
val pushAgent = PushAgent.getInstance(mApplication)
|
||||
|
||||
runOnIoThread { registerDevice() }
|
||||
|
||||
// 注册小米、华为和魅族通道
|
||||
MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
|
||||
HuaWeiRegister.register(mApplication)
|
||||
MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
|
||||
|
||||
//友盟推送
|
||||
val pushAgent = PushAgent.getInstance(mApplication)
|
||||
|
||||
//注册推送服务,每次调用register方法都会回调该接口
|
||||
runOnIoThread { registerDevice() }
|
||||
|
||||
val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
|
||||
mPreviousAlias = aliasInSp?.toObject()
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import io.reactivex.schedulers.Schedulers;
|
||||
public class Config {
|
||||
|
||||
public static final String API_HOST = BuildConfig.API_HOST;
|
||||
public static final String SENSITIVE_API_HOST = BuildConfig.SENSITIVE_API_HOST;
|
||||
|
||||
/**
|
||||
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
|
||||
@ -253,7 +254,7 @@ public class Config {
|
||||
public static void getGhzsSettings() {
|
||||
String channel = HaloApp.getInstance().getChannel();
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication())
|
||||
.getApi().getSettings(PackageUtils.getVersionName(), channel)
|
||||
.getSensitiveApi().getSettings(PackageUtils.getVersionName(), channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<SettingsEntity>() {
|
||||
|
||||
@ -12,11 +12,12 @@ public class Constants {
|
||||
|
||||
public final static int NOT_NETWORK_CODE = 504; // 没有网络的状态码(应该是这个吧!)
|
||||
|
||||
public static final String LOGIN_TOKEN_ID = "userToken_id"; // 用户ID 与服务器无关
|
||||
|
||||
public static final String USER_TOKEN_KEY = "userTokenKey";
|
||||
public static final String USER_INFO_KEY = "userInfoKey";
|
||||
|
||||
public static final String WELCOME_DIALOG_ID = "welcome_dialog_id";
|
||||
public static final String WELCOME_DIALOG_LINK_TITLE = "welcome_dialog_link_title";
|
||||
|
||||
public static final String DEVICE_KEY = "deviceKey";
|
||||
|
||||
public static final String HAS_REQUESTED_NOTIFICATION_PERMISSIONS = "has_requested_notification_permissions";
|
||||
@ -28,12 +29,12 @@ public class Constants {
|
||||
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
||||
|
||||
public static final String EB_QUIT_LOGIN = "quit_login";
|
||||
|
||||
|
||||
// 用于避免历史下载掺和到普通下载状态的 ID 修饰符
|
||||
public static final String GAME_ID_DIVIDER = ":";
|
||||
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
|
||||
public static final String GAME_NAME_DECORATOR = " ";
|
||||
|
||||
|
||||
// 游戏详情进入时的自定义栏目标签是否已经默认展开过一次的标记
|
||||
public static final String SP_HAS_EXPANDED_GAME_DETAIL_TAGS = "has_expanded_game_detail_tags";
|
||||
// 游戏详情进入时的自定义栏目标签是否已经显示过一次展开更多的浮窗提示
|
||||
@ -43,6 +44,13 @@ public class Constants {
|
||||
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
|
||||
public static final String SP_LAST_OPENING_TIME = "last_opening_dialog_time";
|
||||
|
||||
// 游戏图标和图标角标
|
||||
public static final String RAW_GAME_ICON = "raw_game_icon";
|
||||
public static final String GAME_ICON_SUBSCRIPT = "game_icon_subscript";
|
||||
|
||||
// 新用户首次启动光环的时间
|
||||
public static final String SP_INITIAL_USAGE_TIME = "initial_usage_time";
|
||||
|
||||
//引导设置 “通知管理” 引导弹窗
|
||||
public static final String SP_SHOWED_NOTIFICATION_LOGIN = "show_notification_login_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_QUESTION = "show_notification_question_hint";
|
||||
@ -86,6 +94,8 @@ public class Constants {
|
||||
public static final String SP_AUTH_DIALOG = "auth_dialog";
|
||||
//顶部视频进度保存,重启恢复
|
||||
public static final String SP_TOP_VIDEO_SCHEDULE = "top_video_schedule";
|
||||
//我的光环小红点提示
|
||||
public static final String SP_GH_RED_POINT_REMIND = "gh_red_point_remind";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
@ -103,6 +113,9 @@ public class Constants {
|
||||
public static final String BADGE_ADDRESS_DEV = "http://resource.ghzs.com/page/badge_dev/index.html#/";
|
||||
public static final String BADGE_ADDRESS = "http://resource.ghzs.com/page/badge_pro/index.html#/";
|
||||
|
||||
// 腾讯企点地址
|
||||
public static final String TENCENT_QIDIAN_ADDRESS = "https://url.cn/D80iyMVV?_type=wpa&qidian=true";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.common.databind;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
@ -13,6 +14,12 @@ import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.base.OnViewClickListener;
|
||||
import com.gh.common.constant.Config;
|
||||
@ -33,12 +40,14 @@ import com.gh.common.util.LogUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NewsUtils;
|
||||
import com.gh.common.util.NumberUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.PermissionHelper;
|
||||
import com.gh.common.util.PlatformUtils;
|
||||
import com.gh.common.util.ReservationHelper;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.view.DrawableView;
|
||||
import com.gh.common.view.GameIconView;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.download.dialog.DownloadDialog;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
@ -68,12 +77,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
/**
|
||||
* Created by khy on 12/02/18.
|
||||
*/
|
||||
@ -95,6 +98,26 @@ public class BindingAdapters {
|
||||
view.setTextSize(number);
|
||||
}
|
||||
|
||||
@BindingAdapter("setTypeface")
|
||||
public static void setTypeface(TextView view, String type) {
|
||||
if (type == null) return;
|
||||
|
||||
switch (type) {
|
||||
case "bold":
|
||||
view.setTypeface(null, Typeface.BOLD);
|
||||
break;
|
||||
case "italic":
|
||||
view.setTypeface(null, Typeface.ITALIC);
|
||||
break;
|
||||
case "bold_italic":
|
||||
view.setTypeface(null, Typeface.BOLD_ITALIC);
|
||||
break;
|
||||
default:
|
||||
view.setTypeface(null, Typeface.NORMAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"addDetailKaiFuView", "addDetailKaiFuViewListener", "isReadyPatch"})
|
||||
public static void addDetailKaiFuView(LinearLayout view, List<ServerCalendarEntity> list
|
||||
, OnViewClickListener listener, Boolean isReadyPatch) {
|
||||
@ -292,6 +315,13 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("game")
|
||||
public static void setGame(View view, GameEntity gameEntity) {
|
||||
if (gameEntity != null && view instanceof GameIconView) {
|
||||
((GameIconView) view).setGameEntity(gameEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("articleType")
|
||||
public static void setArticleType(TextView view, String articleType) {
|
||||
NewsUtils.setNewsType(view, articleType, 0, 0);
|
||||
@ -406,15 +436,16 @@ public class BindingAdapters {
|
||||
case PLUGIN:
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
ApkEntity apk = gameEntity.getApk().get(0);
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk,
|
||||
() -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
|
||||
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
|
||||
});
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showOverseaDownloadDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.checkDownload(v.getContext(), apk.getSize(),
|
||||
isSubscribe -> download(progressBar, gameEntity, traceEvent, isSubscribe, entrance, location));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
|
||||
@ -446,7 +477,7 @@ public class BindingAdapters {
|
||||
if (gameEntity.getApk().size() == 1) {
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance(progressBar.getContext()).getDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl());
|
||||
if (downloadEntity != null) {
|
||||
PackageUtils.launchSetup(v.getContext(), downloadEntity);
|
||||
PackageInstaller.install(v.getContext(), downloadEntity);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -485,7 +516,7 @@ public class BindingAdapters {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
}
|
||||
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay));
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay,linkEntity.getCloseButton()));
|
||||
progressBar.getContext().startActivity(i);
|
||||
break;
|
||||
}
|
||||
@ -687,14 +718,15 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"setGameName", "isShowPlatform"})
|
||||
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform) {
|
||||
@BindingAdapter({"setGameName", "isShowPlatform", "isShowSuffix"})
|
||||
public static void setGameName(TextView view, GameEntity game, boolean isShowPlatform, @Nullable Boolean isShowSuffix) {
|
||||
if (isShowSuffix == null) isShowSuffix = true; // 默认显示
|
||||
if (isShowPlatform && game.getApk().size() > 0) {
|
||||
view.setText(String.format("%s - %s", game.getName(),
|
||||
view.setText(String.format("%s - %s", !isShowSuffix ? game.getNameWithoutSuffix() : game.getName(),
|
||||
PlatformUtils.getInstance(view.getContext()).getPlatformName(
|
||||
game.getApk().get(0).getPlatform())));
|
||||
} else {
|
||||
view.setText(game.getName());
|
||||
view.setText(!isShowSuffix ? game.getNameWithoutSuffix() : game.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@ -753,4 +785,17 @@ public class BindingAdapters {
|
||||
}
|
||||
view.setText(span);
|
||||
}
|
||||
|
||||
@BindingAdapter({"setVideoData"})
|
||||
public static void setVideoData(TextView view, int count) {
|
||||
if (count > 0) {
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(view.getContext(), R.drawable.ic_video_data_up), null, null, null);
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.text_EA3333));
|
||||
view.setText(count + "");
|
||||
} else {
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
|
||||
view.setTextColor(ContextCompat.getColor(view.getContext(), R.color.text_999999));
|
||||
view.setText("-");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
@ -18,7 +19,10 @@ import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.synthetic.main.dialog_game_off_service.*
|
||||
|
||||
// 游戏关闭下载弹窗
|
||||
class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
|
||||
class GameOffServiceDialogFragment
|
||||
// : BaseTrackableDialogFragment()
|
||||
:BaseDialogFragment() {
|
||||
|
||||
private var mDialog: GameEntity.Dialog? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
@ -42,7 +46,7 @@ class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
|
||||
siteTv.text = site.text
|
||||
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
siteTv.setOnClickListener {
|
||||
MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
// MtaHelper.onEvent("游戏下载状态按钮", getKey(), site.text)
|
||||
DirectUtils.directToWebView(requireContext(), site.url, "(关闭下载弹窗)")
|
||||
dismiss()
|
||||
}
|
||||
@ -52,13 +56,13 @@ class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEvent(): String {
|
||||
return "游戏下载状态按钮"
|
||||
}
|
||||
|
||||
override fun getKey(): String {
|
||||
return "查看详情弹窗"
|
||||
}
|
||||
// override fun getEvent(): String {
|
||||
// return "游戏下载状态按钮"
|
||||
// }
|
||||
//
|
||||
// override fun getKey(): String {
|
||||
// return "查看详情弹窗"
|
||||
// }
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
|
||||
@ -4,16 +4,17 @@ import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.common.repository.ReservationRepository
|
||||
@ -23,29 +24,58 @@ import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
// 预约弹窗
|
||||
class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
class ReserveDialogFragment
|
||||
: BaseDialogFragment(), KeyboardHeightObserver {
|
||||
// : BaseTrackableDialogFragment() {
|
||||
|
||||
@BindView(R.id.reserve_hint_tv)
|
||||
lateinit var reserveHintTv: TextView
|
||||
|
||||
@BindView(R.id.reserve_content_tv)
|
||||
lateinit var reserveContentTv: TextView
|
||||
|
||||
@BindView(R.id.reserve_completed_content_tv)
|
||||
lateinit var reserveCompletedContentTv: TextView
|
||||
|
||||
@BindView(R.id.mobile_et)
|
||||
lateinit var mobileEt: EditText
|
||||
|
||||
@BindView(R.id.reserve_container)
|
||||
lateinit var reserveContainer: View
|
||||
|
||||
@BindView(R.id.reserve_completed_container)
|
||||
lateinit var reserveCompletedContainer: View
|
||||
|
||||
@BindView(R.id.customizable_btn)
|
||||
lateinit var customizableBtn: TextView
|
||||
|
||||
@BindView(R.id.content_container)
|
||||
lateinit var contentContainer: View
|
||||
|
||||
@BindView(R.id.mobile_index_container)
|
||||
lateinit var mobileIndexContainer: View
|
||||
|
||||
@BindView(R.id.mobile_index_reserve)
|
||||
lateinit var mobileIndexReserve: TextView
|
||||
|
||||
@BindView(R.id.mobile_index_user)
|
||||
lateinit var mobileIndexUser: TextView
|
||||
|
||||
@BindView(R.id.mobile_et_delete)
|
||||
lateinit var mobileEtDelete: View
|
||||
|
||||
@BindView(R.id.layout_container)
|
||||
lateinit var layoutContainer: View
|
||||
|
||||
private lateinit var mViewModel: ReserveViewModel
|
||||
|
||||
private var mSuccessCallback: SuccessCallback? = null
|
||||
@ -54,23 +84,32 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
private var mGameId: String = ""
|
||||
private var mGameName: String = ""
|
||||
|
||||
private var mKeyboardHeightProvider: KeyboardHeightProvider? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mViewModel = viewModelProvider()
|
||||
mKeyboardHeightProvider = KeyboardHeightProvider(activity)
|
||||
mKeyboardHeightProvider?.start()
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_reserve_game, null)
|
||||
}
|
||||
|
||||
override fun getEvent(): String {
|
||||
return "预约游戏"
|
||||
}
|
||||
|
||||
override fun getKey(): String {
|
||||
return "预约功能操作"
|
||||
}
|
||||
// override fun getEvent(): String {
|
||||
// return "预约游戏"
|
||||
// }
|
||||
//
|
||||
// override fun getKey(): String {
|
||||
// return "预约功能操作"
|
||||
// }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("SetTextI18n")
|
||||
@ -78,11 +117,14 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
ButterKnife.bind(this, view)
|
||||
|
||||
val reserveContent = "游戏上线,您将<font color='#ff4147'>免费</font>收到短信提醒"
|
||||
|
||||
val reserveContent = "游戏上线,您将收到<font color='#1383EB'>免费短信</font>提醒"
|
||||
reserveContentTv.text = Html.fromHtml(reserveContent)
|
||||
mobileEt.setText(UserManager.getInstance().userInfoEntity.mobile)
|
||||
mobileEt.setSelection(mobileEt.text.length)
|
||||
|
||||
|
||||
mobileEt.setTextChangedListener { s, _, _, _ ->
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
mobileEtDelete.goneIf(s.trim().isEmpty())
|
||||
}
|
||||
|
||||
mViewModel.reservation.observeNonNull(this) {
|
||||
if (it.success) {
|
||||
@ -91,6 +133,11 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
HistoryHelper.insertGameEntity(mGame!!)
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel.reserveMobile.observe(viewLifecycleOwner, Observer {
|
||||
setMobileIndexHint(it)
|
||||
})
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
|
||||
@ -109,7 +156,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
} else {
|
||||
customizableBtn.text = dialogConfig?.text
|
||||
customizableBtn.setOnClickListener {
|
||||
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击跳转按钮")
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击跳转按钮")
|
||||
DirectUtils.directToLinkPage(
|
||||
requireContext(),
|
||||
dialogConfig!!.toLinkEntity(),
|
||||
@ -120,32 +167,126 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMobileIndexHint(reserveMobile: String?) {
|
||||
var userMobile = UserManager.getInstance().userInfoEntity.mobile
|
||||
if (reserveMobile == userMobile) userMobile = null
|
||||
|
||||
if (!reserveMobile.isNullOrEmpty()) {
|
||||
mobileIndexReserve.visibility = View.VISIBLE
|
||||
mobileIndexReserve.text = reserveMobile
|
||||
} else {
|
||||
mobileIndexReserve.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (!userMobile.isNullOrEmpty()) {
|
||||
mobileIndexUser.visibility = View.VISIBLE
|
||||
mobileIndexUser.text = userMobile
|
||||
} else {
|
||||
mobileIndexUser.visibility = View.GONE
|
||||
}
|
||||
mobileIndexContainer.goneIf(mobileIndexUser.visibility == View.GONE && mobileIndexReserve.visibility == View.GONE)
|
||||
if (mobileIndexContainer.visibility ==View.VISIBLE) {
|
||||
mobileIndexContainer.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.reserve_dialog_index_anim)
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.reserve_with_mobile_btn,
|
||||
R.id.reserve_without_mobile_btn,
|
||||
R.id.content_container,
|
||||
R.id.close_btn,
|
||||
R.id.customizable_btn)
|
||||
R.id.customizable_btn,
|
||||
R.id.mobile_index_reserve,
|
||||
R.id.mobile_index_user,
|
||||
R.id.mobile_et_delete,
|
||||
R.id.mobile_et,
|
||||
R.id.layout_container)
|
||||
fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.reserve_without_mobile_btn -> {
|
||||
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击无手机号预约")
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击无手机号预约")
|
||||
if (mobileIndexContainer.visibility == View.VISIBLE) {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
|
||||
mViewModel.reserve(gameId = mGameId, gameName = mGameName)
|
||||
}
|
||||
|
||||
R.id.reserve_with_mobile_btn -> {
|
||||
if (mobileIndexContainer.visibility == View.VISIBLE) {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
|
||||
val mobile = mobileEt.text.toString()
|
||||
if (mobile.length < 11 || !mobile.startsWith("1")) {
|
||||
Utils.toast(context, "手机号格式错误,请检查并重新输入")
|
||||
return
|
||||
}
|
||||
|
||||
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击立即预约")
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击立即预约")
|
||||
mViewModel.reserve(gameId = mGameId, gameName = mGameName, mobile = mobile)
|
||||
}
|
||||
|
||||
R.id.close_btn -> {
|
||||
MtaHelper.onEvent("预约游戏", "预约功能操作", "点击关闭")
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击关闭")
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
R.id.content_container -> {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.mobile_index_reserve -> {
|
||||
mobileEt.setText(mobileIndexReserve.text.toString())
|
||||
mobileEt.setSelection(mobileEt.text.length)
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.mobile_index_user -> {
|
||||
mobileEt.setText(mobileIndexUser.text.toString())
|
||||
mobileEt.setSelection(mobileEt.text.length)
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.mobile_et_delete -> {
|
||||
mobileEt.setText("")
|
||||
}
|
||||
R.id.mobile_et -> {
|
||||
mobileIndexContainer.visibility = View.GONE
|
||||
}
|
||||
R.id.layout_container -> {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (HaloApp.getInstance().mCacheKeyboardHeight > 0) {
|
||||
val attributes = dialog?.window?.attributes
|
||||
val heightPixels = requireContext().resources.displayMetrics.heightPixels
|
||||
val mCacheKeyboardHeight = HaloApp.getInstance().mCacheKeyboardHeight
|
||||
val statusBarHeight = DisplayUtils.getStatusBarHeight(requireContext().resources)
|
||||
dialog?.window?.attributes?.height = heightPixels - mCacheKeyboardHeight - statusBarHeight
|
||||
attributes?.gravity = Gravity.TOP
|
||||
dialog?.window?.attributes = attributes
|
||||
}
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mKeyboardHeightProvider?.setKeyboardHeightObserver(null)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mKeyboardHeightProvider?.close()
|
||||
}
|
||||
|
||||
override fun onKeyboardHeightChanged(height: Int, orientation: Int) {
|
||||
if (height > 0) {
|
||||
val attributes = dialog?.window?.attributes
|
||||
attributes?.gravity = Gravity.CENTER
|
||||
dialog?.window?.attributes = attributes
|
||||
HaloApp.getInstance().mCacheKeyboardHeight = height
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,6 +308,12 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
class ReserveViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val reservation = MutableLiveData<Reservation>()
|
||||
|
||||
val reserveMobile = MutableLiveData<String>()
|
||||
|
||||
init {
|
||||
getAppointmentMobile()
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun reserve(gameId: String, gameName: String, mobile: String = "") {
|
||||
|
||||
@ -189,7 +336,7 @@ class ReserveViewModel(application: Application) : AndroidViewModel(application)
|
||||
reservation.postValue(Reservation(success = true, withMobile = mobile.isNotEmpty(), boundWechat = boundWechat))
|
||||
ReservationRepository.addReservationToMemoryAndRefresh(gameId)
|
||||
|
||||
MtaHelper.onEvent("预约游戏", "预约", gameName)
|
||||
// MtaHelper.onEvent("预约游戏", "预约", gameName)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
@ -198,5 +345,30 @@ class ReserveViewModel(application: Application) : AndroidViewModel(application)
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun getAppointmentMobile() {
|
||||
RetrofitManager.getInstance(getApplication()).api
|
||||
.getAppointmentMobile(UserManager.getInstance().userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
var mobile: String? = null
|
||||
tryCatchInRelease {
|
||||
val jsonArray = JSONArray(data.string())
|
||||
if (jsonArray.length() > 0) {
|
||||
mobile = jsonArray.get(0).toString()
|
||||
}
|
||||
}
|
||||
|
||||
reserveMobile.postValue(mobile)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
reserveMobile.postValue(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
class Reservation(var success: Boolean = false, var withMobile: Boolean = false, var boundWechat: Boolean = false)
|
||||
}
|
||||
@ -11,8 +11,15 @@ data class ExposureEntity(
|
||||
@SerializedName("game_id")
|
||||
val gameId: String? = "",
|
||||
val gameName: String? = "",
|
||||
val gameVersion: String? = "",
|
||||
val sequence: Int? = 0,
|
||||
val platform: String? = "",
|
||||
val downloadType: String? = "",
|
||||
val downloadCompleteType: String? = ""
|
||||
val downloadCompleteType: String? = "",
|
||||
|
||||
// 统计启动弹窗相关数据用的 (ugly)
|
||||
@SerializedName("dialog_id")
|
||||
var welcomeDialogId: String? = "",
|
||||
@SerializedName("link_title")
|
||||
var welcomeDialogLinkTitle: String? = ""
|
||||
) : Parcelable
|
||||
@ -8,6 +8,7 @@ import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
import com.gh.common.util.getFirstElementDividedByDivider
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
@ -27,13 +28,21 @@ data class ExposureEvent(
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
if (gameEntity?.getApk()?.size == 1) {
|
||||
gameEntity.gameVersion = gameEntity.getApk().elementAtOrNull(0)?.version ?: ""
|
||||
}
|
||||
return ExposureEvent(
|
||||
payload = ExposureEntity(gameId = gameEntity?.id,
|
||||
payload = ExposureEntity(
|
||||
gameId = gameEntity?.id?.getFirstElementDividedByDivider(Constants.GAME_ID_DIVIDER),
|
||||
gameName = gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = gameEntity?.gameVersion,
|
||||
sequence = gameEntity?.sequence,
|
||||
platform = gameEntity?.platform,
|
||||
downloadType = gameEntity?.downloadType,
|
||||
downloadCompleteType = gameEntity?.downloadCompleteType),
|
||||
downloadCompleteType = gameEntity?.downloadCompleteType,
|
||||
// ugly
|
||||
welcomeDialogId = gameEntity?.welcomeDialogId ?: eTrace?.firstOrNull()?.payload?.welcomeDialogId,
|
||||
welcomeDialogLinkTitle = gameEntity?.welcomeDialogTitle ?: eTrace?.firstOrNull()?.payload?.welcomeDialogLinkTitle),
|
||||
source = source,
|
||||
eTrace = eTrace,
|
||||
event = event).apply { gameEntity?.exposureEvent = this }
|
||||
|
||||
@ -26,6 +26,10 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
|
||||
visibleState?.let { commitExposure(it) }
|
||||
throttleBus?.clear()
|
||||
}
|
||||
|
||||
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
|
||||
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import com.gh.loghub.LoghubHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
/**
|
||||
* A handful tool for committing logs to aliyun loghub.
|
||||
@ -17,7 +16,7 @@ import kotlin.concurrent.fixedRateTimer
|
||||
* 如何简单地统计列表中每个 item 的曝光事件?
|
||||
*
|
||||
* 1. Adapter 实现 IExposable 接口,在 BindView 阶段更新 ExposureEvent,ExposureEvent 供 getEventByPosition(pos) 方法获取用
|
||||
* 2. 构建一个 ExposureListener 并作为入参添加至 recyclerview 的 Scroll 回调中
|
||||
* 2. 构建一个 ExposureListener 并作为入参添加至 recyclerview 的 onScroll 回调中
|
||||
* 3. 没了
|
||||
*/
|
||||
object ExposureManager {
|
||||
@ -25,7 +24,6 @@ object ExposureManager {
|
||||
private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com"
|
||||
private const val PROJECT = "ghzs"
|
||||
private const val STORE_SIZE = 100
|
||||
private const val STORE_FORCE_UPLOAD_PERIOD = 300 * 1000L
|
||||
private const val LOG_STORE = BuildConfig.EXPOSURE_REPO
|
||||
|
||||
private val loghubHelper = LoghubHelper.getInstance()
|
||||
@ -38,18 +36,12 @@ object ExposureManager {
|
||||
|
||||
@JvmStatic
|
||||
fun init() {
|
||||
TimeUtil.init()
|
||||
|
||||
loghubHelper.init(HaloApp.getInstance().application, ENDPOINT, PROJECT, LOG_STORE) { TimeUtil.currentTimeMillis() }
|
||||
|
||||
exposureExecutor.execute {
|
||||
val eventList = exposureDao.getAll()
|
||||
exposureSet.addAll(eventList)
|
||||
}
|
||||
|
||||
fixedRateTimer(name = "ExposureManager-Store-Checker", initialDelay = 500, period = STORE_FORCE_UPLOAD_PERIOD) {
|
||||
commitSavedExposureEvents(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.g00fy2.versioncompare.Version
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.PackageUtils
|
||||
@ -22,6 +23,7 @@ object ExposureUtils {
|
||||
} else {
|
||||
entity.id
|
||||
}
|
||||
gameEntity.gameVersion = entity.getApk().elementAtOrNull(0)?.version ?: gameEntity.gameVersion
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadType = downloadType.toString()
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
@ -63,7 +65,11 @@ object ExposureUtils {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DownloadType.PLUGIN_DOWNLOAD
|
||||
if (!TextUtils.isEmpty(apkEntity.ghVersion)) {
|
||||
DownloadType.PLUGIN_DOWNLOAD
|
||||
} else {
|
||||
DownloadType.UPDATE
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DownloadType.DOWNLOAD
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
package com.gh.common.exposure.time
|
||||
|
||||
import com.gh.gamecenter.entity.TimeEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
class Corrector {
|
||||
|
||||
companion object {
|
||||
const val TIME_CORRECTOR_ADJUST_PERIOD: Long = 600000
|
||||
}
|
||||
|
||||
var delta: Long = 0
|
||||
|
||||
init {
|
||||
fixedRateTimer("TimeUtil-Corrector-Checker", initialDelay = 0, period = TIME_CORRECTOR_ADJUST_PERIOD) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<TimeEntity>() {
|
||||
override fun onResponse(response: TimeEntity?) {
|
||||
val serverTime = response?.time
|
||||
serverTime?.let { delta = it * 1000 - System.currentTimeMillis() }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,15 @@
|
||||
package com.gh.common.exposure.time
|
||||
|
||||
import com.gh.common.FixedRateJobHelper
|
||||
|
||||
object TimeUtil {
|
||||
|
||||
private lateinit var corrector: Corrector
|
||||
|
||||
fun init() {
|
||||
corrector = Corrector()
|
||||
}
|
||||
|
||||
fun currentTimeMillis(): Long {
|
||||
return corrector.delta + System.currentTimeMillis()
|
||||
return FixedRateJobHelper.timeDeltaBetweenServerAndClient + System.currentTimeMillis()
|
||||
}
|
||||
|
||||
fun currentTime(): Int {
|
||||
return if (::corrector.isInitialized) {
|
||||
((corrector.delta + System.currentTimeMillis()) / 1000).toInt()
|
||||
} else {
|
||||
(System.currentTimeMillis() / 1000).toInt()
|
||||
}
|
||||
return ((FixedRateJobHelper.timeDeltaBetweenServerAndClient + System.currentTimeMillis()) / 1000).toInt()
|
||||
}
|
||||
|
||||
}
|
||||
21
app/src/main/java/com/gh/common/filter/RegionSetting.kt
Normal file
21
app/src/main/java/com/gh/common/filter/RegionSetting.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package com.gh.common.filter
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class RegionSetting(
|
||||
@SerializedName("game_mirror")
|
||||
var mirrorGameIdSet: HashSet<String>,
|
||||
@SerializedName("game_block")
|
||||
var filterGameIdSet: HashSet<String>,
|
||||
@SerializedName("channel_control")
|
||||
var channelControl: ChannelControl) {
|
||||
|
||||
@Keep
|
||||
data class ChannelControl(
|
||||
@SerializedName("game_category")
|
||||
var gameCategory: String,
|
||||
@SerializedName("effect")
|
||||
var effect: Boolean)
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
package com.gh.common.filter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.Function
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
object RegionSettingHelper {
|
||||
|
||||
private var mChannelControl: RegionSetting.ChannelControl? = null
|
||||
private var mFilterGameIdSet: HashSet<String>? = hashSetOf()
|
||||
private var mDisplayMirrorIfoGameIdSet: HashSet<String>? = hashSetOf()
|
||||
|
||||
private const val SP_SETTING = "region_setting"
|
||||
|
||||
fun shouldThisGameDisplayMirrorInfo(gameId: String): Boolean {
|
||||
return mDisplayMirrorIfoGameIdSet?.contains(gameId) ?: false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldThisGameBeFiltered(gameId: String?): Boolean {
|
||||
return mFilterGameIdSet?.contains(gameId) ?: false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun filterGame(list: List<GameEntity>?): ArrayList<GameEntity> {
|
||||
if (list == null) return arrayListOf()
|
||||
|
||||
if (mFilterGameIdSet?.isEmpty() == true) {
|
||||
if (list is ArrayList) return list
|
||||
}
|
||||
|
||||
val listCopy: ArrayList<GameEntity> = if (list is ArrayList) list else ArrayList(list)
|
||||
listCopy.removeAll { mFilterGameIdSet?.contains(it.id) ?: false }
|
||||
return listCopy
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var filterGame = Function { list: List<GameEntity> ->
|
||||
filterGame(list)
|
||||
list
|
||||
}
|
||||
|
||||
fun shouldGameOfThisCategoryUseMirrorInfo(category: String) : Boolean {
|
||||
return if (mChannelControl == null || mChannelControl?.effect == false || !isUserUsedLessThan24Hours()) {
|
||||
false
|
||||
} else {
|
||||
mChannelControl?.gameCategory == category
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun getRegionSetting() {
|
||||
// 使用默认的 Schdulers.io() 可能会触发 OOM
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.sensitiveApi
|
||||
.getRegionSetting(HaloApp.getInstance().channel)
|
||||
.subscribeOn(AppExecutor.cachedScheduler)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<RegionSetting>() {
|
||||
override fun onSuccess(data: RegionSetting) {
|
||||
updateSettingsInMemory(data)
|
||||
SPUtils.setString(SP_SETTING, data.toJson())
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
SPUtils.getString(SP_SETTING).toObject<RegionSetting>()?.let {
|
||||
updateSettingsInMemory(it)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateSettingsInMemory(data: RegionSetting) {
|
||||
mFilterGameIdSet = data.filterGameIdSet
|
||||
mDisplayMirrorIfoGameIdSet = data.mirrorGameIdSet
|
||||
mChannelControl = data.channelControl
|
||||
}
|
||||
|
||||
/**
|
||||
* 该用户是否是使用了不到 24 小时的新用户
|
||||
*/
|
||||
private fun isUserUsedLessThan24Hours(): Boolean {
|
||||
val initialUsageTime = SPUtils.getLong(Constants.SP_INITIAL_USAGE_TIME, 0)
|
||||
return !(initialUsageTime == 0L || System.currentTimeMillis() - initialUsageTime > 86400000)
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,7 +15,7 @@ import com.gh.gamecenter.room.converter.*
|
||||
import com.gh.gamecenter.room.dao.*
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 5, exportSchema = false)
|
||||
@Database(entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class], version = 7, exportSchema = false)
|
||||
@TypeConverters(CountConverter::class,
|
||||
CommunityConverter::class,
|
||||
TimeConverter::class,
|
||||
@ -23,7 +23,8 @@ import com.halo.assistant.HaloApp
|
||||
ThumbnailConverter::class,
|
||||
TagStyleListConverter::class,
|
||||
StringArrayListConverter::class,
|
||||
CommunityVideoConverter::class)
|
||||
CommunityVideoConverter::class,
|
||||
UserConverter::class)
|
||||
|
||||
abstract class HistoryDatabase : RoomDatabase() {
|
||||
|
||||
@ -54,11 +55,27 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_5_6: Migration = object : Migration(5, 6) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE MyVideoEntity add title TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("Alter TABLE MyVideoEntity add commentCount INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("Alter TABLE MyVideoEntity add user TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_6_7: Migration = object : Migration(6, 7) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter TABLE HistoryGameEntity add iconSubscript TEXT DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
val instance by lazy {
|
||||
Room.databaseBuilder(HaloApp.getInstance().application, HistoryDatabase::class.java, "USER_TRACK_HISTORY_DATABASE")
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.addMigrations(MIGRATION_3_4)
|
||||
.addMigrations(MIGRATION_4_5)
|
||||
.addMigrations(MIGRATION_5_6)
|
||||
.addMigrations(MIGRATION_6_7)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,8 @@ object HistoryHelper {
|
||||
historyGame.id = updateEntity.id
|
||||
historyGame.brief = updateEntity.brief
|
||||
historyGame.des = ""
|
||||
historyGame.icon = updateEntity.icon
|
||||
historyGame.icon = updateEntity.rawIcon ?: updateEntity.icon
|
||||
historyGame.iconSubscript = historyGame.iconSubscript
|
||||
historyGame.name = updateEntity.name
|
||||
historyGame.tagStyle = updateEntity.tagStyle
|
||||
historyGame.tag = updateEntity.tag
|
||||
@ -55,11 +56,11 @@ object HistoryHelper {
|
||||
historyGame.id = gameEntity.id
|
||||
historyGame.brief = gameEntity.brief
|
||||
historyGame.des = gameEntity.des
|
||||
historyGame.icon = gameEntity.icon
|
||||
historyGame.icon = gameEntity.rawIcon ?: gameEntity.icon
|
||||
historyGame.iconSubscript = gameEntity.iconSubscript
|
||||
historyGame.name = gameEntity.name
|
||||
historyGame.tagStyle = gameEntity.tagStyle
|
||||
historyGame.tag = gameEntity.getTag()
|
||||
historyGame.isLibaoExist = gameEntity.isLibaoExists
|
||||
return historyGame
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
package com.gh.common.loghub
|
||||
|
||||
import android.app.Application
|
||||
import androidx.annotation.Keep
|
||||
import com.aliyun.sls.android.sdk.model.Log
|
||||
import com.aliyun.sls.android.sdk.model.LogGroup
|
||||
import com.gh.common.exposure.ExposureEntity
|
||||
import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.loghub.LoghubHelper
|
||||
import org.json.JSONObject
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.concurrent.fixedRateTimer
|
||||
|
||||
object LoghubUtils {
|
||||
|
||||
private const val STORE_SIZE = 100
|
||||
private const val STORE_FORCE_UPLOAD_INTERVAL = 120 * 1000L
|
||||
|
||||
private lateinit var mApplication: Application
|
||||
|
||||
private val loghubEventSet by lazy { hashSetOf<LoghubEvent>() }
|
||||
@ -27,10 +27,6 @@ object LoghubUtils {
|
||||
val eventList = loghubEventDao.getAll()
|
||||
loghubEventSet.addAll(eventList)
|
||||
}
|
||||
|
||||
fixedRateTimer(name = "Loghub-Event-Checker", initialDelay = 1000, period = STORE_FORCE_UPLOAD_INTERVAL) {
|
||||
commitSavedLoghubEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -50,11 +46,28 @@ object LoghubUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun log(jsonString: String, logStore: String, forcedUpload: Boolean) {
|
||||
loghubEventExecutor.execute {
|
||||
try {
|
||||
val event = LoghubEvent(time = (System.currentTimeMillis() / 1000L).toString(), content = jsonString, logStore = logStore)
|
||||
loghubEventSet.add(event)
|
||||
loghubEventDao.insert(event)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
if (forcedUpload || loghubEventSet.size >= STORE_SIZE) {
|
||||
commitSavedLoghubEvents()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadLogGroup(logGroup: LogGroup, logStore: String) {
|
||||
LoghubHelper.getInstance().uploadLogGroup(logGroup, logStore)
|
||||
}
|
||||
|
||||
private fun commitSavedLoghubEvents() {
|
||||
fun commitSavedLoghubEvents() {
|
||||
loghubEventExecutor.execute {
|
||||
if (loghubEventSet.isEmpty()) return@execute
|
||||
|
||||
@ -93,4 +106,12 @@ object LoghubUtils {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
data class SimpleLogContainerEntity(
|
||||
var event: String? = null,
|
||||
var action: String? = null,
|
||||
var meta: Meta? = null,
|
||||
var payload: ExposureEntity? = null,
|
||||
var timestamp: Long? = 0)
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.repository
|
||||
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.common.util.ApkActiveUtils
|
||||
import com.gh.common.util.RandomUtils
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
@ -15,7 +16,8 @@ object RemenkapaiRepository {
|
||||
@JvmStatic
|
||||
fun getRemenkapai(size: Int): Observable<List<GameEntity>> {
|
||||
return if (remenkapaiList.isEmpty()) {
|
||||
RetrofitManager.getInstance(getApplication()).api.remenkapai
|
||||
RetrofitManager.getInstance(getApplication()).sensitiveApi.remenkapai
|
||||
.map(RegionSettingHelper.filterGame)
|
||||
.map { gameList -> filterEntityWithoutApk(gameList) }
|
||||
.map { pickRandomSizeEntity(size) }
|
||||
.map(ApkActiveUtils.filterMapperList)
|
||||
|
||||
14
app/src/main/java/com/gh/common/util/AntiBotHelper.kt
Normal file
14
app/src/main/java/com/gh/common/util/AntiBotHelper.kt
Normal file
@ -0,0 +1,14 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.alibaba.wireless.security.jaq.avmp.IJAQAVMPSignComponent
|
||||
import com.alibaba.wireless.security.open.SecurityGuardManager
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object AntiBotHelper {
|
||||
@JvmStatic
|
||||
val manager by lazy {
|
||||
SecurityGuardManager.getInstance(HaloApp.getInstance().application).getInterface(IJAQAVMPSignComponent::class.java).apply {
|
||||
this.initialize()
|
||||
}
|
||||
}
|
||||
}
|
||||
6
app/src/main/java/com/gh/common/util/BiCallback.kt
Normal file
6
app/src/main/java/com/gh/common/util/BiCallback.kt
Normal file
@ -0,0 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
interface BiCallback<FIRST, SECOND> {
|
||||
fun onFirst(first: FIRST)
|
||||
fun onSecond(second: SECOND)
|
||||
}
|
||||
@ -1,14 +1,19 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.gh.common.util.CommentUtils.copyText
|
||||
import com.gh.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.CommentDetailActivity
|
||||
import com.gh.gamecenter.MessageDetailActivity
|
||||
import com.gh.gamecenter.adapter.OnCommentCallBackListener
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.CommentEntity
|
||||
import com.gh.gamecenter.entity.MeEntity
|
||||
import com.gh.gamecenter.entity.Permissions
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.comment.OnCommentOptionClickListener
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.lightgame.utils.Utils
|
||||
@ -23,13 +28,13 @@ import retrofit2.HttpException
|
||||
object CommentHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun showCommunityArticleCommentOptions(context: Context,
|
||||
fun showCommunityArticleCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
articleId: String,
|
||||
communityId: String,
|
||||
listener: OnCommentCallBackListener?) {
|
||||
showCommentOptions(context = context,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
articleId = articleId,
|
||||
@ -38,12 +43,12 @@ object CommentHelper {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showAnswerCommentOptions(context: Context,
|
||||
fun showAnswerCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
answerId: String,
|
||||
listener: OnCommentCallBackListener?) {
|
||||
showCommentOptions(context = context,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
answerId = answerId,
|
||||
@ -51,27 +56,34 @@ object CommentHelper {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showVideoCommentOptions(context: Context,
|
||||
fun showVideoCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
videoId: String,
|
||||
listener: OnCommentCallBackListener?) {
|
||||
showCommentOptions(context = context,
|
||||
isVideoAuthor: Boolean,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
videoId = videoId,
|
||||
isVideoAuthor = isVideoAuthor,
|
||||
listener = listener)
|
||||
}
|
||||
|
||||
private fun showCommentOptions(context: Context,
|
||||
private fun showCommentOptions(view: View,
|
||||
commentEntity: CommentEntity,
|
||||
showConversation: Boolean,
|
||||
articleId: String? = null,
|
||||
communityId: String? = null,
|
||||
answerId: String? = null,
|
||||
videoId: String? = null,
|
||||
listener: OnCommentCallBackListener? = null) {
|
||||
isVideoAuthor: Boolean = false,
|
||||
listener: OnCommentOptionClickListener? = null) {
|
||||
val context = view.context
|
||||
val dialogOptions = ArrayList<String>()
|
||||
if (isVideoAuthor || (videoId != null && commentEntity.user.id == UserManager.getInstance().userId)) {
|
||||
dialogOptions.add("删除评论")
|
||||
}
|
||||
dialogOptions.add("复制")
|
||||
dialogOptions.add("投诉")
|
||||
|
||||
@ -88,55 +100,75 @@ object CommentHelper {
|
||||
dialogOptions.add("查看对话")
|
||||
}
|
||||
|
||||
DialogUtils.showListDialog(context, dialogOptions, null) {
|
||||
when (it) {
|
||||
"管理" -> showControlDialog(context, answerId, articleId, communityId, commentEntity, commentEntity.me!!)
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val layout = inflater.inflate(R.layout.comment_more_option, null)
|
||||
val popupWindow = BugFixedPopupWindow(layout,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
val container = layout.findViewById<LinearLayout>(R.id.container)
|
||||
for (text in dialogOptions) {
|
||||
val item = inflater.inflate(R.layout.comment_more_option_item, container, false)
|
||||
container.addView(item)
|
||||
|
||||
"复制" -> copyText(commentEntity.content, context)
|
||||
val hitText = item.findViewById<TextView>(R.id.hint_text)
|
||||
hitText.text = text
|
||||
|
||||
"投诉" -> {
|
||||
context.ifLogin("回答详情-评论-投诉") {
|
||||
showReportTypeDialog(context) { reportType ->
|
||||
item.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
listener?.onCommentOptionClick(commentEntity, text)
|
||||
when (text) {
|
||||
"管理" -> showControlDialog(context, answerId, articleId, communityId, commentEntity, commentEntity.me!!)
|
||||
|
||||
val commentListener = object : PostCommentUtils.PostCommentListener {
|
||||
override fun postSuccess(response: JSONObject?) {
|
||||
Utils.toast(context, "感谢您的投诉")
|
||||
}
|
||||
"复制" -> copyText(commentEntity.content, context)
|
||||
|
||||
override fun postFailed(error: Throwable?) {
|
||||
if (error == null) {
|
||||
Utils.toast(context, "投诉失败,请稍后重试")
|
||||
} else {
|
||||
Utils.toast(context, "投诉失败,${error.message}")
|
||||
"投诉" -> {
|
||||
context.ifLogin("回答详情-评论-投诉") {
|
||||
showReportTypeDialog(context) { reportType ->
|
||||
|
||||
val commentListener = object : PostCommentUtils.PostCommentListener {
|
||||
override fun postSuccess(response: JSONObject?) {
|
||||
Utils.toast(context, "感谢您的投诉")
|
||||
}
|
||||
|
||||
override fun postFailed(error: Throwable?) {
|
||||
if (error == null) {
|
||||
Utils.toast(context, "投诉失败,请稍后重试")
|
||||
} else {
|
||||
Utils.toast(context, "投诉失败,${error.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (answerId != null) {
|
||||
PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType, commentListener)
|
||||
} else if (articleId != null) {
|
||||
PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType, commentListener)
|
||||
} else {
|
||||
PostCommentUtils.reportVideoComment(context, videoId, commentEntity.id, reportType, commentListener)
|
||||
if (answerId != null) {
|
||||
PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType, commentListener)
|
||||
} else if (articleId != null) {
|
||||
PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType, commentListener)
|
||||
} else {
|
||||
PostCommentUtils.reportVideoComment(context, videoId, commentEntity.id, reportType, commentListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"查看对话" -> {
|
||||
if (answerId != null) {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getAnswerCommentIntent(context, commentEntity.id, answerId, null))
|
||||
} else if (articleId != null) {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null))
|
||||
} else {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getVideoCommentIntent(context, commentEntity.id, videoId, null))
|
||||
"查看对话" -> {
|
||||
if (answerId != null) {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getAnswerCommentIntent(context, commentEntity.id, answerId, null))
|
||||
} else if (articleId != null) {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null))
|
||||
} else {
|
||||
context.startActivity(CommentDetailActivity
|
||||
.getVideoCommentIntent(context, commentEntity.id, videoId, isVideoAuthor, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
popupWindow.isTouchable = true
|
||||
popupWindow.isFocusable = true
|
||||
|
||||
popupWindow.showAutoOrientation(view)
|
||||
}
|
||||
|
||||
private fun showControlDialog(context: Context,
|
||||
|
||||
@ -6,7 +6,7 @@ import android.widget.LinearLayout;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.gamecenter.ViewImageActivity;
|
||||
import com.gh.gamecenter.ImageViewerActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -93,7 +93,7 @@ public class ConcernContentUtils {
|
||||
break;
|
||||
}
|
||||
imageView.setOnClickListener(v -> {
|
||||
Intent checkIntent = ViewImageActivity.getViewImageIntent(context, (ArrayList<String>) list, position, entrance);
|
||||
Intent checkIntent = ImageViewerActivity.getIntent(context, (ArrayList<String>) list, position, entrance);
|
||||
context.startActivity(checkIntent);
|
||||
});
|
||||
return imageView;
|
||||
|
||||
@ -20,12 +20,13 @@ import java.util.Map;
|
||||
public class DataLogUtils {
|
||||
|
||||
// 轮播图
|
||||
public static void uploadLunbotuLog(Context context, String type, String text, String index, String source) {
|
||||
public static void uploadLunbotuLog(Context context, String type, String text, String title, String index, String source) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("index", index);
|
||||
map.put("type", type);
|
||||
map.put("text", text);
|
||||
map.put("source", source);
|
||||
map.put("slide_title", title);
|
||||
uploadLog(context, "slide", map);
|
||||
}
|
||||
|
||||
|
||||
@ -3,19 +3,16 @@ package com.gh.common.util;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gid.GidCallback;
|
||||
import com.gh.gid.GidHelper;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.tencent.bugly.crashreport.CrashReport;
|
||||
import com.tencent.stat.MtaSDkException;
|
||||
@ -126,11 +123,18 @@ public class DataUtils {
|
||||
public static void getGid() {
|
||||
GidHelper.getInstance().registerDevice(new GidCallback() {
|
||||
@Override
|
||||
public void onSuccess(String s) {
|
||||
Utils.log("Gid", s);
|
||||
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, s).apply();
|
||||
public void onSuccess(String gid) {
|
||||
Utils.log("Gid", gid);
|
||||
PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().getApplication()).edit().putString(Constants.DEVICE_KEY, gid).apply();
|
||||
|
||||
String originalGid = HaloApp.getInstance().getGid();
|
||||
HaloApp.getInstance().setGid(gid);
|
||||
|
||||
// 避免重复调用
|
||||
if (!TextUtils.isEmpty(gid) && !gid.equals(originalGid)) {
|
||||
GameSubstituteRepositoryHelper.updateSubstitutableGames();
|
||||
}
|
||||
|
||||
HaloApp.getInstance().setGid(s);
|
||||
// 避免初始化顺序问题导致 MetaUtil 一直持有空的 gid
|
||||
MetaUtil.INSTANCE.refreshMeta();
|
||||
}
|
||||
@ -197,36 +201,36 @@ public class DataUtils {
|
||||
|
||||
// 游戏下载
|
||||
public static void onGameDownloadEvent(Context context, String gameName, String platform, String entrance, String status, String method) {
|
||||
Map<String, Object> kv = new HashMap<>();
|
||||
|
||||
platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
|
||||
|
||||
kv.put("版本", platform);
|
||||
kv.put("用户机型", Build.MODEL);
|
||||
kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
|
||||
kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
kv.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
kv.put("位置", entrance);
|
||||
kv.put("类型", method);
|
||||
kv.put("厂商", Build.MANUFACTURER);
|
||||
kv.put("Android版本", Build.VERSION.RELEASE);
|
||||
onEvent(context, "游戏下载", gameName, kv);
|
||||
|
||||
Map<String, Object> kv2 = new HashMap<>();
|
||||
kv2.put("状态", status);
|
||||
kv2.put("位置", entrance);
|
||||
|
||||
if (status.equals("开始")) {
|
||||
kv2.put("版本", entrance + "-开始");
|
||||
kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
|
||||
kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
|
||||
} else {
|
||||
kv2.put("版本", platform);
|
||||
kv2.put("游戏分平台", gameName + "-" + platform);
|
||||
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
}
|
||||
|
||||
onEvent(context, "游戏下载位置", gameName, kv2);
|
||||
// Map<String, Object> kv = new HashMap<>();
|
||||
//
|
||||
// platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(platform);
|
||||
//
|
||||
// kv.put("版本", platform);
|
||||
// kv.put("用户机型", Build.MODEL);
|
||||
// kv.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
|
||||
// kv.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
// kv.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
// kv.put("位置", entrance);
|
||||
// kv.put("类型", method);
|
||||
// kv.put("厂商", Build.MANUFACTURER);
|
||||
// kv.put("Android版本", Build.VERSION.RELEASE);
|
||||
// onEvent(context, "游戏下载", gameName, kv);
|
||||
//
|
||||
// Map<String, Object> kv2 = new HashMap<>();
|
||||
// kv2.put("状态", status);
|
||||
// kv2.put("位置", entrance);
|
||||
//
|
||||
// if (status.equals("开始")) {
|
||||
// kv2.put("版本", entrance + "-开始");
|
||||
// kv2.put("游戏分平台", gameName + "-" + platform + "-开始");
|
||||
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME + "-开始");
|
||||
// } else {
|
||||
// kv2.put("版本", platform);
|
||||
// kv2.put("游戏分平台", gameName + "-" + platform);
|
||||
// kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
// }
|
||||
//
|
||||
// onEvent(context, "游戏下载位置", gameName, kv2);
|
||||
}
|
||||
|
||||
// 游戏更新
|
||||
|
||||
@ -6,6 +6,8 @@ import android.view.View;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
import com.gh.common.view.DownloadProgressBar;
|
||||
import com.gh.common.xapk.XapkInstaller;
|
||||
import com.gh.common.xapk.XapkUnzipStatus;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.DetailViewHolder;
|
||||
@ -13,7 +15,6 @@ import com.gh.gamecenter.entity.LinkEntity;
|
||||
import com.gh.gamecenter.entity.PluginLocation;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
/**
|
||||
* Created by khy on 27/06/17.
|
||||
@ -112,8 +113,18 @@ public class DetailDownloadUtils {
|
||||
}
|
||||
|
||||
public static void detailInvalidate(DetailViewHolder viewHolder) {
|
||||
viewHolder.mDownloadPb.setProgress((int) (viewHolder.downloadEntity.getPercent() * 10));
|
||||
DownloadEntity downloadEntity = viewHolder.downloadEntity;
|
||||
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
|
||||
|
||||
if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
|
||||
String percent = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_PERCENT);
|
||||
viewHolder.mDownloadPb.setText("解压中(" + percent + "%)");
|
||||
viewHolder.mDownloadPb.setProgress((int) (Float.valueOf(percent) * 10));
|
||||
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.XAPK_UNZIPPING);
|
||||
return;
|
||||
}
|
||||
|
||||
viewHolder.mDownloadPb.setProgress((int) (viewHolder.downloadEntity.getPercent() * 10));
|
||||
switch (downloadEntity.getStatus()) {
|
||||
case downloading:
|
||||
case pause:
|
||||
|
||||
@ -11,6 +11,8 @@ import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
import com.tencent.stat.StatConfig;
|
||||
@ -222,8 +224,7 @@ public class DeviceUtils {
|
||||
|
||||
// get sim
|
||||
public static String getSim(Context context) {
|
||||
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
String imsi = tm.getSubscriberId();
|
||||
String imsi = getTelephonySubscriberId(context);
|
||||
if (imsi == null) {
|
||||
return "";
|
||||
}
|
||||
@ -239,6 +240,12 @@ public class DeviceUtils {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getTelephonySubscriberId(Context context) {
|
||||
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
return tm.getSubscriberId();
|
||||
}
|
||||
|
||||
// ping domain
|
||||
public static String ping(String domain) {
|
||||
try {
|
||||
@ -269,18 +276,21 @@ public class DeviceUtils {
|
||||
|
||||
// 只能获取WiFi的IpAddress
|
||||
public static String getCurrentIpAddress() {
|
||||
String ipAddress;
|
||||
WifiManager wifiManager = (WifiManager) HaloApp.getInstance().
|
||||
getApplication().
|
||||
getApplicationContext().
|
||||
getSystemService(Context.WIFI_SERVICE);
|
||||
int address = wifiManager.getDhcpInfo().ipAddress;
|
||||
ipAddress = ((address & 0xFF)
|
||||
+ "." + ((address >> 8) & 0xFF)
|
||||
+ "." + ((address >> 16) & 0xFF)
|
||||
+ "." + ((address >> 24) & 0xFF));
|
||||
return ipAddress;
|
||||
String ipAddress = "0.0.0.0";
|
||||
try {
|
||||
WifiManager wifiManager = (WifiManager) HaloApp.getInstance().
|
||||
getApplication().
|
||||
getApplicationContext().
|
||||
getSystemService(Context.WIFI_SERVICE);
|
||||
int address = wifiManager.getDhcpInfo().ipAddress;
|
||||
ipAddress = ((address & 0xFF)
|
||||
+ "." + ((address >> 8) & 0xFF)
|
||||
+ "." + ((address >> 16) & 0xFF)
|
||||
+ "." + ((address >> 24) & 0xFF));
|
||||
return ipAddress;
|
||||
} catch (Exception e) {
|
||||
return ipAddress;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.CountDownTimer;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Html;
|
||||
@ -40,8 +39,10 @@ import com.gh.common.view.LimitHeightLinearLayout;
|
||||
import com.gh.common.view.MaxHeightNestedScrollView;
|
||||
import com.gh.gamecenter.AboutActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.SuggestionActivity;
|
||||
import com.gh.gamecenter.WebActivity;
|
||||
import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder;
|
||||
import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding;
|
||||
import com.gh.gamecenter.databinding.ImprintContentItemBinding;
|
||||
import com.gh.gamecenter.databinding.PrivacyItemBinding;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
@ -49,9 +50,11 @@ import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.PrivacyPolicyEntity;
|
||||
import com.gh.gamecenter.entity.SettingsEntity;
|
||||
import com.gh.gamecenter.entity.TrackableEntity;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.halo.assistant.fragment.SettingsFragment;
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.AppManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
@ -60,7 +63,6 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
@ -196,7 +198,7 @@ public class DialogUtils {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> Utils.toast(context, "当前使用移动网络下载,请注意流量消耗"), 500);
|
||||
callBack.onResponse(false);
|
||||
} else {
|
||||
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(context), "出现弹窗提示");
|
||||
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(context), "出现弹窗提示");
|
||||
showDownloadDialog(context,
|
||||
() -> callBack.onResponse(false),
|
||||
() -> callBack.onResponse(true));
|
||||
@ -256,12 +258,12 @@ public class DialogUtils {
|
||||
}, 500);
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "本次允许");
|
||||
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "本次允许");
|
||||
});
|
||||
wifiAuto.setOnClickListener(v -> {
|
||||
cancelListener.onCancel();
|
||||
dialog.dismiss();
|
||||
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "连上WiFi后自动下载");
|
||||
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "连上WiFi后自动下载");
|
||||
});
|
||||
allowAlways.setOnClickListener(v -> {
|
||||
PreferenceManager
|
||||
@ -276,7 +278,7 @@ public class DialogUtils {
|
||||
}, 500);
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "总是允许");
|
||||
// MtaHelper.onEvent("移动网络下载", NetworkUtils.getMobileNetworkType(finalContext), "总是允许");
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
@ -1101,6 +1103,21 @@ public class DialogUtils {
|
||||
final ConfirmListener cmListener,
|
||||
final CancelListener clListener,
|
||||
TrackableEntity trackableEntity) {
|
||||
return showTrackableDialog(context, false, title, message, positive, negative, cmListener, clListener, trackableEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useRoundedCornerStyle 使用圆角样式
|
||||
*/
|
||||
public static Dialog showTrackableDialog(Context context,
|
||||
boolean useRoundedCornerStyle,
|
||||
String title,
|
||||
CharSequence message,
|
||||
String positive,
|
||||
String negative,
|
||||
final ConfirmListener cmListener,
|
||||
final CancelListener clListener,
|
||||
TrackableEntity trackableEntity) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final TrackableDialog dialog = new TrackableDialog(context,
|
||||
@ -1112,7 +1129,17 @@ public class DialogUtils {
|
||||
trackableEntity.getKeyBackValue(),
|
||||
trackableEntity.getLogShowEvent());
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_alert, null);
|
||||
View contentView;
|
||||
if (useRoundedCornerStyle) {
|
||||
contentView = LayoutInflater.from(context).inflate(R.layout.dialog_alert_with_rounded_corner, null);
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
}
|
||||
} else {
|
||||
contentView = LayoutInflater.from(context).inflate(R.layout.dialog_alert, null);
|
||||
}
|
||||
|
||||
TextView contentTv = contentView.findViewById(R.id.dialog_content);
|
||||
TextView titleTv = contentView.findViewById(R.id.dialog_title);
|
||||
TextView negativeTv = contentView.findViewById(R.id.dialog_negative);
|
||||
@ -1267,6 +1294,45 @@ public class DialogUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// 海外下载地址弹窗
|
||||
public static void showOverseaDownloadDialog(Context context, GameEntity gameEntity, @NonNull ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
if (gameEntity.getOverseasAddressDialog() == null
|
||||
|| gameEntity.getApk().size() == 0
|
||||
|| !gameEntity.getOverseasAddressDialog().isEnable()) {
|
||||
listener.onConfirm();
|
||||
} else {
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
DialogOverseaConfirmationBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.dialog_oversea_confirmation, null, false);
|
||||
|
||||
View contentView = binding.getRoot();
|
||||
|
||||
binding.setGame(gameEntity);
|
||||
binding.urlTv.setText(gameEntity.getOverseasAddressDialog().getLink());
|
||||
binding.closeIv.setOnClickListener(v -> dialog.dismiss());
|
||||
binding.downloadBtn.setText("下载(" + gameEntity.getApk().get(0).getSize() + ")");
|
||||
binding.downloadBtn.setOnClickListener(v -> {
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
if ("show&download".equals(gameEntity.getOverseasAddressDialog().getStatus())) {
|
||||
gameEntity.getApk().get(0).setUrl(gameEntity.getOverseasAddressDialog().getLink());
|
||||
}
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
}
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
public static void showImprintDialog(Context context, GameEntity gameEntity, String titleName) {
|
||||
context = checkDialogContext(context);
|
||||
Dialog dialog = new Dialog(context, R.style.full_dialog);
|
||||
@ -1343,6 +1409,98 @@ public class DialogUtils {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showStopServerExplanationDialog(Context context, String content, String gameName) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new TrackableDialog(context, R.style.GhAlertDialog, "评论说明弹窗", "弹窗", gameName, null, null, true);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_stop_service_explanation, null);
|
||||
|
||||
TextView contentTv = contentView.findViewById(R.id.contentTv);
|
||||
MaxHeightNestedScrollView scrollView = contentView.findViewById(R.id.scrollView);
|
||||
if (TextUtils.isEmpty(content)) {
|
||||
content = context.getString(R.string.rating_protection);
|
||||
}
|
||||
contentTv.setText(content);
|
||||
TextView ok = contentView.findViewById(R.id.dialog_ok);
|
||||
scrollView.setScrollChangedListener((l, t, oldl, oldt) -> {
|
||||
MtaHelper.onEvent("评论说明弹窗", "滑动内容", gameName);
|
||||
});
|
||||
ok.setOnClickListener(v -> {
|
||||
MtaHelper.onEvent("评论说明弹窗", "弹窗", "点击我知道了");
|
||||
MtaHelper.onEvent("评论说明弹窗", "点击我知道了", gameName);
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60f);
|
||||
window.setAttributes(params);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showPluggableNeverRemindDialog(Context context, String nameAndPlatform, @NonNull ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_pluggable_never_remind, null);
|
||||
|
||||
View cancelBtn = contentView.findViewById(R.id.cancel);
|
||||
View confirmBtn = contentView.findViewById(R.id.confirm);
|
||||
TextView contentTv = contentView.findViewById(R.id.content);
|
||||
|
||||
contentTv.setText(("助手首页将不再提示《" + nameAndPlatform + "》的所有插件化消息,确定吗?"));
|
||||
|
||||
cancelBtn.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
confirmBtn.setOnClickListener(v -> {
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showUnzipFailureDialog(Context context, DownloadEntity downloadEntity) {
|
||||
final Context activityContext = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(activityContext, R.style.GhAlertDialog);
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawableResource(android.R.color.transparent);
|
||||
}
|
||||
|
||||
View contentView = LayoutInflater.from(activityContext).inflate(R.layout.dialog_unzip_failure, null);
|
||||
|
||||
View cancelBtn = contentView.findViewById(R.id.cancel);
|
||||
View confirmBtn = contentView.findViewById(R.id.confirm);
|
||||
|
||||
|
||||
cancelBtn.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
confirmBtn.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
String hint = "《" + downloadEntity.getName() + "》游戏安装包解压失败,问题反馈:";
|
||||
SuggestionActivity.startSuggestionActivity(activityContext, SuggestType.normal, null, hint);
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context may be is application context
|
||||
* @return activity context
|
||||
|
||||
@ -6,11 +6,17 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.base.BaseActivity
|
||||
import com.gh.base.ToolBarActivity
|
||||
import com.gh.base.fragment.BaseFragment_TabLayout
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.exposure.ExposureEvent.Companion.createEvent
|
||||
import com.gh.common.exposure.ExposureManager.log
|
||||
import com.gh.common.exposure.ExposureTraceUtils.appendTrace
|
||||
import com.gh.common.exposure.ExposureType
|
||||
import com.gh.common.util.EntranceUtils.*
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.amway.AmwayActivity
|
||||
@ -21,8 +27,10 @@ import com.gh.gamecenter.eventbus.EBReuse
|
||||
import com.gh.gamecenter.eventbus.EBSkip
|
||||
import com.gh.gamecenter.fragment.MainWrapperFragment
|
||||
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailActivity
|
||||
import com.gh.gamecenter.game.upload.GameSubmissionActivity
|
||||
import com.gh.gamecenter.gamedetail.GameDetailFragment
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.mvvm.Resource
|
||||
import com.gh.gamecenter.mygame.PlayedGameActivity
|
||||
import com.gh.gamecenter.personalhome.UserHomeActivity
|
||||
import com.gh.gamecenter.qa.CommunityFragment
|
||||
@ -32,17 +40,24 @@ import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.column.detail.AskColumnDetailActivity
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity
|
||||
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.servers.GameServersActivity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.suggest.SuggestType
|
||||
import com.gh.gamecenter.tag.TagsActivity
|
||||
import com.gh.gamecenter.video.data.VideoDataActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.gh.gamecenter.video.game.GameVideoActivity
|
||||
import com.gh.gamecenter.video.videomanager.VideoManagerActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_ClipboardManager
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import retrofit2.HttpException
|
||||
|
||||
/**
|
||||
* 跳转用的方法
|
||||
@ -124,30 +139,39 @@ object DirectUtils {
|
||||
when (linkEntity.type) {
|
||||
"article", "news", "文章" -> {
|
||||
NewsUtils.statNewsViews(context, linkEntity.link) // 统计阅读量
|
||||
context.startActivity(NewsDetailActivity.getIntentById(context, linkEntity.link, BaseActivity.mergeEntranceAndPath(entrance, path)))
|
||||
directToArticle(context, linkEntity.link
|
||||
?: "", BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
}
|
||||
|
||||
"game", "游戏" -> {
|
||||
if (exposureEvent != null) {
|
||||
GameDetailActivity.startGameDetailActivity(context, linkEntity.link, BaseActivity.mergeEntranceAndPath(entrance, path), exposureEvent)
|
||||
directToGameDetail(context, linkEntity.link
|
||||
?: "", BaseActivity.mergeEntranceAndPath(entrance, path), traceEvent = exposureEvent)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(context, linkEntity.link, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
directToGameDetail(context, linkEntity.link
|
||||
?: "", BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
}
|
||||
}
|
||||
|
||||
"column", "游戏专题" -> SubjectActivity.startSubjectActivity(context, linkEntity.link, linkEntity.text, false, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
"column", "游戏专题" -> directToSubject(context, linkEntity.link
|
||||
?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
|
||||
"question", "社区问题" -> context.startActivity(QuestionsDetailActivity.getIntent(context, linkEntity.link, entrance, path))
|
||||
"question", "社区问题" -> directToQuestionDetail(context, linkEntity.link
|
||||
?: "", entrance, path)
|
||||
|
||||
"answer", "社区回答" -> context.startActivity(AnswerDetailActivity.getIntent(context, linkEntity.link, entrance, path))
|
||||
"answer", "社区回答" -> directToAnswerDetail(context, linkEntity.link ?: "", entrance, path)
|
||||
|
||||
"community", "问答社区" -> directToCommunity(context, CommunityEntity(linkEntity.link!!, linkEntity.text!!))
|
||||
"community", "问答社区" -> {
|
||||
if (linkEntity.link.isNullOrEmpty()) return
|
||||
directToCommunity(context, CommunityEntity(linkEntity.link!!, linkEntity.text!!))
|
||||
}
|
||||
|
||||
"community_article", "社区文章" -> context.startActivity(ArticleDetailActivity.getIntent(context, linkEntity.community!!, linkEntity.link!!, entrance, path))
|
||||
"community_article", "社区文章" -> directToCommunityArticle(context, linkEntity.community!!, linkEntity.link!!, entrance, path)
|
||||
|
||||
"community_column", "社区专题" -> directToCommunityColumn(context, linkEntity.community, linkEntity.link!!, entrance, path)
|
||||
|
||||
"community_special_column" -> context.startActivity(AskColumnDetailActivity.getIntentByColumnId(context, linkEntity.link, linkEntity.community!!, entrance, path))
|
||||
"community_special_column" -> directAskColumnDetail(context, linkEntity.link
|
||||
?: "", linkEntity.community!!, entrance, path)
|
||||
|
||||
"web", "inurl", "web链接" -> {
|
||||
when {
|
||||
@ -166,37 +190,31 @@ object DirectUtils {
|
||||
|
||||
"tag" -> context.startActivity(TagsActivity.getIntent(context, linkEntity.text!!, linkEntity.title, entrance, path))
|
||||
|
||||
"all_community_article" -> {
|
||||
context.startActivity(SimpleArticleListActivity.getIntent(
|
||||
context,
|
||||
linkEntity.link ?: "",
|
||||
entrance,
|
||||
path))
|
||||
}
|
||||
"all_community_article" -> directSimpleArticleList(context, linkEntity.link
|
||||
?: "", entrance, path)
|
||||
|
||||
"category", "分类" -> {
|
||||
context.startActivity(CategoryDirectoryActivity.getIntent(context, linkEntity.link!!, linkEntity.text!!))
|
||||
}
|
||||
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
|
||||
|
||||
"block", "版块" -> {
|
||||
context.startActivity(BlockActivity.getIntent(context, SubjectRecommendEntity(
|
||||
link = linkEntity.link,
|
||||
text = linkEntity.text,
|
||||
name = linkEntity.name,
|
||||
display = linkEntity.display ?: Display())))
|
||||
if (linkEntity.link.isNullOrEmpty()) return
|
||||
directToBlock(context,
|
||||
SubjectRecommendEntity(
|
||||
link = linkEntity.link,
|
||||
text = linkEntity.text,
|
||||
name = linkEntity.name,
|
||||
display = linkEntity.display ?: Display()),
|
||||
entrance)
|
||||
}
|
||||
|
||||
"column_collection", "专题合集" -> directToColumnCollection(context, linkEntity.link!!, -1, entrance)
|
||||
|
||||
"server", "game_server" -> {
|
||||
context.startActivity(GameServersActivity.getIntent(context, entrance, path))
|
||||
}
|
||||
"server", "game_server", "开服表" -> directToGameServers(context, entrance, path)
|
||||
|
||||
"top_game_comment" -> directToAmway(context, null, entrance, path)
|
||||
|
||||
"wechat_bind" -> context.startActivity(WebActivity.getBindWechatIntent(context))
|
||||
|
||||
"video", "video_stream" -> directToVideoDetail(context,
|
||||
"video", "video_stream", "视频" -> directToVideoDetail(context,
|
||||
videoId = linkEntity.link!!,
|
||||
fromLocation = VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value,
|
||||
entrance = entrance,
|
||||
@ -204,16 +222,21 @@ object DirectUtils {
|
||||
|
||||
"game_video" -> directToGameVideo(context, linkEntity.link ?: "", entrance, path)
|
||||
|
||||
"libao" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
|
||||
"libao", "礼包" -> directToGiftDetail(context, linkEntity.link ?: "", entrance)
|
||||
|
||||
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, entrance)
|
||||
|
||||
"qa" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
|
||||
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
|
||||
|
||||
"qa_collection" -> directToQaCollection(context, linkEntity.text ?: "", linkEntity.link
|
||||
"qa_collection", "Q&A合集" -> directToQaCollection(context, linkEntity.text
|
||||
?: "", linkEntity.link
|
||||
?: "")
|
||||
|
||||
"anliwall" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
|
||||
"anliwall", "安利墙" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
|
||||
|
||||
"game_detail_comment" -> directToGameDetail(context, linkEntity.link ?: "", entrance)
|
||||
|
||||
"game_upload", "游戏投稿" -> directGameUpload(context, entrance, path)
|
||||
|
||||
//"h5_game_center" -> directLetoGameCenter(context)
|
||||
|
||||
@ -233,15 +256,27 @@ object DirectUtils {
|
||||
/**
|
||||
* 跳转至QA
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToQa(context: Context, text: String, id: String) {
|
||||
context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaId = id))
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, QaActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_NAVIGATION_TITLE, text)
|
||||
bundle.putString(KEY_QA_ID, id)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至QA合集
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToQaCollection(context: Context, text: String, id: String) {
|
||||
context.startActivity(QaActivity.getIntent(context, navigationTitle = text, qaCollectionId = id))
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, QaActivity::class.java.simpleName)
|
||||
bundle.putString(KEY_NAVIGATION_TITLE, text)
|
||||
bundle.putString(KEY_QA_COLLECTION_ID, id)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,7 +284,14 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String, columnName: String = "") {
|
||||
context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance, columnName))
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, ColumnCollectionDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
bundle.putString(KEY_COLLECTION_ID, id)
|
||||
bundle.putString(KEY_COLUMNNAME, columnName)
|
||||
bundle.putInt(KEY_POSITION, position)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -257,6 +299,7 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToArticle(context: Context, id: String, entrance: String? = null) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, NewsDetailActivity::class.java.simpleName)
|
||||
@ -299,7 +342,8 @@ object DirectUtils {
|
||||
* 跳转到游戏详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, scrollToLibao: Boolean = false) {
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, scrollToLibao: Boolean = false, traceEvent: ExposureEvent? = null) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, GameDetailActivity::class.java.simpleName)
|
||||
@ -308,6 +352,11 @@ object DirectUtils {
|
||||
bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_TRENDES)
|
||||
bundle.putBoolean(KEY_SCROLL_TO_LIBAO, scrollToLibao)
|
||||
}
|
||||
if (traceEvent != null) {
|
||||
val clickEvent = createEvent(GameEntity(id), traceEvent.source, appendTrace(traceEvent), ExposureType.CLICK)
|
||||
log(clickEvent)
|
||||
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
|
||||
}
|
||||
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
@ -323,7 +372,16 @@ object DirectUtils {
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
bundle.putBoolean(KEY_OPEN_VIDEO_STREAMING, true)
|
||||
bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_DESC)
|
||||
// GameDetailActivity.startGameDetailToVideoStreaming(context, id, entrance)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToGameDetail(context: Context, id: String, defaultTab: Int = GameDetailFragment.INDEX_DESC, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, GameDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
bundle.putInt(KEY_TARGET, defaultTab)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@ -335,6 +393,7 @@ object DirectUtils {
|
||||
// 专栏
|
||||
@JvmStatic
|
||||
fun directToSubject(context: Context, id: String, subjectName: String? = "", entrance: String? = null) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
val subjectData = SubjectData(subjectId = id, subjectName = subjectName, isOrder = false)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
@ -411,6 +470,7 @@ object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToAnswerDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, AnswerDetailActivity::class.java.name)
|
||||
@ -421,6 +481,7 @@ object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToQuestionDetail(context: Context, id: String, entrance: String? = null, path: String? = null) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, QuestionsDetailActivity::class.java.name)
|
||||
@ -431,6 +492,7 @@ object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToWebView(context: Context, url: String, entrance: String? = null) {
|
||||
if (url.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, WebActivity::class.java.simpleName)
|
||||
@ -449,7 +511,11 @@ object DirectUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun directToExternalBrowser(context: Context, url: String) {
|
||||
if (url.isEmpty()) return
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
if (context !is AppCompatActivity) {
|
||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(browserIntent)
|
||||
}
|
||||
|
||||
@ -470,7 +536,11 @@ object DirectUtils {
|
||||
chatType = "wpa"
|
||||
}
|
||||
val str = "mqqwpa://im/chat?chat_type=$chatType&uin=$qq&version=1&src_type=web"
|
||||
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(str)))
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(str))
|
||||
if (context !is AppCompatActivity) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
// 没有安装QQ 复制账号
|
||||
Util_System_ClipboardManager.setText(context, qq)
|
||||
@ -481,17 +551,25 @@ object DirectUtils {
|
||||
// 跳转 QQ 群
|
||||
@JvmStatic
|
||||
fun directToQqGroup(context: Context, groupNumber: String? = null): Boolean {
|
||||
val intent = Intent()
|
||||
intent.data = Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$groupNumber")
|
||||
// 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
// 未安装手Q或安装的版本不支持
|
||||
if (groupNumber.isNullOrEmpty()) return false
|
||||
if (ShareUtils.isQQClientAvailable(context)) {
|
||||
val intent = Intent()
|
||||
intent.data = Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$groupNumber")
|
||||
// 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
return try {
|
||||
if (context !is AppCompatActivity) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
Utils.toast(context, "请安装QQ客户端")
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -499,6 +577,7 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGiftDetail(context: Context, giftId: String, entrance: String? = null) {
|
||||
if (giftId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, LibaoDetailActivity::class.java.simpleName)
|
||||
@ -551,11 +630,24 @@ object DirectUtils {
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToCommunityArticle(context: Context, community: CommunityEntity?, articleId: String?, entrance: String?, path: String?) {
|
||||
if (articleId.isNullOrEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_TO, ArticleDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_COMMUNITY_ARTICLE_ID, articleId)
|
||||
bundle.putParcelable(KEY_COMMUNITY_DATA, community)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到社区专题
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToCommunityColumn(context: Context, community: CommunityEntity?, subjectId: String, entrance: String?, path: String?) {
|
||||
if (subjectId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_TO, CommunitySubjectActivity::class.java.name)
|
||||
@ -569,7 +661,8 @@ object DirectUtils {
|
||||
* @param fromLocation 可见 [VideoDetailContainerViewModel.Location]
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToVideoDetail(context: Context, videoId: String, fromLocation: String, showComment: Boolean = false, gameId: String = "", entrance: String? = null, path: String? = "", referer: String = "", type: String = "", act: String = "") {
|
||||
fun directToVideoDetail(context: Context, videoId: String, fromLocation: String, showComment: Boolean = false, gameId: String = "", entrance: String? = null,
|
||||
path: String? = "", referer: String = "", type: String = "", act: String = "", fieldId: String = "", sectionName: String = "") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
@ -582,6 +675,8 @@ object DirectUtils {
|
||||
bundle.putString(KEY_REFERER, referer)
|
||||
bundle.putString(KEY_TYPE, type)
|
||||
bundle.putString(KEY_ACTIVITY_NAME, act)
|
||||
bundle.putString(KEY_FIELD_ID, fieldId)
|
||||
bundle.putString(KEY_SECTION_NAME, sectionName)
|
||||
jumpActivity(context, bundle)
|
||||
} else {
|
||||
DialogUtils.showLowSystemVersionDialog(context)
|
||||
@ -619,10 +714,11 @@ object DirectUtils {
|
||||
* 跳转至上传视频
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToVideoManager(context: Context, linkEntity: VideoLinkEntity, entrance: String? = null, path: String? = "") {
|
||||
fun directToVideoManager(context: Context, linkEntity: VideoLinkEntity, simpleGameEntity: SimpleGameEntity, entrance: String? = null, path: String? = "") {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putParcelable(VideoLinkEntity::class.java.simpleName, linkEntity)
|
||||
bundle.putParcelable(SimpleGameEntity::class.java.simpleName, simpleGameEntity)
|
||||
bundle.putString(KEY_TO, VideoManagerActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
jumpActivity(context, bundle)
|
||||
@ -633,6 +729,7 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameVideo(context: Context, gameId: String, entrance: String? = null, path: String? = "") {
|
||||
if (gameId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putString(KEY_TO, GameVideoActivity::class.java.name)
|
||||
@ -680,6 +777,7 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directCategoryDirectory(context: Context, categoryId: String, categoryTitle: String, entrance: String? = null, path: String? = "") {
|
||||
if (categoryId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
|
||||
bundle.putString(KEY_CATEGORY_ID, categoryId)
|
||||
@ -708,6 +806,7 @@ object DirectUtils {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directAskColumnDetail(context: Context, columnId: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
|
||||
if (columnId.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_COLUMN_ID, columnId)
|
||||
@ -716,4 +815,89 @@ object DirectUtils {
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到板块
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToBlock(context: Context, blockData: SubjectRecommendEntity, entrance: String) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, BlockActivity::class.java.name)
|
||||
bundle.putParcelable(KEY_BLOCK_DATA, blockData)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到开服表
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameServers(context: Context, entrance: String, path: String) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, GameServersActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, ToolBarActivity.mergeEntranceAndPath(entrance, path))
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到游戏上传
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directGameUpload(context: Context, entrance: String? = null, path: String? = "") {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, GameSubmissionActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 社区文章
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directSimpleArticleList(context: Context, sortType: String, entrance: String? = null, path: String? = "") {
|
||||
if (sortType.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, SimpleArticleListActivity::class.java.name)
|
||||
bundle.putString(KEY_TYPE, sortType)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directGameZone(context: Context, gameId: String, url: String, entrance: String? = null) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.sensitiveApi
|
||||
.getGameDigest(gameId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<GameEntity>() {
|
||||
override fun onResponse(response: GameEntity?) {
|
||||
response?.apply {
|
||||
if (zone.status == "on") {
|
||||
if (zone.style == "link") {
|
||||
directToGameDetail(context, gameId, GameDetailFragment.INDEX_TRENDES, entrance)
|
||||
} else {
|
||||
directToWebView(context, url, entrance)
|
||||
}
|
||||
} else {
|
||||
directToWebView(context, url, entrance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directVideoData(context: Context, entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, VideoDataActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
}
|
||||
@ -271,6 +271,16 @@ public class DisplayUtils {
|
||||
return metrics.heightPixels;
|
||||
}
|
||||
|
||||
public static int getToastOffset() {
|
||||
int i = Resources.getSystem().getIdentifier("toast_y_offset", "dimen", "android");
|
||||
return HaloApp.getInstance().getApplication().getResources().getDimensionPixelSize(i);
|
||||
}
|
||||
|
||||
public static int getToastDefaultGravity() {
|
||||
int i = Resources.getSystem().getIdentifier("config_toastDefaultGravity", "integer", "android");
|
||||
return HaloApp.getInstance().getApplication().getResources().getInteger(i);
|
||||
}
|
||||
|
||||
public static boolean hasSoftKeys(Context context) {
|
||||
if (!(context instanceof Activity)) return false;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
@ -18,8 +19,12 @@ object DownloadHelper {
|
||||
* @param block 成功添加下载任务后执行的代码块
|
||||
*/
|
||||
fun createABrandNewDownloadTaskQuietly(gameId: String? = "", packageName: String? = "", block: () -> Unit) {
|
||||
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
|
||||
return
|
||||
}
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api
|
||||
.sensitiveApi
|
||||
.getGameDigest(gameId)
|
||||
.map(ApkActiveUtils.filterMapper)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
@ -15,6 +15,8 @@ import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
import com.gh.common.xapk.XapkInstaller;
|
||||
import com.gh.common.xapk.XapkUnzipStatus;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.download.dialog.DownloadDialog;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
@ -134,16 +136,23 @@ public class DownloadItemUtils {
|
||||
|
||||
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
|
||||
boolean isShowPlatform) {
|
||||
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false);
|
||||
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false, null);
|
||||
}
|
||||
|
||||
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
|
||||
boolean isShowPlatform, boolean hideDownloadBtnIfNoAvailableContent) {
|
||||
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, hideDownloadBtnIfNoAvailableContent);
|
||||
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, hideDownloadBtnIfNoAvailableContent, null);
|
||||
}
|
||||
|
||||
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
|
||||
boolean isShowPlatform, PluginLocation pluginLocation, boolean hideDownloadBtnIfNoAvailableContent) {
|
||||
boolean isShowPlatform, String briefStyle) {
|
||||
updateItem(context, gameEntity, holder, isShowPlatform, PluginLocation.only_game, false, briefStyle);
|
||||
}
|
||||
|
||||
public static void updateItem(Context context, GameEntity gameEntity, GameViewHolder holder,
|
||||
boolean isShowPlatform, PluginLocation pluginLocation,
|
||||
boolean hideDownloadBtnIfNoAvailableContent,
|
||||
@Nullable String briefStyle) {
|
||||
|
||||
// 控制是否显示下载按钮
|
||||
if (!Config.isShowDownload(gameEntity.getId()) || context.getString(R.string.app_name).equals(gameEntity.getName())) {
|
||||
@ -154,9 +163,7 @@ public class DownloadItemUtils {
|
||||
|
||||
// 显示预约
|
||||
if (gameEntity.isReservable()) {
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.getId())) {
|
||||
holder.gameDownloadBtn.setText("预约");
|
||||
holder.gameDownloadBtn.setTextColor(Color.WHITE);
|
||||
@ -174,9 +181,7 @@ public class DownloadItemUtils {
|
||||
LinkEntity h5LinkEntity = gameEntity.getH5Link();
|
||||
String offStatus = gameEntity.getDownloadOffStatus();
|
||||
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
|
||||
if (h5LinkEntity != null) {
|
||||
if ("play".equals(h5LinkEntity.getType())) {
|
||||
@ -201,16 +206,16 @@ public class DownloadItemUtils {
|
||||
holder.gameDownloadBtn.setClickable(false);
|
||||
}
|
||||
} else if (gameEntity.getApk().size() == 1) {
|
||||
updateNormalItem(context, holder, gameEntity, isShowPlatform, pluginLocation);
|
||||
updateNormalItem(context, holder, gameEntity, isShowPlatform, pluginLocation, briefStyle);
|
||||
} else {
|
||||
updatePluginItem(context, holder, gameEntity, isShowPlatform, pluginLocation);
|
||||
updatePluginItem(context, holder, gameEntity, isShowPlatform, pluginLocation, briefStyle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 更新正常的条目,只有一个apk包
|
||||
static void updateNormalItem(Context context, GameViewHolder holder, GameEntity gameEntity,
|
||||
boolean isShowPlatform, PluginLocation pluginLocation) {
|
||||
boolean isShowPlatform, PluginLocation pluginLocation, String briefStyle) {
|
||||
|
||||
final ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
|
||||
final ApkEntity apkEntity = gameEntity.getApk().get(0);
|
||||
@ -226,14 +231,12 @@ public class DownloadItemUtils {
|
||||
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
|
||||
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
}
|
||||
|
||||
// 更新插件的条目,有多个apk包
|
||||
private static void updatePluginItem(Context context, GameViewHolder holder, GameEntity gameEntity,
|
||||
boolean isShowPlatform, PluginLocation pluginLocation) {
|
||||
boolean isShowPlatform, PluginLocation pluginLocation, String briefStyle) {
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, holder.gameDownloadBtn, pluginLocation);
|
||||
|
||||
ArrayMap<String, DownloadEntity> entryMap = gameEntity.getEntryMap();
|
||||
@ -252,18 +255,15 @@ public class DownloadItemUtils {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
updateItemViewStatus(holder, false, briefStyle);
|
||||
}
|
||||
|
||||
// 更改进度条和提示文本的状态
|
||||
public static void changeStatus(Context context, GameViewHolder holder, DownloadEntity downloadEntity,
|
||||
boolean isShowPlatform, boolean isNormal) {
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
holder.gameProgressbar.setVisibility(View.VISIBLE);
|
||||
holder.gameInfo.setVisibility(View.VISIBLE);
|
||||
|
||||
updateItemViewStatus(holder, true, null);
|
||||
holder.gameProgressbar.setProgressDrawable(context.getResources().getDrawable(R.drawable.progressbar_bg_style));
|
||||
|
||||
String platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
|
||||
|
||||
@ -324,6 +324,17 @@ public class DownloadItemUtils {
|
||||
holder.gameDownloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style));
|
||||
}
|
||||
} else if (status.equals(DownloadStatus.done)) {
|
||||
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
|
||||
if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
|
||||
String percent = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_PERCENT);
|
||||
holder.gameProgressbar.setProgressDrawable(context.getResources().getDrawable(R.drawable.progressbar_xapk_style));
|
||||
holder.gameDownloadSpeed.setText(R.string.unzipping);
|
||||
holder.gameProgressbar.setProgress((int) (Float.valueOf(percent) * 10));
|
||||
holder.gameDownloadPercentage.setText(percent + "%");
|
||||
holder.gameDownloadBtn.setText(R.string.unzipping);
|
||||
return;
|
||||
}
|
||||
|
||||
holder.gameProgressbar.setProgress(1000);
|
||||
if (isShowPlatform && platform != null) {
|
||||
holder.gameDownloadSpeed.setText(String.format("%s - 下载完成", platform));
|
||||
@ -345,6 +356,29 @@ public class DownloadItemUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateItemViewStatus(GameViewHolder holder, boolean hasDownload, @Nullable String briefStyle) {
|
||||
if (hasDownload) {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
holder.gameProgressbar.setVisibility(View.VISIBLE);
|
||||
holder.gameInfo.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.gameProgressbar.setVisibility(View.GONE);
|
||||
holder.gameInfo.setVisibility(View.GONE);
|
||||
if (briefStyle != null && briefStyle.contains("star")) {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(briefStyle) || briefStyle.contains("brief")) {
|
||||
holder.gameDes.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.gameDes.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setOnClickListener(final Context context,
|
||||
final TextView downloadBtn,
|
||||
final GameEntity gameEntity,
|
||||
@ -429,12 +463,12 @@ public class DownloadItemUtils {
|
||||
|
||||
LinkEntity linkEntity = gameEntity.getH5Link();
|
||||
|
||||
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
|
||||
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
|
||||
if (isPlay) {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
}
|
||||
|
||||
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay);
|
||||
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay,linkEntity.getCloseButton());
|
||||
context.startActivity(i);
|
||||
});
|
||||
} else if (gameEntity.getApk().size() == 1) {
|
||||
@ -500,8 +534,10 @@ public class DownloadItemUtils {
|
||||
// 先弹下载弹窗(如果需要的话)
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -510,8 +546,10 @@ public class DownloadItemUtils {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
DialogUtils.showVersionNumberDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
DialogUtils.showOverseaDownloadDialog(context, gameEntity, () -> {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -539,10 +577,6 @@ public class DownloadItemUtils {
|
||||
}
|
||||
DataUtils.onGameLaunchEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), location);
|
||||
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk().get(0).getPackageName());
|
||||
} else if (str.equals(context.getString(R.string.waiting))
|
||||
|| str.equals(context.getString(R.string.downloading))) {
|
||||
context.startActivity(DownloadManagerActivity.getDownloadMangerIntent(context,
|
||||
apk.getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
|
||||
} else if (str.equals(context.getString(R.string.update))) {
|
||||
if (entrance.contains("我的游戏")) {
|
||||
MtaHelper.onEvent("我的游戏_启动", "更新", gameEntity.getName());
|
||||
@ -551,6 +585,9 @@ public class DownloadItemUtils {
|
||||
DialogUtils.checkDownload(context, apk.getSize(),
|
||||
isSubscribe -> update(context, gameEntity, entrance, location, isSubscribe, traceEvent));
|
||||
});
|
||||
} else {
|
||||
context.startActivity(DownloadManagerActivity.getDownloadMangerIntent(context,
|
||||
apk.getUrl(), entrance + "+(" + location.split(":")[0] + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -611,9 +648,9 @@ public class DownloadItemUtils {
|
||||
}
|
||||
adapter.notifyItemChanged(position);
|
||||
} else if (PackageUtils.isCanPluggable(apkEntity)) {
|
||||
DialogUtils.showPluginDialog(context, () -> context.startActivity(PackageUtils.getUninstallIntent(context, path)));
|
||||
DialogUtils.showPluginDialog(context, () -> PackageInstaller.uninstall(context, path));
|
||||
} else {
|
||||
PackageUtils.launchSetup(context, downloadEntity);
|
||||
PackageInstaller.install(context, downloadEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.common.xapk.XapkUnzipStatus
|
||||
import com.gh.gamecenter.R
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -38,9 +40,10 @@ object DownloadNotificationHelper {
|
||||
var requireUpdateNotificationGroupDelay = false
|
||||
val notificationManager = getNotificationManager()
|
||||
val downloadNotificationId = (entity.gameId + entity.packageName).hashCode()
|
||||
val xapkStatus = entity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
|
||||
|
||||
val intent = Intent()
|
||||
if (entity.status == DownloadStatus.done) {
|
||||
if (entity.status == DownloadStatus.done && xapkStatus != XapkUnzipStatus.FAILURE.name) {
|
||||
intent.putExtra(EntranceUtils.KEY_DATA, entity.toJson())
|
||||
intent.putExtra(EntranceUtils.KEY_PATH, entity.path)
|
||||
intent.action = ACTION_INSTALL
|
||||
@ -65,18 +68,23 @@ object DownloadNotificationHelper {
|
||||
.setContentIntent(pendingIntent)
|
||||
.setGroup(DOWNLOAD_GROUP_KEY)
|
||||
.setWhen(whenTime)
|
||||
.setProgress(PROGRESS_MAX, entity.percent.toInt(), false)
|
||||
|
||||
when (entity.status) {
|
||||
DownloadStatus.downloading -> builder.setContentText(String.format("%s(剩%s)",
|
||||
SpeedUtils.getSpeed(entity.speed),
|
||||
SpeedUtils.getRemainTime(entity.size, entity.progress, entity.speed * 1024)))
|
||||
DownloadStatus.done -> builder.setContentText("下载完成,点击立即安装")
|
||||
DownloadStatus.waiting -> builder.setContentText("等待中")
|
||||
DownloadStatus.subscribe,
|
||||
DownloadStatus.timeout,
|
||||
DownloadStatus.neterror -> builder.setContentText("已暂停,连接WiFi自动下载")
|
||||
else -> builder.setContentText("暂停中")
|
||||
|
||||
if (xapkStatus == XapkUnzipStatus.FAILURE.name) {
|
||||
builder.setContentText("《" + entity.name + "》解压失败,点击查看详情~")
|
||||
} else {
|
||||
when (entity.status) {
|
||||
DownloadStatus.downloading -> builder.setContentText(String.format("%s(剩%s)",
|
||||
SpeedUtils.getSpeed(entity.speed),
|
||||
SpeedUtils.getRemainTime(entity.size, entity.progress, entity.speed * 1024)))
|
||||
DownloadStatus.done -> builder.setContentText("下载完成,点击立即安装")
|
||||
DownloadStatus.waiting -> builder.setContentText("等待中")
|
||||
DownloadStatus.subscribe,
|
||||
DownloadStatus.timeout,
|
||||
DownloadStatus.neterror -> builder.setContentText("已暂停,连接WiFi自动下载")
|
||||
else -> builder.setContentText("暂停中")
|
||||
}
|
||||
builder.setProgress(PROGRESS_MAX, entity.percent.toInt(), false)
|
||||
}
|
||||
|
||||
when {
|
||||
@ -88,30 +96,39 @@ object DownloadNotificationHelper {
|
||||
else -> builder.setSortKey("C")
|
||||
}
|
||||
|
||||
val notification = builder.build()
|
||||
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
|
||||
|
||||
if (entity.status == DownloadStatus.delete
|
||||
|| entity.status == DownloadStatus.cancel
|
||||
|| entity.status == DownloadStatus.hijack
|
||||
|| entity.status == DownloadStatus.notfound
|
||||
|| entity.status == DownloadStatus.overflow
|
||||
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
|
||||
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty())) {
|
||||
requireUpdateNotificationGroupDelay = true
|
||||
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
|
||||
} else {
|
||||
if (entity.status != DownloadStatus.downloading) {
|
||||
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
|
||||
tryCatchInRelease {
|
||||
val notification = builder.build() // 可能会抛出异常
|
||||
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
|
||||
if (xapkStatus == XapkUnzipStatus.FAILURE.name) {
|
||||
notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
|
||||
} else {
|
||||
val time = mNotifyMap[entity.path]
|
||||
val curTime = System.currentTimeMillis()
|
||||
if (time == null || curTime - time > 2000) {
|
||||
mNotifyMap[entity.path] = curTime
|
||||
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
|
||||
}
|
||||
|
||||
if (entity.status == DownloadStatus.delete
|
||||
|| entity.status == DownloadStatus.cancel
|
||||
|| entity.status == DownloadStatus.hijack
|
||||
|| entity.status == DownloadStatus.notfound
|
||||
|| entity.status == DownloadStatus.overflow
|
||||
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
|
||||
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty()
|
||||
&& xapkStatus != XapkUnzipStatus.FAILURE.name)) {
|
||||
requireUpdateNotificationGroupDelay = true
|
||||
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
|
||||
} else {
|
||||
if (entity.status != DownloadStatus.downloading) {
|
||||
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
|
||||
} else {
|
||||
val time = mNotifyMap[entity.path]
|
||||
val curTime = System.currentTimeMillis()
|
||||
if (time == null || curTime - time > 2000) {
|
||||
mNotifyMap[entity.path] = curTime
|
||||
notificationManager.notify(entity.path, DOWNLOAD_NOTIFICATION_ID, notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requireUpdateNotificationGroupDelay) {
|
||||
// 虽然运行到这里时 notification 已经被 cancel 了,但在下面的 notificationManager.getActiveNotifications 里它有可能还是 active 状态,
|
||||
// 这里延时 100 ms 避免出现所有的任务都取消了以后依旧有一条 notification group 常驻
|
||||
|
||||
@ -6,6 +6,8 @@ import android.preference.PreferenceManager
|
||||
import com.gh.base.BaseActivity
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureUtils
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.download.DownloadDataHelper
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
@ -43,11 +45,15 @@ object DownloadObserver {
|
||||
fun initObserver() {
|
||||
val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
// todo 如何处理xapk安装问题
|
||||
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
|
||||
if (!xapkStatus.isNullOrEmpty()) return
|
||||
|
||||
val gameId = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
|
||||
val downloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
|
||||
|
||||
if (downloadEntity.status != DownloadStatus.downloading) {
|
||||
LogUtils.uploadDownloadEvent(downloadEntity)
|
||||
tryCatchInRelease {
|
||||
DownloadDataHelper.uploadDownloadEvent(downloadEntity)
|
||||
}
|
||||
|
||||
if (DownloadStatus.hijack == downloadEntity.status) {
|
||||
@ -55,9 +61,9 @@ object DownloadObserver {
|
||||
processHijack(downloadEntity)
|
||||
val nameAndPlatform = (downloadEntity.name + ":"
|
||||
+ PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
MtaHelper.onEvent("下载劫持",
|
||||
"游戏名字", nameAndPlatform,
|
||||
"网络状态", DeviceUtils.getNetwork(mApplication))
|
||||
// MtaHelper.onEvent("下载劫持",
|
||||
// "游戏名字", nameAndPlatform,
|
||||
// "网络状态", DeviceUtils.getNetwork(mApplication))
|
||||
return
|
||||
} else if (DownloadStatus.notfound == downloadEntity.status) {
|
||||
// 404 Not Found
|
||||
@ -66,9 +72,9 @@ object DownloadObserver {
|
||||
downloadManager.cancel(downloadEntity.url)
|
||||
Utils.toast(mApplication, "该链接已失效!请联系管理员。")
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
|
||||
"游戏", downloadEntity.name,
|
||||
"平台", downloadEntity.platform)
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
|
||||
// "游戏", downloadEntity.name,
|
||||
// "平台", downloadEntity.platform)
|
||||
|
||||
DialogUtils.showAlertDialog(AppManager.getInstance().currentActivity(), "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
|
||||
SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
|
||||
@ -90,9 +96,9 @@ object DownloadObserver {
|
||||
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
|
||||
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
|
||||
"游戏", downloadEntity.name,
|
||||
"平台", downloadEntity.platform)
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
|
||||
// "游戏", downloadEntity.name,
|
||||
// "平台", downloadEntity.platform)
|
||||
debugOnly {
|
||||
Utils.log("DownloadObserver", "下载自动暂停->" + downloadEntity.toJson())
|
||||
}
|
||||
@ -103,7 +109,7 @@ object DownloadObserver {
|
||||
MtaHelper.onEvent("软件更新", "下载完成")
|
||||
tryWithDefaultCatch {
|
||||
// 会有 ActivityNotFoundException 异常,catch 掉不管了
|
||||
mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path, true))
|
||||
PackageInstaller.install(mApplication, downloadEntity)
|
||||
}
|
||||
DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据
|
||||
} else {
|
||||
@ -131,7 +137,7 @@ object DownloadObserver {
|
||||
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
tryWithDefaultCatch {
|
||||
mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path))
|
||||
PackageInstaller.install(mApplication, downloadEntity, false)
|
||||
}
|
||||
} else {
|
||||
// 弹出卸载提示框
|
||||
@ -149,11 +155,11 @@ object DownloadObserver {
|
||||
val pm = mApplication.packageManager
|
||||
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
|
||||
if (packageInfo == null) {
|
||||
MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
|
||||
"游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
|
||||
"游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
|
||||
// "游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
//
|
||||
// MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
|
||||
// "游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,13 +205,13 @@ object DownloadObserver {
|
||||
type = ExposureUtils.DownloadType.DOWNLOAD
|
||||
}
|
||||
|
||||
val kv2 = HashMap<String, Any>()
|
||||
kv2["版本"] = downloadEntity.platform
|
||||
kv2["状态"] = "下载完成"
|
||||
kv2["位置"] = downloadEntity.entrance ?: "null"
|
||||
kv2["游戏分平台"] = downloadEntity.name + "-" + platform
|
||||
kv2["光环助手版本"] = BuildConfig.VERSION_NAME
|
||||
DataUtils.onEvent(mApplication, "游戏下载位置", downloadEntity.name, kv2)
|
||||
// val kv2 = HashMap<String, Any>()
|
||||
// kv2["版本"] = downloadEntity.platform
|
||||
// kv2["状态"] = "下载完成"
|
||||
// kv2["位置"] = downloadEntity.entrance ?: "null"
|
||||
// kv2["游戏分平台"] = downloadEntity.name + "-" + platform
|
||||
// kv2["光环助手版本"] = BuildConfig.VERSION_NAME
|
||||
// DataUtils.onEvent(mApplication, "游戏下载位置", downloadEntity.name, kv2)
|
||||
|
||||
if (downloadEntity.isPluggable) {
|
||||
val kv3 = HashMap<String, Any>()
|
||||
@ -215,16 +221,18 @@ object DownloadObserver {
|
||||
type = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD
|
||||
DataUtils.onEvent(mApplication, "插件化", downloadEntity.name, kv3)
|
||||
|
||||
MtaHelper.onEvent(
|
||||
"插件化_新",
|
||||
"位置", downloadEntity.entrance,
|
||||
"游戏", downloadEntity.name + "-" + downloadEntity.platform,
|
||||
"操作", "下载完成",
|
||||
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
|
||||
// MtaHelper.onEvent(
|
||||
// "插件化_新",
|
||||
// "位置", downloadEntity.entrance,
|
||||
// "游戏", downloadEntity.name + "-" + downloadEntity.platform,
|
||||
// "操作", "下载完成",
|
||||
// "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
|
||||
}
|
||||
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR)),
|
||||
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER),
|
||||
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = downloadEntity.versionName ?: ""),
|
||||
downloadEntity.platform,
|
||||
downloadEntity.exposureTrace,
|
||||
type)
|
||||
|
||||
@ -4,8 +4,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.gamecenter.MainActivity;
|
||||
@ -13,6 +11,8 @@ import com.gh.gamecenter.NormalActivity;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
* @Date 2017/4/25
|
||||
@ -28,6 +28,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_ID = "id";
|
||||
public static final String KEY_URL = "url";
|
||||
public static final String KEY_GAMENAME = "gameName";
|
||||
public static final String KEY_PACKAGE_MD5 = "package_md5";
|
||||
public static final String HOST_ARTICLE = "article";
|
||||
public static final String HOST_UPLOAD_VIDEO = "upload_video";//上传视频
|
||||
public static final String HOST_VIDEO_SINGLE = "video_single";//指定视频-不能划动
|
||||
@ -41,6 +42,13 @@ public class EntranceUtils {
|
||||
public static final String HOST_COLUMN_COLLECTION = "column_collection";//专题合集
|
||||
public static final String HOST_COMMUNITY_QUESTION_LABEL_DETAIL = "community_question_label_detail";//问题标签详情
|
||||
public static final String HOST_COMMUNITY_COLUMN_DETAIL = "community_column_detail";//专栏详情
|
||||
public static final String HOST_BLOCK = "block";//板块
|
||||
public static final String HOST_SERVER_BLOCK = "server";//开服表板块
|
||||
public static final String HOST_AMWAY_BLOCK = "amway";//安利墙板块
|
||||
public static final String HOST_HELP = "help";//Q&A
|
||||
public static final String HOST_HELP_COLLECTION = "help_collection";//Q&A合集
|
||||
public static final String HOST_GAME_UPLOAD = "game_upload";//游戏上传
|
||||
public static final String HOST_GAME_ZONE = "game_zone";//游戏专区
|
||||
public static final String HOST_COMMUNITY_ARTICLE = "community_article";
|
||||
public static final String HOST_COMMUNITY_COLUMN = "community_column";
|
||||
public static final String HOST_GAME = "game";
|
||||
@ -49,6 +57,7 @@ public class EntranceUtils {
|
||||
public static final String HOST_WEB = "web";
|
||||
public static final String HOST_QQ = "qq";
|
||||
public static final String HOST_QQ_GROUP = "qqgroup";
|
||||
public static final String HOST_QQ_QUN = "qqqun";
|
||||
public static final String HOST_DOWNLOAD = "download";
|
||||
public static final String HOST_UPDATE = "update";
|
||||
public static final String HOST_LIBAO = "libao";
|
||||
@ -74,6 +83,7 @@ public class EntranceUtils {
|
||||
public static final String ENTRANCE_DOWNLOAD = "(下载跳转)";
|
||||
public static final String ENTRANCE_RECOMMEND = "(落地页)";
|
||||
public static final String ENTRANCE_BLOCK_RECOMMEND = "(推荐入口)";
|
||||
public static final String ENTRANCE_AMWAY = "(安利墙)";
|
||||
public static final String KEY_SUGGEST_HINT_TYPE = "suggestHintType";
|
||||
public static final String KEY_PACKAGENAME = "packageName";
|
||||
public static final String KEY_PLATFORM = "platform";
|
||||
@ -155,12 +165,17 @@ public class EntranceUtils {
|
||||
public static final String KEY_WEB_SHARE = "webShare";
|
||||
public static final String KEY_ACTIVITY_NAME = "activityName";//活动名称
|
||||
public static final String KEY_REQUIRE_REDIRECT = "require_redirect"; // 标记需要再跳转
|
||||
public static final String KEY_FIELD_ID = "field_id"; // 专区板块id
|
||||
public static final String KEY_SECTION_NAME = "section_name"; // 专区专题名
|
||||
public static final String KEY_COLUMNNAME = "columnName";
|
||||
public static final String KEY_QA_ID = "qaId";
|
||||
public static final String KEY_QA_COLLECTION_ID = "qaCollectionId";
|
||||
public static final String KEY_SHOW_EDIT_DRAFT = "showEditDraft";
|
||||
public static final String KEY_ARTICLE_OPEN_IN_NEW_PAGE = "openArticleInNewPage";
|
||||
public static final String KEY_ONLY_CREATE_DRAFT = "onlyCreateDraft";
|
||||
public static final String KEY_KAIFU_SELECT_TIME = "kaifuSelectTime";
|
||||
public static final String KEY_POSTER_PATH = "posterPath";
|
||||
public static final String KEY_BLACK_THEME = "blackTheme";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
@ -3,10 +3,11 @@ package com.gh.common.util
|
||||
import android.animation.Animator
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.text.Editable
|
||||
import android.text.Html
|
||||
import android.text.Spanned
|
||||
import android.text.TextWatcher
|
||||
import android.os.Build
|
||||
import android.text.*
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.ImageSpan
|
||||
import android.text.style.URLSpan
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
@ -18,16 +19,23 @@ import androidx.core.text.HtmlCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.*
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.DefaultUrlHandler
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.view.CenterImageSpan
|
||||
import com.gh.common.view.CustomLinkMovementMethod
|
||||
import com.gh.common.view.ExpandTextView
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
@ -35,7 +43,9 @@ import io.reactivex.disposables.Disposable
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
@ -191,6 +201,28 @@ inline fun <reified T : Any> T.toJson(): String {
|
||||
return GsonUtils.toJson(this)
|
||||
}
|
||||
|
||||
fun String.insert(index: Int, string: String): String {
|
||||
return this.substring(0, index) + string + this.substring(index, this.length)
|
||||
}
|
||||
|
||||
/**
|
||||
* TextView 内部处理 ul li ol 得跟 Android 版本走,这里换成专属的标签手动处理
|
||||
*/
|
||||
fun String.replaceUnsupportedHtmlTag(): String {
|
||||
return this.replace("<ul", "<hul")
|
||||
.replace("</ul>", "</hul>")
|
||||
.replace("<li", "<hli")
|
||||
.replace("</li>", "</hli>")
|
||||
.replace("<ol", "<hol")
|
||||
.replace("</ol>", "</hol>")
|
||||
}
|
||||
|
||||
fun String.containHtmlTag(): Boolean {
|
||||
val pattern = Pattern.compile("<(\"[^\"]*\"|'[^']*'|[^'\">])*>")
|
||||
val matcher = pattern.matcher(this)
|
||||
return matcher.find()
|
||||
}
|
||||
|
||||
/**
|
||||
* 在限定 interval 里只触发一次 action
|
||||
*/
|
||||
@ -246,6 +278,15 @@ fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动抛出异常
|
||||
*/
|
||||
fun throwException(message: String = "", predicate: Boolean = true) {
|
||||
if (predicate) {
|
||||
throw RuntimeException(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String related
|
||||
*/
|
||||
@ -285,6 +326,17 @@ fun String.subStringIfPossible(length: Int): String {
|
||||
}
|
||||
}
|
||||
|
||||
fun String.countOccurrences(char: String): Int {
|
||||
return StringTokenizer(" $this ", char).countTokens() - 1
|
||||
}
|
||||
|
||||
fun String.getFirstElementDividedByDivider(divider: String): String {
|
||||
if (this.contains(divider)) {
|
||||
return this.split(divider.toRegex()).toTypedArray()[0]
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun String.copyTextAndToast(toastText: String = "复制成功") {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
@ -442,6 +494,75 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截 TextView 中的 Url Span,用应用内页面的形式打开链接
|
||||
* @param shrankText 未展开时的文字
|
||||
* @param expandedText 展开后的文字
|
||||
*/
|
||||
fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence, expandedText: CharSequence) {
|
||||
var shrankSsb = shrankText.interceptUrlSpanAndRoundImageSpan()
|
||||
var expandedSsb = expandedText.interceptUrlSpanAndRoundImageSpan()
|
||||
|
||||
// 去掉旧版本 Android 系统 [Html.FROM_HTML_MODE_LEGACY] 产生的两个换行符 (丑陋的代码)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
while (shrankSsb.contains("\n\n")) {
|
||||
val index = shrankSsb.indexOf("\n\n", 0, true)
|
||||
shrankSsb = SpannableStringBuilder(shrankSsb.subSequence(0, index)).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length))
|
||||
}
|
||||
while (expandedSsb.contains("\n\n")) {
|
||||
val index = expandedSsb.indexOf("\n\n", 0, true)
|
||||
expandedSsb = SpannableStringBuilder(expandedSsb.subSequence(0, index)).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length))
|
||||
}
|
||||
}
|
||||
|
||||
// 去掉多余的 P 标签换行
|
||||
if (expandedSsb.endsWith("\n", true)) {
|
||||
expandedSsb = SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length)))
|
||||
}
|
||||
|
||||
movementMethod = CustomLinkMovementMethod.getInstance()
|
||||
|
||||
shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, shrankSsb, highlightedTextClickListener = null)
|
||||
expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, expandedSsb, highlightedTextClickListener = null)
|
||||
setShrankTextAndExpandedText(shrankSsb, expandedSsb)
|
||||
}
|
||||
|
||||
fun CharSequence.interceptUrlSpanAndRoundImageSpan(): SpannableStringBuilder {
|
||||
return SpannableStringBuilder.valueOf(this).apply {
|
||||
getSpans(0, length, URLSpan::class.java).forEach {
|
||||
setSpan(
|
||||
object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) {
|
||||
widget.context.startActivity(WebActivity.getIntent(widget.context, it.url, true))
|
||||
}
|
||||
}
|
||||
},
|
||||
getSpanStart(it),
|
||||
getSpanEnd(it),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
removeSpan(it)
|
||||
}
|
||||
|
||||
getSpans(0, length, ImageSpan::class.java).forEach {
|
||||
setSpan(
|
||||
CenterImageSpan(it.drawable),
|
||||
getSpanStart(it),
|
||||
getSpanEnd(it),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
removeSpan(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.toColor(): Int {
|
||||
return ContextCompat.getColor(HaloApp.getInstance().application, this)
|
||||
}
|
||||
@ -461,6 +582,17 @@ fun SimpleDraweeView.display(url: String) {
|
||||
ImageUtils.display(this, url)
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadEntity extension
|
||||
*/
|
||||
fun DownloadEntity.addMetaExtra(key: String, value: String?) {
|
||||
value?.let { meta[key] = value }
|
||||
}
|
||||
|
||||
fun DownloadEntity.getMetaExtra(key: String) : String {
|
||||
return meta[key] ?: ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Process related
|
||||
*/
|
||||
@ -473,7 +605,20 @@ inline fun Context.doOnMainProcessOnly(f: () -> Unit) {
|
||||
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
|
||||
f.invoke()
|
||||
} else {
|
||||
Utils.log("Block one useless sub process method call.")
|
||||
tryWithDefaultCatch {
|
||||
Utils.log("Block one useless sub process method call from ${Thread.currentThread().stackTrace[3].methodName} -> ${Thread.currentThread().stackTrace[2].methodName}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun doOnMainProcessOnly(f: () -> Unit) {
|
||||
val processName = PackageUtils.obtainProcessName(HaloApp.getInstance().application)
|
||||
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
|
||||
f.invoke()
|
||||
} else {
|
||||
tryWithDefaultCatch {
|
||||
Utils.log("Block one useless sub process method call from ${Thread.currentThread().stackTrace[3].methodName} -> ${Thread.currentThread().stackTrace[2].methodName}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,4 +707,41 @@ fun LottieAnimationView.doOnAnimationEnd(action: () -> Unit) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun String?.getExtension(): String? {
|
||||
this ?: return null
|
||||
|
||||
tryCatchInRelease {
|
||||
val lastDotIndex = this.lastIndexOf('.')
|
||||
return if (lastDotIndex == -1) null else this.substring(lastDotIndex + 1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查内容是否一致
|
||||
* @return true:相同 false:不同
|
||||
*/
|
||||
fun List<String>?.checkSameFromStringArray(check2: List<String>?): Boolean {
|
||||
if (this == check2) {
|
||||
return true
|
||||
}
|
||||
if (this == null && check2 == null) {
|
||||
return true
|
||||
}
|
||||
if (this == null || check2 == null) {
|
||||
return false
|
||||
}
|
||||
if (this.size != check2.size) {
|
||||
return false
|
||||
}
|
||||
for (tag in this) {
|
||||
if (!check2.contains(tag)) return false
|
||||
}
|
||||
for (tag in check2) {
|
||||
if (!this.contains(tag)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
183
app/src/main/java/com/gh/common/util/ExtraTagHandler.kt
Normal file
183
app/src/main/java/com/gh/common/util/ExtraTagHandler.kt
Normal file
@ -0,0 +1,183 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.text.Editable
|
||||
import android.text.Html.TagHandler
|
||||
import android.text.Spanned
|
||||
import android.text.style.BulletSpan
|
||||
import android.text.style.LeadingMarginSpan
|
||||
import android.util.Log
|
||||
import org.xml.sax.XMLReader
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Implements support for ordered (`<ol>`) and unordered (`<ul>`) lists in to Android TextView.
|
||||
*
|
||||
*
|
||||
* This can be used as follows:<br></br>
|
||||
* `textView.setText(Html.fromHtml("<ul><li>item 1</li><li>item 2</li></ul>", null, new HtmlListTagHandler()));`
|
||||
*
|
||||
*
|
||||
* Implementation based on code by Juha Kuitunen (https://bitbucket.org/Kuitsi/android-textview-html-list),
|
||||
* released under Apache License v2.0. Refactored & improved by Matthias Stevens (InThePocket.mobi).
|
||||
*
|
||||
*
|
||||
* **Known issues:**
|
||||
* * The indentation on nested `<ul>`s isn't quite right (TODO fix this)
|
||||
* * the `start` attribute of `<ol>` is not supported. Doing so is tricky because
|
||||
* [Html.TagHandler.handleTag] does not expose tag attributes.
|
||||
* The only way to do it would be to use reflection to access the attribute information kept by the XMLReader
|
||||
* (see: http://stackoverflow.com/a/24534689/1084488).
|
||||
*
|
||||
* https://bitbucket.org/Kuitsi/android-textview-html-list/src/master/app/src/main/java/fi/iki/kuitsi/listtest/MyTagHandler.java
|
||||
*
|
||||
*/
|
||||
class ExtraTagHandler : TagHandler {
|
||||
/**
|
||||
* Keeps track of lists (ol, ul). On bottom of Stack is the outermost list
|
||||
* and on top of Stack is the most nested list
|
||||
*/
|
||||
private val lists = Stack<ListTag>()
|
||||
|
||||
/**
|
||||
* @see android.text.Html.TagHandler.handleTag
|
||||
*/
|
||||
override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader) {
|
||||
if (UL_TAG.equals(tag, ignoreCase = true)) {
|
||||
if (opening) { // handle <ul>
|
||||
lists.push(Ul())
|
||||
} else { // handle </ul>
|
||||
lists.pop()
|
||||
}
|
||||
} else if (OL_TAG.equals(tag, ignoreCase = true)) {
|
||||
if (opening) { // handle <ol>
|
||||
lists.push(Ol()) // use default start index of 1
|
||||
} else { // handle </ol>
|
||||
lists.pop()
|
||||
}
|
||||
} else if (LI_TAG.equals(tag, ignoreCase = true)) {
|
||||
if (opening) { // handle <li>
|
||||
lists.peek().openItem(output)
|
||||
} else { // handle </li>
|
||||
lists.peek().closeItem(output, lists.size)
|
||||
}
|
||||
} else {
|
||||
Log.d("TagHandler", "Found an unsupported tag $tag")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract super class for [Ul] and [Ol].
|
||||
*/
|
||||
private abstract class ListTag {
|
||||
/**
|
||||
* Opens a new list item.
|
||||
*
|
||||
* @param text
|
||||
*/
|
||||
open fun openItem(text: Editable) {
|
||||
if (text.length > 0 && text[text.length - 1] != '\n') {
|
||||
text.append("\n")
|
||||
}
|
||||
val len = text.length
|
||||
text.setSpan(this, len, len, Spanned.SPAN_MARK_MARK)
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a list item.
|
||||
*
|
||||
* @param text
|
||||
* @param indentation
|
||||
*/
|
||||
fun closeItem(text: Editable, indentation: Int) {
|
||||
if (text.length > 0 && text[text.length - 1] != '\n') {
|
||||
text.append("\n")
|
||||
}
|
||||
val replaces = getReplaces(text, indentation)
|
||||
val len = text.length
|
||||
val listTag = getLast(text)
|
||||
val where = text.getSpanStart(listTag)
|
||||
text.removeSpan(listTag)
|
||||
if (where != len) {
|
||||
for (replace in replaces) {
|
||||
text.setSpan(replace, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun getReplaces(text: Editable?, indentation: Int): Array<Any>
|
||||
|
||||
/**
|
||||
* Note: This knows that the last returned object from getSpans() will be the most recently added.
|
||||
*
|
||||
* @see Html
|
||||
*/
|
||||
private fun getLast(text: Spanned): ListTag? {
|
||||
val listTags = text.getSpans(0, text.length, ListTag::class.java)
|
||||
return if (listTags.size == 0) {
|
||||
null
|
||||
} else listTags[listTags.size - 1]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing the unordered list (`<ul>`) HTML tag.
|
||||
*/
|
||||
private class Ul : ListTag() {
|
||||
override fun getReplaces(text: Editable?, indentation: Int): Array<Any> {
|
||||
// Nested BulletSpans increases distance between BULLET_SPAN and text, so we must prevent it.
|
||||
var bulletMargin = INDENT_PX
|
||||
if (indentation > 1) {
|
||||
bulletMargin = INDENT_PX - BULLET_SPAN.getLeadingMargin(true)
|
||||
if (indentation > 2) {
|
||||
// This get's more complicated when we add a LeadingMarginSpan into the same line:
|
||||
// we have also counter it's effect to BulletSpan
|
||||
bulletMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX
|
||||
}
|
||||
}
|
||||
return arrayOf(
|
||||
LeadingMarginSpan.Standard(LIST_ITEM_INDENT_PX * (indentation - 1)),
|
||||
BulletSpan(bulletMargin)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing the ordered list (`<ol>`) HTML tag.
|
||||
*/
|
||||
private class Ol
|
||||
/**
|
||||
* Creates a new `<ul>` with start index of 1.
|
||||
*/ @JvmOverloads constructor(private var nextIdx: Int = 1) : ListTag() {
|
||||
override fun openItem(text: Editable) {
|
||||
super.openItem(text)
|
||||
text.append(Integer.toString(nextIdx++)).append(". ")
|
||||
}
|
||||
|
||||
override fun getReplaces(text: Editable?, indentation: Int): Array<Any> {
|
||||
var numberMargin = LIST_ITEM_INDENT_PX * (indentation - 1)
|
||||
if (indentation > 2) {
|
||||
// Same as in ordered lists: counter the effect of nested Spans
|
||||
numberMargin -= (indentation - 2) * LIST_ITEM_INDENT_PX
|
||||
}
|
||||
return arrayOf(LeadingMarginSpan.Standard(numberMargin))
|
||||
}
|
||||
/**
|
||||
* Creates a new `<ul>` with given start index.
|
||||
*
|
||||
* @param nextIdx
|
||||
*/
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val OL_TAG = "hol"
|
||||
private const val UL_TAG = "hul"
|
||||
private const val LI_TAG = "hli"
|
||||
|
||||
/**
|
||||
* List indentation in pixels. Nested lists use multiple of this.
|
||||
*/
|
||||
private const val INDENT_PX = 10
|
||||
private const val LIST_ITEM_INDENT_PX = INDENT_PX * 2
|
||||
private val BULLET_SPAN = BulletSpan(INDENT_PX)
|
||||
}
|
||||
}
|
||||
@ -1,19 +1,28 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.TextUtils
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
/**
|
||||
* 首页补充游戏库辅助类
|
||||
*/
|
||||
object GameRepositoryHelper {
|
||||
object GameSubstituteRepositoryHelper {
|
||||
|
||||
private const val KEY_GAME_REPOSITORY = "game_repository"
|
||||
private const val KEY_GAME_REPOSITORY = "game_substitute_repository"
|
||||
|
||||
private var mSubstitutableGameIdSet = hashSetOf<String>()
|
||||
private var mApi = RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
private val mSensitiveApi = RetrofitManager.getInstance(HaloApp.getInstance().application).sensitiveApi
|
||||
private var mApplicationContext = HaloApp.getInstance().application
|
||||
|
||||
var gameCollectionList: List<SubjectEntity> = arrayListOf()
|
||||
|
||||
@ -25,11 +34,8 @@ object GameRepositoryHelper {
|
||||
* 获取游戏补充库
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getGameRepository(context: Context) {
|
||||
|
||||
RetrofitManager.getInstance(context)
|
||||
.api
|
||||
.reserveColumns
|
||||
fun updateGameSubstituteRepository() {
|
||||
mSensitiveApi.reserveColumns
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Response<List<SubjectEntity>>() {
|
||||
override fun onResponse(response: List<SubjectEntity>?) {
|
||||
@ -38,27 +44,41 @@ object GameRepositoryHelper {
|
||||
updateGameRepository(response)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@SuppressLint("CheckResult")
|
||||
fun updateSubstitutableGames() {
|
||||
mApplicationContext.doOnMainProcessOnly {
|
||||
val single = if (UserManager.getInstance().isLoggedIn) {
|
||||
mApi.getIdListOfPlayedGames(UserManager.getInstance().userId, Utils.getTime(mApplicationContext))
|
||||
} else {
|
||||
mApi.getIdListOfDownloadedGames(HaloApp.getInstance().gid, Utils.getTime(mApplicationContext))
|
||||
}
|
||||
single.subscribeOn(Schedulers.io()).subscribe(object : BiResponse<List<String>>() {
|
||||
override fun onSuccess(data: List<String>) {
|
||||
mSubstitutableGameIdSet = data.toHashSet()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新内存中的游戏库(即从 SP 中再读一次)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun refreshGameRepository() = loadSavedRepository()
|
||||
fun refreshRepositoryFromLocal() = loadSavedRepository()
|
||||
|
||||
private fun loadSavedRepository() {
|
||||
gameCollectionList = SPUtils.getString(KEY_GAME_REPOSITORY).toObject() ?: arrayListOf()
|
||||
}
|
||||
|
||||
fun updateGameRepository(subjects: List<SubjectEntity>?) {
|
||||
|
||||
private fun updateGameRepository(subjects: List<SubjectEntity>?) {
|
||||
if (subjects == null) return
|
||||
|
||||
SPUtils.setString(KEY_GAME_REPOSITORY, subjects.toJson())
|
||||
|
||||
gameCollectionList = subjects
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +86,7 @@ object GameRepositoryHelper {
|
||||
* @param collectionId 补充游戏库相应专题 ID
|
||||
* @param gameIdList 该专题里已经包含的游戏 ID 列表
|
||||
*/
|
||||
fun getOneUniqueGame(collectionId: String?, gameIdList: HashSet<String>): GameEntity? {
|
||||
private fun getOneUniqueGame(collectionId: String?, gameIdList: HashSet<String>): GameEntity? {
|
||||
collectionId?.let {
|
||||
val collection = gameCollectionList.find { it.id == collectionId }
|
||||
collection?.let {
|
||||
@ -82,10 +102,13 @@ object GameRepositoryHelper {
|
||||
return null
|
||||
}
|
||||
|
||||
fun replaceInstalledApp(gameList: MutableList<GameEntity>,
|
||||
alreadyDisplayedGameIdSet: HashSet<String>,
|
||||
relatedCollectionId: String,
|
||||
shouldLogReplaceEvent: Boolean) {
|
||||
/**
|
||||
* 替换游戏,包括 已安装,历史下载,历史已安装等类型
|
||||
*/
|
||||
fun replaceGames(gameList: MutableList<GameEntity>,
|
||||
alreadyDisplayedGameIdSet: HashSet<String>,
|
||||
relatedCollectionId: String,
|
||||
shouldLogReplaceEvent: Boolean) {
|
||||
val positionOfTheGameToReplaceList = arrayListOf<Int>()
|
||||
|
||||
// 标记需要替换的已安装游戏
|
||||
@ -96,23 +119,32 @@ object GameRepositoryHelper {
|
||||
continue
|
||||
}
|
||||
|
||||
var isThisPositionAdded = false
|
||||
var isThisPositionLabeled = false
|
||||
|
||||
// 从 游戏ID 判断当前游戏是否需要被替换
|
||||
if (mSubstitutableGameIdSet.contains(game.id)) {
|
||||
positionOfTheGameToReplaceList.add(index)
|
||||
isThisPositionLabeled = true
|
||||
}
|
||||
|
||||
// 检查是否已安装该游戏里同包名的 APK
|
||||
for (apk in game.getApk()) {
|
||||
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
|
||||
// 将该位置的游戏标记为需要替换
|
||||
positionOfTheGameToReplaceList.add(index)
|
||||
isThisPositionAdded = true
|
||||
break
|
||||
if (!isThisPositionLabeled) {
|
||||
for (apk in game.getApk()) {
|
||||
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
|
||||
// 将该位置的游戏标记为需要替换
|
||||
positionOfTheGameToReplaceList.add(index)
|
||||
isThisPositionLabeled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
|
||||
if (!isThisPositionAdded) {
|
||||
if (!isThisPositionLabeled) {
|
||||
var relatedPackageList = arrayListOf<String>()
|
||||
for (entity in PackageHelper.relatedPackageList) {
|
||||
if (entity.gameId == game.id) {
|
||||
relatedPackageList = ArrayList(entity.packages)
|
||||
relatedPackageList = ArrayList(entity.packages!!)
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -139,14 +171,17 @@ object GameRepositoryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun isThisGameUnique(game: GameEntity, gameIdList: HashSet<String>): Boolean {
|
||||
// 若该补充游戏已经存在关联关系,判定为非唯一
|
||||
// 判断该游戏是否出现在已安装列表
|
||||
if (mSubstitutableGameIdSet.contains(game.id)) return false
|
||||
|
||||
// 该补充游戏是否已经存在关联关系
|
||||
for (relatedId in game.relatedGameIds!!) {
|
||||
if (gameIdList.contains(relatedId)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for (apk in game.getApk()) {
|
||||
// 检查本地是否已安装该游戏,已过滤那部分框架服务的包名
|
||||
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
|
||||
@ -5,6 +5,8 @@ import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.gamecenter.R;
|
||||
@ -22,9 +24,6 @@ import com.lightgame.download.DownloadStatus;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
|
||||
public class GameUtils {
|
||||
|
||||
/**
|
||||
@ -183,6 +182,8 @@ public class GameUtils {
|
||||
GameUpdateEntity gameUpdateEntity = new GameUpdateEntity();
|
||||
gameUpdateEntity.setId(gameEntity.getId());
|
||||
gameUpdateEntity.setIcon(gameEntity.getIcon());
|
||||
gameUpdateEntity.setRawIcon(gameEntity.getRawIcon());
|
||||
gameUpdateEntity.setIconSubscript(gameEntity.getIconSubscript());
|
||||
gameUpdateEntity.setName(gameEntity.getName());
|
||||
gameUpdateEntity.setPackageName(apkEntity.getPackageName());
|
||||
gameUpdateEntity.setSize(apkEntity.getSize());
|
||||
@ -199,6 +200,7 @@ public class GameUtils {
|
||||
gameUpdateEntity.setDownload(gameEntity.getDownload());
|
||||
gameUpdateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
|
||||
gameUpdateEntity.setPluginDesc(gameEntity.getPluginDesc());
|
||||
gameUpdateEntity.setFormat(apkEntity.getFormat());
|
||||
|
||||
GameCollectionEntity pluggableCollection = getPluggableCollectionFromGameEntity(gameEntity, apkEntity.getPackageName());
|
||||
if (pluggableCollection != null) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import org.json.JSONArray
|
||||
|
||||
@ -10,6 +11,7 @@ import org.json.JSONArray
|
||||
*/
|
||||
object GsonUtils {
|
||||
val gson: Gson = Gson()
|
||||
val gsonThatIgnoreNull: Gson = GsonBuilder().serializeNulls().create()
|
||||
|
||||
@JvmStatic
|
||||
fun <T> fromJson(json: String, t: Class<T>): T {
|
||||
@ -32,4 +34,9 @@ object GsonUtils {
|
||||
fun toJson(any: Any?): String {
|
||||
return gson.toJson(any)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun toJsonIgnoreNull(any: Any?): String {
|
||||
return gsonThatIgnoreNull.toJson(any)
|
||||
}
|
||||
}
|
||||
50
app/src/main/java/com/gh/common/util/HomePluggableHelper.kt
Normal file
50
app/src/main/java/com/gh/common/util/HomePluggableHelper.kt
Normal file
@ -0,0 +1,50 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.HomePluggableFilterEntity
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object HomePluggableHelper {
|
||||
|
||||
private val mHomePluggableFilterDao = AppDatabase.getInstance(HaloApp.getInstance().application).homePluggableFilterDao()
|
||||
|
||||
@JvmStatic
|
||||
fun setHomePluggableFilterData(gameEntity: GameEntity, isNever: Boolean) {
|
||||
val apkList = gameEntity.getApk()
|
||||
if (apkList.isNotEmpty()) {
|
||||
val apk = apkList.first()
|
||||
val tag = if (isNever) "never" else apk.version ?: ""
|
||||
mHomePluggableFilterDao.addData(HomePluggableFilterEntity(pkgName = apk.packageName, tag = tag, active = isNever))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showHomePluggable(gameEntity: GameEntity): Boolean {
|
||||
val apkList = gameEntity.getApk()
|
||||
if (apkList.isNotEmpty()) {
|
||||
val apk = apkList.first()
|
||||
val filterData = mHomePluggableFilterDao.getDataByPkgName(apk.packageName)
|
||||
if (filterData?.active == true) {
|
||||
val filterTag = filterData.tag
|
||||
return filterTag != "never" && apk.version != filterTag
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPermanentInactivePluggablePackage() = mHomePluggableFilterDao.getDataByTag("never")
|
||||
|
||||
@JvmStatic
|
||||
fun activationFilterData() {
|
||||
val filterList = mHomePluggableFilterDao.getDataByActive(false)
|
||||
|
||||
if (filterList != null) {
|
||||
for (entity in filterList) {
|
||||
entity.active = true
|
||||
}
|
||||
mHomePluggableFilterDao.addData(filterList)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
@ -9,21 +10,21 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.facebook.common.executors.CallerThreadExecutor
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.controller.BaseControllerListener
|
||||
import com.facebook.drawee.controller.ControllerListener
|
||||
import com.facebook.drawee.drawable.ScalingUtils
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.facebook.imagepipeline.core.ImagePipeline
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
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.halo.assistant.HaloApp
|
||||
import com.squareup.picasso.Picasso
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
|
||||
@ -216,17 +217,21 @@ object ImageUtils {
|
||||
.build()
|
||||
}
|
||||
|
||||
// 获取bitmap
|
||||
// 获取bitmap (使用 fresco 获取 gif bitmap 会为空,https://github.com/facebook/fresco/issues/241)
|
||||
// 所以这里换用 picasso
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun display(context: Context?, url: String?, dataSubscriber: BaseBitmapDataSubscriber) {
|
||||
val imageRequest = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(url))
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build()
|
||||
|
||||
Fresco.getImagePipeline()
|
||||
.fetchDecodedImage(imageRequest, context)
|
||||
.subscribe(dataSubscriber, CallerThreadExecutor.getInstance())
|
||||
fun getBitmap(url: String, callback: BiCallback<Bitmap, Boolean>) {
|
||||
Single.just(url)
|
||||
.map { Picasso.with(HaloApp.getInstance().application).load(url).priority(Picasso.Priority.HIGH).get() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
callback.onFirst(it)
|
||||
}, {
|
||||
callback.onSecond(true)
|
||||
it.printStackTrace()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -327,7 +332,7 @@ object ImageUtils {
|
||||
|
||||
//预加载图片
|
||||
@JvmStatic
|
||||
fun prefetchToDiskCache(url: String){
|
||||
fun prefetchToDiskCache(url: String) {
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val imageRequest = ImageRequest.fromUri(url)
|
||||
imagePipeline.prefetchToDiskCache(imageRequest, HaloApp.getInstance().application)
|
||||
@ -337,4 +342,7 @@ object ImageUtils {
|
||||
fun onLoadFinal(imageInfo: ImageInfo?)
|
||||
}
|
||||
|
||||
fun getVideoSnapshot(videoUrl: String, progress: Long): String {
|
||||
return "$videoUrl?x-oss-process=video/snapshot,t_$progress,f_jpg,w_0,h_0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,12 +6,16 @@ import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.exposure.ExposureEntity;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureSource;
|
||||
import com.gh.common.exposure.meta.Meta;
|
||||
import com.gh.common.exposure.meta.MetaUtil;
|
||||
import com.gh.common.loghub.LoghubUtils;
|
||||
import com.gh.download.DownloadDataHelper;
|
||||
import com.gh.common.loghub.SimpleLogContainerEntity;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.entity.CommunityEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
@ -19,7 +23,6 @@ import com.gh.gamecenter.entity.SpecialColumn;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
@ -29,8 +32,6 @@ import org.json.JSONObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by khy on 2/01/18.
|
||||
*/
|
||||
@ -53,55 +54,6 @@ public class LogUtils {
|
||||
uploadVideoStreaming(object);
|
||||
}
|
||||
|
||||
public static void uploadDownloadEvent(DownloadEntity downloadEntity) {
|
||||
Context context = HaloApp.getInstance().getApplication();
|
||||
Meta meta = MetaUtil.INSTANCE.getMeta();
|
||||
JSONObject object = new JSONObject();
|
||||
|
||||
try {
|
||||
object.put("event", DownloadDataHelper.getDownloadStatusAlias(downloadEntity));
|
||||
object.put("msg", downloadEntity.getError());
|
||||
object.put("status", downloadEntity.getStatus().getStatus());
|
||||
|
||||
// payload
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
payloadObject.put("game_id", downloadEntity.getGameId());
|
||||
payloadObject.put("gameName", downloadEntity.getName());
|
||||
payloadObject.put("platform", downloadEntity.getPlatform());
|
||||
payloadObject.put("package", downloadEntity.getPackageName());
|
||||
payloadObject.put("filename", downloadEntity.getPath().substring(downloadEntity.getPath().lastIndexOf("/") + 1));
|
||||
payloadObject.put("total_size", (downloadEntity.getSize() / 1024 / 1024));
|
||||
payloadObject.put("completed_size", (downloadEntity.getProgress() / 1024 / 1024));
|
||||
|
||||
object.put("payload", payloadObject);
|
||||
|
||||
// meta
|
||||
JSONObject metaObject = new JSONObject();
|
||||
metaObject.put("android_id", meta.getAndroid_id());
|
||||
metaObject.put("android_sdk", meta.getAndroid_sdk());
|
||||
metaObject.put("android_version", meta.getAndroid_version());
|
||||
metaObject.put("appVersion", meta.getAppVersion());
|
||||
metaObject.put("channel", meta.getChannel());
|
||||
metaObject.put("gid", meta.getGid());
|
||||
metaObject.put("imei", meta.getImei());
|
||||
metaObject.put("mac", meta.getMac());
|
||||
metaObject.put("manufacturer", meta.getManufacturer());
|
||||
metaObject.put("model", meta.getModel());
|
||||
metaObject.put("network", DeviceUtils.getNetwork(context));
|
||||
metaObject.put("os", meta.getOs());
|
||||
metaObject.put("userId", meta.getUserId());
|
||||
|
||||
object.put("meta", metaObject);
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
LoghubUtils.log(object, "download_debug", false);
|
||||
}
|
||||
|
||||
public static void uploadCommunityArticle(String tracers, String articleId, String articleTitle, int readTime, CommunityEntity community, SpecialColumn specialColumn) {
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
@ -283,7 +235,7 @@ public class LogUtils {
|
||||
|
||||
uploadToReservation(object);
|
||||
}
|
||||
|
||||
|
||||
private static void uploadToCommunity(JSONObject object) {
|
||||
uploadToCommunity(object, false);
|
||||
}
|
||||
@ -419,4 +371,138 @@ public class LogUtils {
|
||||
}
|
||||
uploadVideoStreaming(object);
|
||||
}
|
||||
|
||||
public static void uploadWelcomeDialog(String action, String dialogId, String linkTitle) {
|
||||
ExposureEntity payload = new ExposureEntity();
|
||||
payload.setWelcomeDialogId(dialogId);
|
||||
payload.setWelcomeDialogId(linkTitle);
|
||||
|
||||
SimpleLogContainerEntity entity = new SimpleLogContainerEntity();
|
||||
entity.setEvent("dialog");
|
||||
entity.setAction(action);
|
||||
entity.setMeta(MetaUtil.INSTANCE.getMeta());
|
||||
entity.setPayload(payload);
|
||||
entity.setTimestamp(System.currentTimeMillis() / 1000);
|
||||
|
||||
LoghubUtils.log(GsonUtils.toJsonIgnoreNull(entity), "event", false);
|
||||
}
|
||||
|
||||
public static void uploadLikeFromWelcomeDialog() {
|
||||
String dialogId = (String) HaloApp.get(Constants.WELCOME_DIALOG_ID, false);
|
||||
String linkTitle = (String) HaloApp.get(Constants.WELCOME_DIALOG_LINK_TITLE, false);
|
||||
|
||||
ExposureEntity payload = new ExposureEntity();
|
||||
payload.setWelcomeDialogId(dialogId);
|
||||
payload.setWelcomeDialogLinkTitle(linkTitle);
|
||||
|
||||
SimpleLogContainerEntity entity = new SimpleLogContainerEntity();
|
||||
entity.setEvent("like");
|
||||
entity.setMeta(MetaUtil.INSTANCE.getMeta());
|
||||
entity.setPayload(payload);
|
||||
entity.setTimestamp(System.currentTimeMillis() / 1000);
|
||||
|
||||
LoghubUtils.log(GsonUtils.toJsonIgnoreNull(entity), "event", false);
|
||||
}
|
||||
|
||||
public static void uploadCommentFromWelcomeDialog() {
|
||||
String dialogId = (String) HaloApp.get(Constants.WELCOME_DIALOG_ID, false);
|
||||
String linkTitle = (String) HaloApp.get(Constants.WELCOME_DIALOG_LINK_TITLE, false);
|
||||
|
||||
ExposureEntity payload = new ExposureEntity();
|
||||
payload.setWelcomeDialogId(dialogId);
|
||||
payload.setWelcomeDialogLinkTitle(linkTitle);
|
||||
|
||||
SimpleLogContainerEntity entity = new SimpleLogContainerEntity();
|
||||
entity.setEvent("comment");
|
||||
entity.setMeta(MetaUtil.INSTANCE.getMeta());
|
||||
entity.setPayload(payload);
|
||||
entity.setTimestamp(System.currentTimeMillis() / 1000);
|
||||
|
||||
LoghubUtils.log(GsonUtils.toJsonIgnoreNull(entity), "event", false);
|
||||
}
|
||||
|
||||
private static void uploadShare(JSONObject object) {
|
||||
Meta meta = MetaUtil.INSTANCE.getMeta();
|
||||
JSONObject metaObject = new JSONObject();
|
||||
try {
|
||||
metaObject.put("android_id", meta.getAndroid_id());
|
||||
metaObject.put("android_sdk", meta.getAndroid_sdk());
|
||||
metaObject.put("android_version", meta.getAndroid_version());
|
||||
metaObject.put("appVersion", meta.getAppVersion());
|
||||
metaObject.put("channel", meta.getChannel());
|
||||
metaObject.put("gid", meta.getGid());
|
||||
metaObject.put("imei", meta.getImei());
|
||||
metaObject.put("mac", meta.getMac());
|
||||
metaObject.put("manufacturer", meta.getManufacturer());
|
||||
metaObject.put("model", meta.getModel());
|
||||
metaObject.put("network", meta.getNetwork());
|
||||
metaObject.put("os", meta.getOs());
|
||||
metaObject.put("userId", meta.getUserId());
|
||||
|
||||
object.put("event", "SHARE");
|
||||
object.put("meta", metaObject);
|
||||
object.put("timestamp", System.currentTimeMillis() / 1000);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->" + object.toString());
|
||||
}
|
||||
|
||||
LoghubUtils.log(object, "event", false);
|
||||
}
|
||||
|
||||
public static void uploadShareEnter(String entrance, String url, String title, String summary, String resourceId) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("action", "entrance_source");
|
||||
payloadObject.put("entrance", entrance);
|
||||
payloadObject.put("url", url);
|
||||
payloadObject.put("title", title);
|
||||
payloadObject.put("summary", summary);
|
||||
payloadObject.put("resource_id", resourceId);
|
||||
object.put("payload", payloadObject);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
uploadShare(object);
|
||||
}
|
||||
|
||||
public static void uploadShareType(String shareType, String entrance, String url, String title, String summary, String resourceId) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("action", "share_type");
|
||||
payloadObject.put("share_type", shareType);
|
||||
payloadObject.put("entrance", entrance);
|
||||
payloadObject.put("url", url);
|
||||
payloadObject.put("title", title);
|
||||
payloadObject.put("summary", summary);
|
||||
payloadObject.put("resource_id", resourceId);
|
||||
object.put("payload", payloadObject);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
uploadShare(object);
|
||||
}
|
||||
|
||||
public static void uploadShareResult(String shareType, String entrance, String shareResult, String url, String title, String summary, String resourceId) {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONObject payloadObject = new JSONObject();
|
||||
try {
|
||||
object.put("action", "share_result");
|
||||
payloadObject.put("share_type", shareType);
|
||||
payloadObject.put("entrance", entrance);
|
||||
payloadObject.put("share_result", shareResult);
|
||||
payloadObject.put("url", url);
|
||||
payloadObject.put("title", title);
|
||||
payloadObject.put("summary", summary);
|
||||
payloadObject.put("resource_id", resourceId);
|
||||
object.put("payload", payloadObject);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
uploadShare(object);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ import com.tencent.tauth.Tencent
|
||||
import com.tencent.tauth.UiError
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* 第三方登录辅助类
|
||||
@ -37,12 +37,12 @@ object LoginHelper {
|
||||
|
||||
private var mTencent: Tencent // QQ
|
||||
private var mIWXAPI: IWXAPI // 微信
|
||||
private var mSsoHandler: SsoHandler? = null // 微博 // TODO 完成回调时清掉这个 handler ?
|
||||
private var mSsoHandler: WeakReference<SsoHandler>? = null // 微博
|
||||
|
||||
private var mQqLoginListener: IUiListener
|
||||
|
||||
private var mAccessToken: Oauth2AccessToken? = null // weibo
|
||||
private var mLoginCallback: LoginCallback? = null
|
||||
private var mLoginCallback: WeakReference<LoginCallback>? = null
|
||||
|
||||
init {
|
||||
val context = HaloApp.getInstance().application.applicationContext
|
||||
@ -64,11 +64,11 @@ object LoginHelper {
|
||||
content.put("access_token_expire", Utils.getTime(context) + o.getLong("expires_in"))
|
||||
content.put("access_token", o.getString("access_token"))
|
||||
|
||||
mLoginCallback?.onLoginSuccess(LoginTag.qq, content) // 回调QQ登录成功
|
||||
mLoginCallback?.get()?.onLoginSuccess(LoginTag.qq, content) // 回调QQ登录成功
|
||||
} catch (e: JSONException) {
|
||||
val errorString = "QQ登录数据回调异常::$e"
|
||||
|
||||
mLoginCallback?.onLoginFailure(LoginTag.qq, errorString) // 回调QQ登录失败
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.qq, errorString) // 回调QQ登录失败
|
||||
|
||||
Utils.log(errorString)
|
||||
e.printStackTrace()
|
||||
@ -77,12 +77,12 @@ object LoginHelper {
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
mLoginCallback?.onLoginFailure(LoginTag.qq,"登录取消")
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.qq, "登录取消")
|
||||
Utils.log("QQ 登录取消")
|
||||
}
|
||||
|
||||
override fun onError(p0: UiError?) {
|
||||
mLoginCallback?.onLoginFailure(LoginTag.qq,"登录失败")
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.qq, "登录失败")
|
||||
Utils.log("QQ 登录失败")
|
||||
}
|
||||
}
|
||||
@ -99,23 +99,23 @@ object LoginHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun onWechatLoginSuccess(content: JSONObject) {
|
||||
mLoginCallback?.onLoginSuccess(LoginTag.wechat, content)
|
||||
mLoginCallback?.get()?.onLoginSuccess(LoginTag.wechat, content)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun onWechatLoginFailure(error: String) {
|
||||
mLoginCallback?.onLoginFailure(LoginTag.wechat, error)
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.wechat, error)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun onWeiboLoginCallback(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
mSsoHandler?.authorizeCallBack(requestCode, resultCode, data)
|
||||
mSsoHandler?.get()?.authorizeCallBack(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
// QQ登录
|
||||
@JvmStatic
|
||||
fun loginWithQQ(loginCallback: LoginCallback, activity: Activity) {
|
||||
mLoginCallback = loginCallback
|
||||
mLoginCallback = WeakReference(loginCallback)
|
||||
if (!mTencent.isSessionValid) {
|
||||
Utils.log("QQLogin")
|
||||
mTencent.login(activity, "all", mQqLoginListener)
|
||||
@ -132,7 +132,7 @@ object LoginHelper {
|
||||
// 微信登录
|
||||
@JvmStatic
|
||||
fun loginWithWechat(loginCallback: LoginCallback) {
|
||||
mLoginCallback = loginCallback
|
||||
mLoginCallback = WeakReference(loginCallback)
|
||||
val register = mIWXAPI.registerApp(Config.WECHAT_APPID)
|
||||
|
||||
val req = SendAuth.Req()
|
||||
@ -149,9 +149,9 @@ object LoginHelper {
|
||||
// 微博登录
|
||||
@JvmStatic
|
||||
fun loginWithWeibo(loginCallback: LoginCallback, context: Activity) {
|
||||
mLoginCallback = loginCallback
|
||||
mSsoHandler = SsoHandler(context)
|
||||
mSsoHandler?.authorizeClientSso(object : WbAuthListener {
|
||||
mLoginCallback = WeakReference(loginCallback)
|
||||
mSsoHandler = WeakReference(SsoHandler(context))
|
||||
mSsoHandler?.get()?.authorizeClientSso(object : WbAuthListener {
|
||||
override fun onSuccess(token: Oauth2AccessToken?) {
|
||||
token?.let {
|
||||
RuntimeUtils.getInstance().runOnUiThread {
|
||||
@ -159,7 +159,7 @@ object LoginHelper {
|
||||
if (mAccessToken?.isSessionValid == true) {
|
||||
// 保存 Token 到 SharedPreferences
|
||||
AccessTokenKeeper.writeAccessToken(context, mAccessToken)
|
||||
Toast.makeText(context, "授权成功", Toast.LENGTH_SHORT).show()
|
||||
Utils.toast(context, "授权成功")
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,17 +170,17 @@ object LoginHelper {
|
||||
content.put("access_token_expire", Utils.getTime(context) + token.expiresTime)
|
||||
content.put("refresh_token", token.refreshToken)
|
||||
// content.put("refresh_token_expire", Utils.getTime(mContext) + 86400 * 30); // refresh_token 有效期30天
|
||||
mLoginCallback?.onLoginSuccess(LoginTag.weibo, content)// 微博 登录回调
|
||||
mLoginCallback?.get()?.onLoginSuccess(LoginTag.weibo, content)// 微博 登录回调
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(p0: WbConnectErrorMessage?) {
|
||||
mLoginCallback?.onLoginFailure(LoginTag.weibo, "微博登录需要客户端支持,请先安装微博")
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.weibo, "微博登录需要客户端支持,请先安装微博")
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
mLoginCallback?.onLoginFailure(LoginTag.weibo, "取消授权")
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.weibo, "取消授权")
|
||||
}
|
||||
})
|
||||
// 第一次启动本应用,AccessToken 不可用
|
||||
|
||||
@ -55,6 +55,7 @@ public class LoginUtils {
|
||||
@Override
|
||||
public void onFailure(HttpException e) {
|
||||
super.onFailure(e);
|
||||
listener.onCaptcha(null);
|
||||
if (e == null) {
|
||||
Utils.toast(context, "无法获取验证码,请检查你的网络状态");
|
||||
return;
|
||||
|
||||
@ -4,6 +4,8 @@ import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.entity.NewsEntity;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
@ -78,7 +80,7 @@ public class NewsUtils {
|
||||
/**
|
||||
* 设置新闻类型
|
||||
*/
|
||||
public static void setNewsType(TextView textView, String type, int priority, int position) {
|
||||
public static void setNewsType(TextView textView, @Nullable String type, int priority, int position) {
|
||||
if (priority != 0) {
|
||||
if (position == 0) {
|
||||
textView.setText(R.string.article_top);
|
||||
@ -92,7 +94,7 @@ public class NewsUtils {
|
||||
}
|
||||
|
||||
textView.setTextColor(Color.WHITE);
|
||||
switch (type) {
|
||||
switch (type != null ? type : "") {
|
||||
case "活动":
|
||||
textView.setBackgroundResource(R.drawable.textview_orange_style);
|
||||
break;
|
||||
|
||||
@ -96,7 +96,7 @@ object NotificationHelper {
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun show(activity: AppCompatActivity?) {
|
||||
fun show(activity: AppCompatActivity?) {
|
||||
if (activity == null) return
|
||||
RetrofitManager.getInstance(activity).api.bootPopup
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
@ -16,6 +16,18 @@ object NumberUtils {
|
||||
}
|
||||
return s
|
||||
}
|
||||
@JvmStatic
|
||||
fun transSimpleLetterCount(count: Int): String {
|
||||
val s: String
|
||||
s = if (count > 10000) {
|
||||
val number = count / 10000f
|
||||
val fmt = DecimalFormat("#.0")
|
||||
fmt.format(number) + "W"
|
||||
} else {
|
||||
count.toString()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun transSimpleUsageTime(second: Long): String {
|
||||
|
||||
88
app/src/main/java/com/gh/common/util/OssUploadUtils.kt
Normal file
88
app/src/main/java/com/gh/common/util/OssUploadUtils.kt
Normal file
@ -0,0 +1,88 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.alibaba.sdk.android.oss.ClientConfiguration
|
||||
import com.alibaba.sdk.android.oss.ClientException
|
||||
import com.alibaba.sdk.android.oss.OSSClient
|
||||
import com.alibaba.sdk.android.oss.ServiceException
|
||||
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
|
||||
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
|
||||
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask
|
||||
import com.alibaba.sdk.android.oss.model.PutObjectRequest
|
||||
import com.alibaba.sdk.android.oss.model.PutObjectResult
|
||||
import com.gh.gamecenter.entity.OssEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
|
||||
object OssUploadUtils {
|
||||
//上传文件类型
|
||||
enum class UploadType(val value: String) {
|
||||
GAME("game")//后缀apk
|
||||
}
|
||||
|
||||
//获取Oss配置
|
||||
private fun getOssUpdateConfig(type: UploadType): Single<OssEntity> {
|
||||
return RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api
|
||||
.getOssUpdateConfig(type.value)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
}
|
||||
|
||||
//异步上传文件
|
||||
@JvmStatic
|
||||
fun uploadFile(path: String, uploadType: UploadType, listener: OnUploadFileListener?): Disposable {
|
||||
return getOssUpdateConfig(uploadType)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.flatMap { mOssEntity ->
|
||||
Single.create<String> {
|
||||
val conf = ClientConfiguration()
|
||||
conf.connectionTimeout = 15 * 1000
|
||||
conf.socketTimeout = 15 * 1000
|
||||
conf.maxConcurrentRequest = 5
|
||||
conf.maxErrorRetry = 2
|
||||
|
||||
val credentialProvider = OSSStsTokenCredentialProvider(mOssEntity.accessKeyId, mOssEntity.accessKeySecret, mOssEntity.securityToken)
|
||||
val oss = OSSClient(HaloApp.getInstance().application, mOssEntity.endPoint, credentialProvider, conf)
|
||||
|
||||
// 构造上传请求
|
||||
val put = PutObjectRequest(mOssEntity.bucket, mOssEntity.key, path)
|
||||
|
||||
val task: OSSAsyncTask<*> = oss.asyncPutObject(put, object : OSSCompletedCallback<PutObjectRequest?, PutObjectResult> {
|
||||
override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult) {
|
||||
it.onSuccess(mOssEntity.domain + mOssEntity.key)
|
||||
}
|
||||
|
||||
override fun onFailure(request: PutObjectRequest?, clientExcepion: ClientException?, serviceException: ServiceException?) {
|
||||
clientExcepion?.printStackTrace()
|
||||
serviceException?.printStackTrace()
|
||||
if (serviceException != null) {
|
||||
it.onError(Throwable(message = clientExcepion?.message + "/" + serviceException.message))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { url, throwable ->
|
||||
if (url.isNotEmpty()) {
|
||||
listener?.onSuccess(url)
|
||||
return@subscribe
|
||||
}
|
||||
if (throwable != null) {
|
||||
listener?.onError(throwable)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface OnUploadFileListener {
|
||||
fun onSuccess(url: String)
|
||||
fun onError(e: Throwable?)
|
||||
}
|
||||
}
|
||||
129
app/src/main/java/com/gh/common/util/PackageInstaller.kt
Normal file
129
app/src/main/java/com/gh/common/util/PackageInstaller.kt
Normal file
@ -0,0 +1,129 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.content.FileProvider
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.FileUtils
|
||||
import com.lightgame.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
object PackageInstaller {
|
||||
|
||||
|
||||
/**
|
||||
* 为了兼容java代码
|
||||
*/
|
||||
@JvmStatic
|
||||
fun install(context: Context, downloadEntity: DownloadEntity) {
|
||||
install(context, downloadEntity, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动安装应用程序并取消通知栏安装消息
|
||||
*
|
||||
* 兼容所有包安装(apk,xapk),后续可加上apks
|
||||
*
|
||||
* 主动点击安装如果是xapk则需要toast提示
|
||||
*/
|
||||
@JvmStatic
|
||||
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
|
||||
// 取消状态栏下载完成的通知,若存在
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
|
||||
val pkgPath = downloadEntity.path
|
||||
if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) {
|
||||
XapkInstaller.install(context, downloadEntity, showUnzipToast)
|
||||
} else {
|
||||
install(context, downloadEntity.path)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动安装应用程序
|
||||
*
|
||||
* 除非特殊情况,请勿使用此方法进行应用安装操作
|
||||
* 除非你已经确定该文件一定是Apk
|
||||
*/
|
||||
@JvmStatic
|
||||
fun install(context: Context, pkgPath: String) {
|
||||
try {
|
||||
if (PackageUtils.isCanLaunchSetup(context, pkgPath)) {
|
||||
val installIntent = getInstallIntent(context, pkgPath)
|
||||
context.startActivity(installIntent)
|
||||
} else {
|
||||
DialogUtils.showPluginDialog(context) {
|
||||
uninstall(context, pkgPath)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Utils.toast(context, e.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启动安装意图
|
||||
*
|
||||
* 除非特殊情况,请勿使用此方法进行应用安装操作
|
||||
* 除非你已经确定该文件一定是Apk且该次安装无需检查签名情况
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getInstallIntent(context: Context, path: String): Intent {
|
||||
var uri = Uri.fromFile(File(path))
|
||||
val installIntent = Intent(Intent.ACTION_VIEW)
|
||||
if ("smartisan" == Build.MANUFACTURER) {
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, File(path))
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
} else {
|
||||
// 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现
|
||||
// Application 上下文就更不用说了
|
||||
val pkgName = PackageUtils.getPackageNameByPath(context, path)
|
||||
if (pkgName == context.packageName || context is Application) {
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
}
|
||||
InstallUtils.getInstance(context).addInstall(PackageUtils.getPackageNameByPath(context, path))
|
||||
return installIntent
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载应用
|
||||
*/
|
||||
@JvmStatic
|
||||
fun uninstall(context: Context, path: String) {
|
||||
val uninstallIntent = Intent()
|
||||
uninstallIntent.action = Intent.ACTION_DELETE
|
||||
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
val packageName = PackageUtils.getPackageNameByPath(context, path)
|
||||
uninstallIntent.data = Uri.parse("package:$packageName")
|
||||
InstallUtils.getInstance(context).addUninstall(packageName)
|
||||
context.startActivity(uninstallIntent)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDownloadPath(gameName: String?, format: String?): String {
|
||||
return FileUtils.getDownloadPath(HaloApp.getInstance().application, getDownloadFileName(gameName, format))
|
||||
}
|
||||
|
||||
private fun getDownloadFileName(gameName: String?, format: String?): String {
|
||||
var fileExtension = "apk"
|
||||
if (format == XapkInstaller.XAPK_EXTENSION_NAME) {
|
||||
fileExtension = XapkInstaller.XAPK_EXTENSION_NAME
|
||||
}
|
||||
return MD5Utils.getContentMD5(gameName + "_" + System.currentTimeMillis()) + "." + fileExtension
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@ -13,17 +12,18 @@ import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.g00fy2.versioncompare.Version;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.GameUpdateEntity;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@ -31,7 +31,6 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
@ -42,9 +41,6 @@ import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
public class PackageUtils {
|
||||
|
||||
public static final String publicKey = "OpenSSLRSAPublicKey{modulus=a8c4bb5748fec8d5c35db1a7a182d41ba4721a91131a417330af79ef4ddb43f9fa0ff4907b0a613bfe152de0ed8fc1b2e6f94a908aa98a5f7adc1ce814ba7ec919d75d9910bdfd8649b4789da6a90ffb61f0d23ac4f828a78fcd0d6f6120c1c43c1f87f7498a89eb40ca8e32dfc2f9d5c10d612b95192870223674e241e53305abf320d7eed76ded398778576e4db7b17b3bc6a792f13de5e43a6a5fae4276c73e6990ce97f68dff0ec16fc9594f175c8d49cd0d7877340d9de60942ca0efc737e50b6c295dfe0713e4532b4e810e1ea11b702b4a27753e41559cbceb247e7f044ec4e3ab2e8bccd8b9fd71286e63307550bcde86deee95adb8133076269135b,publicExponent=10001}";
|
||||
@ -63,6 +59,8 @@ public class PackageUtils {
|
||||
updateEntity.setId(gameEntity.getId());
|
||||
updateEntity.setName(gameEntity.getName());
|
||||
updateEntity.setIcon(gameEntity.getIcon());
|
||||
updateEntity.setRawIcon(gameEntity.getRawIcon());
|
||||
updateEntity.setIconSubscript(gameEntity.getIconSubscript());
|
||||
updateEntity.setPackageName(apkEntity.getPackageName());
|
||||
updateEntity.setSize(apkEntity.getSize());
|
||||
updateEntity.setVersion(apkEntity.getVersion());
|
||||
@ -76,6 +74,7 @@ public class PackageUtils {
|
||||
updateEntity.setDownload(gameEntity.getDownload());
|
||||
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
|
||||
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
|
||||
updateEntity.setFormat(apkEntity.getFormat());
|
||||
updateList.add(updateEntity);
|
||||
}
|
||||
}
|
||||
@ -113,6 +112,7 @@ public class PackageUtils {
|
||||
updateEntity.setTagStyle(gameEntity.getTagStyle());
|
||||
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
|
||||
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
|
||||
updateEntity.setFormat(apkEntity.getFormat());
|
||||
updateList.add(updateEntity);
|
||||
}
|
||||
}
|
||||
@ -232,29 +232,6 @@ public class PackageUtils {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 启动安装应用程序
|
||||
*/
|
||||
public static void launchSetup(final Context context, DownloadEntity downloadEntity) {
|
||||
// 取消状态栏下载完成的通知,若存在
|
||||
downloadEntity.getMeta().put(Constants.MARK_ALREADY_TRIGGERED_INSTALLATION, "YES");
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity);
|
||||
launchSetup(context, downloadEntity.getPath());
|
||||
}
|
||||
|
||||
private static void launchSetup(final Context context, final String path) {
|
||||
try {
|
||||
if (isCanLaunchSetup(context, path)) {
|
||||
context.startActivity(PackageUtils.getInstallIntent(context, path));
|
||||
} else {
|
||||
DialogUtils.showPluginDialog(context,
|
||||
() -> context.startActivity(PackageUtils.getUninstallIntent(context, path)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Utils.toast(context, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 path 获取 apk 信息确定处理方式
|
||||
*
|
||||
@ -291,37 +268,6 @@ public class PackageUtils {
|
||||
return compareSignatureBetweenInstalledAppWithApk(context, packageName, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据路径,获取安装游戏的意图
|
||||
*/
|
||||
public static Intent getInstallIntent(Context context, String path) {
|
||||
return getInstallIntent(context, path, false);
|
||||
}
|
||||
|
||||
public static Intent getInstallIntent(Context context, String path, boolean isInAppUpdate) {
|
||||
Uri uri = Uri.fromFile(new File(path));
|
||||
Intent installIntent = new Intent(Intent.ACTION_VIEW);
|
||||
if ("smartisan".equals(Build.MANUFACTURER)) {
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, new File(path));
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
|
||||
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
} else {
|
||||
// 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现
|
||||
// Application 上下文就更不用说了
|
||||
if (isInAppUpdate || context instanceof Application) {
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
|
||||
}
|
||||
InstallUtils.getInstance(context).addInstall(getPackageNameByPath(context, path));
|
||||
return installIntent;
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据包名,获取卸载游戏的意图
|
||||
*/
|
||||
@ -552,9 +498,10 @@ public class PackageUtils {
|
||||
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
|
||||
&& !PackageUtils.isSignedByGh(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取调用者的进程名
|
||||
*
|
||||
* @param context 调用者的上下文
|
||||
* @return 进程名
|
||||
*/
|
||||
@ -571,5 +518,38 @@ public class PackageUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 应用是否在前台运行
|
||||
*/
|
||||
public static boolean isAppOnForeground(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getApplicationContext()
|
||||
.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (activityManager == null) return false;
|
||||
|
||||
List<ActivityManager.RunningAppProcessInfo> appProcesses =
|
||||
activityManager.getRunningAppProcesses();
|
||||
if (appProcesses == null) return false;
|
||||
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
if (pm == null) return false;
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
|
||||
if (!pm.isInteractive()) return false;
|
||||
} else {
|
||||
if (!pm.isScreenOn()) return false;
|
||||
}
|
||||
|
||||
String packageName = context.getApplicationContext().getPackageName();
|
||||
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
|
||||
// The name of the process that this object is associated with.
|
||||
if (appProcess.processName.equals(packageName) && appProcess.importance
|
||||
== ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
135
app/src/main/java/com/gh/common/util/PicassoImageGetter.java
Normal file
135
app/src/main/java/com/gh/common/util/PicassoImageGetter.java
Normal file
@ -0,0 +1,135 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Html;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
import com.squareup.picasso.Transformation;
|
||||
|
||||
public class PicassoImageGetter implements Html.ImageGetter {
|
||||
private TextView textView = null;
|
||||
|
||||
public PicassoImageGetter() {
|
||||
}
|
||||
|
||||
public PicassoImageGetter(TextView target) {
|
||||
textView = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getDrawable(String source) {
|
||||
BitmapDrawablePlaceHolder drawable = new BitmapDrawablePlaceHolder();
|
||||
|
||||
Context context = HaloApp.getInstance().getApplication();
|
||||
Picasso.with(context)
|
||||
.load(source)
|
||||
.transform(new CircleTransformation())
|
||||
.placeholder(ResourcesCompat.getDrawable(context.getResources(), R.drawable.personal_user_default_icon, context
|
||||
.getTheme()))
|
||||
.into(drawable);
|
||||
|
||||
return drawable;
|
||||
}
|
||||
|
||||
private class BitmapDrawablePlaceHolder extends BitmapDrawable implements Target {
|
||||
protected Drawable drawable;
|
||||
|
||||
@Override
|
||||
public void draw(final Canvas canvas) {
|
||||
if (drawable != null) {
|
||||
Paint.FontMetricsInt fmPaint = textView.getPaint().getFontMetricsInt();
|
||||
float fontHeight = fmPaint.descent - fmPaint.ascent;
|
||||
float textSize = textView.getTextSize();
|
||||
|
||||
if (fontHeight - textSize > 0) {
|
||||
canvas.translate((fontHeight - textSize) / 2, 0);
|
||||
}
|
||||
drawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
public void setDrawable(Drawable drawable) {
|
||||
try {
|
||||
this.drawable = drawable;
|
||||
|
||||
Paint.FontMetricsInt fmPaint = textView.getPaint().getFontMetricsInt();
|
||||
int fontHeight = fmPaint.descent - fmPaint.ascent;
|
||||
int textSize = (int) textView.getTextSize();
|
||||
|
||||
drawable.setBounds(0, 0, textSize, textSize);
|
||||
setBounds(0, 0, fontHeight, fontHeight);
|
||||
if (textView != null) {
|
||||
textView.setText(textView.getText());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||
setDrawable(new BitmapDrawable(HaloApp.getInstance()
|
||||
.getApplication()
|
||||
.getResources(), bitmap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable errorDrawable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable placeHolderDrawable) {
|
||||
setDrawable(placeHolderDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
private class CircleTransformation implements Transformation {
|
||||
@Override
|
||||
public Bitmap transform(Bitmap source) {
|
||||
int size = Math.min(source.getWidth(), source.getHeight());
|
||||
|
||||
int x = (source.getWidth() - size) / 2;
|
||||
int y = (source.getHeight() - size) / 2;
|
||||
|
||||
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
|
||||
if (squaredBitmap != source) {
|
||||
source.recycle();
|
||||
}
|
||||
|
||||
Bitmap.Config config = source.getConfig() != null ? source.getConfig() : Bitmap.Config.ARGB_8888;
|
||||
Bitmap bitmap = Bitmap.createBitmap(size, size, config);
|
||||
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
BitmapShader shader = new BitmapShader(squaredBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
paint.setShader(shader);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
float r = size / 2f;
|
||||
canvas.drawCircle(r, r, r, paint);
|
||||
|
||||
squaredBitmap.recycle();
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return "circle";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -36,43 +36,23 @@ import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
|
||||
public class PlatformUtils {
|
||||
|
||||
|
||||
private static PlatformUtils mInstance;
|
||||
|
||||
|
||||
private Context context;
|
||||
|
||||
|
||||
private ArrayMap<String, String> platformMap;
|
||||
private ArrayMap<String, Integer> platformPicMap;
|
||||
private ArrayMap<String, String> platformPicUrlMap;
|
||||
private ArrayMap<String, String> platformColorMap;
|
||||
private boolean isCheck = false;
|
||||
private boolean isUpdate = false;
|
||||
|
||||
|
||||
private PlatformUtils(Context con) {
|
||||
this.context = con.getApplicationContext();
|
||||
initMap();
|
||||
}
|
||||
|
||||
|
||||
private void initMap() {
|
||||
ArrayMap<String, Integer> platformPicMap = new ArrayMap<>();
|
||||
platformPicMap.put("360", R.drawable.platform_360);
|
||||
platformPicMap.put("37wan", R.drawable.platform_37);
|
||||
platformPicMap.put("91", R.drawable.platform_91);
|
||||
platformPicMap.put("9u", R.drawable.platform_9u);
|
||||
platformPicMap.put("anzhi", R.drawable.platform_anzhi);
|
||||
platformPicMap.put("baidu", R.drawable.platform_baidu);
|
||||
platformPicMap.put("dangle", R.drawable.platform_dl);
|
||||
platformPicMap.put("ewan", R.drawable.platform_ewan);
|
||||
platformPicMap.put("gf", R.drawable.platform_gf);
|
||||
platformPicMap.put("gf-w", R.drawable.platform_gfw);
|
||||
platformPicMap.put("huawei", R.drawable.platform_hw);
|
||||
platformPicMap.put("mi", R.drawable.platform_mi);
|
||||
platformPicMap.put("oppo", R.drawable.platform_oppo);
|
||||
platformPicMap.put("ouwan", R.drawable.platform_ouwan);
|
||||
platformPicMap.put("pps", R.drawable.platform_pps);
|
||||
platformPicMap.put("vivo", R.drawable.platform_vivo);
|
||||
platformPicMap.put("wdj", R.drawable.platform_wdj);
|
||||
|
||||
ArrayMap<String, String> platformColorMap = new ArrayMap<>();
|
||||
platformColorMap.put("360", "#218FA4");
|
||||
platformColorMap.put("37wan", "#F5BD20");
|
||||
@ -91,24 +71,20 @@ public class PlatformUtils {
|
||||
platformColorMap.put("pps", "#FF8C27");
|
||||
platformColorMap.put("vivo", "#3FA5E3");
|
||||
platformColorMap.put("wdj", "#5ABA3F");
|
||||
|
||||
|
||||
ArrayMap<String, String> platformMap = new ArrayMap<>();
|
||||
ArrayMap<String, String> platformPicUrlMap = new ArrayMap<>();
|
||||
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
"gh_platform", Context.MODE_PRIVATE);
|
||||
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
|
||||
Set<String> set = sharedPreferences.getStringSet("platform", null);
|
||||
if (set == null) {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties
|
||||
.load(context.getAssets().open("platform.properties"));
|
||||
properties.load(context.getAssets().open("platform.properties"));
|
||||
Set<String> pset = new HashSet<>();
|
||||
for (Object object : properties.keySet()) {
|
||||
platformMap.put(object.toString(),
|
||||
(String) properties.get(object));
|
||||
pset.add(object.toString() + "="
|
||||
+ (String) properties.get(object) + "=" + "=");
|
||||
platformMap.put(object.toString(), (String) properties.get(object));
|
||||
pset.add(object.toString() + "=" + (String) properties.get(object) + "=" + "=");
|
||||
}
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putStringSet("platform", pset);
|
||||
@ -133,11 +109,10 @@ public class PlatformUtils {
|
||||
// checkPlatformPic(urls);
|
||||
}
|
||||
}
|
||||
|
||||
updatePlatform(platformMap, platformPicMap, platformPicUrlMap,
|
||||
platformColorMap);
|
||||
|
||||
updatePlatform(platformMap, platformPicUrlMap, platformColorMap);
|
||||
}
|
||||
|
||||
|
||||
private void checkPlatformPic(final ArrayList<String> urls) {
|
||||
isCheck = true;
|
||||
File file = new File(FileUtils.getPlatformPicDir(context));
|
||||
@ -154,53 +129,41 @@ public class PlatformUtils {
|
||||
}
|
||||
}
|
||||
if (urls.size() != 0) {
|
||||
AppExecutor.getIoExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int success = 0;
|
||||
for (int i = 0; i < urls.size(); i++) {
|
||||
String url = urls.get(i);
|
||||
String savePath = FileUtils.getPlatformPicDir(context)
|
||||
+ File.separator
|
||||
+ url.substring(url.lastIndexOf("/") + 1);
|
||||
int code = FileUtils.downloadFile(url, savePath);
|
||||
if (code == HttpURLConnection.HTTP_OK) {
|
||||
success++;
|
||||
}
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
int success = 0;
|
||||
for (int i = 0; i < urls.size(); i++) {
|
||||
String url = urls.get(i);
|
||||
String savePath = FileUtils.getPlatformPicDir(context) + File.separator + url
|
||||
.substring(url.lastIndexOf("/") + 1);
|
||||
int code = FileUtils.downloadFile(url, savePath);
|
||||
if (code == HttpURLConnection.HTTP_OK) {
|
||||
success++;
|
||||
}
|
||||
if (success == urls.size()) {
|
||||
Handler handler = new Handler(context.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
|
||||
}
|
||||
});
|
||||
}
|
||||
isCheck = false;
|
||||
}
|
||||
if (success == urls.size()) {
|
||||
Handler handler = new Handler(context.getMainLooper());
|
||||
handler.post(() -> EventBus.getDefault().post(new EBReuse("PlatformChanged")));
|
||||
}
|
||||
isCheck = false;
|
||||
});
|
||||
} else {
|
||||
isCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePlatform(ArrayMap<String, String> pMap,
|
||||
ArrayMap<String, Integer> pPMap, ArrayMap<String, String> pUMap,
|
||||
ArrayMap<String, String> pCMap) {
|
||||
|
||||
private void updatePlatform(ArrayMap<String, String> pMap, ArrayMap<String, String> pUMap, ArrayMap<String, String> pCMap) {
|
||||
platformMap = pMap;
|
||||
platformPicMap = pPMap;
|
||||
platformPicUrlMap = pUMap;
|
||||
platformColorMap = pCMap;
|
||||
}
|
||||
|
||||
|
||||
public static PlatformUtils getInstance(Context context) {
|
||||
if (mInstance == null) {
|
||||
mInstance = new PlatformUtils(context);
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
|
||||
public String getPlatformColor(String platform) {
|
||||
if ("".equals(platform) || "官方版".equals(platform)) {
|
||||
return "#BB3D42";
|
||||
@ -209,26 +172,16 @@ public class PlatformUtils {
|
||||
if (color != null) {
|
||||
return color;
|
||||
}
|
||||
|
||||
int themeColor = ContextCompat.getColor(HaloApp.getInstance().getApplication(), R.color.theme);
|
||||
|
||||
int themeColor = ContextCompat.getColor(HaloApp.getInstance()
|
||||
.getApplication(), R.color.theme);
|
||||
return String.format("#%06X", 0xFFFFFF & themeColor);
|
||||
}
|
||||
|
||||
public int getPlatformPic(String platform) {
|
||||
if ("".equals(platform) || "官方版".equals(platform)) {
|
||||
return R.drawable.platform_gf;
|
||||
}
|
||||
Integer id = platformPicMap.get(platform);
|
||||
if (id != null) {
|
||||
return id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public String getPlatformPicUrl(String platform) {
|
||||
return platformPicUrlMap.get(platform);
|
||||
}
|
||||
|
||||
|
||||
public String getPlatformName(String platform) {
|
||||
if ("".equals(platform) || "官方版".equals(platform)) {
|
||||
return "官方版";
|
||||
@ -242,38 +195,40 @@ public class PlatformUtils {
|
||||
}
|
||||
return platform;
|
||||
}
|
||||
|
||||
|
||||
public void getPlatform() {
|
||||
if (isUpdate) {
|
||||
return;
|
||||
}
|
||||
isUpdate = true;
|
||||
RetrofitManager.getInstance(context).getApi().getGamePlatform()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<List<PlatformEntity>>() {
|
||||
@Override
|
||||
public void onResponse(List<PlatformEntity> response) {
|
||||
Set<String> platformSet = new HashSet<>();
|
||||
for (PlatformEntity platformEntity : response) {
|
||||
platformSet.add(platformEntity.toString());
|
||||
}
|
||||
SharedPreferences sp = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
|
||||
sp.edit().putStringSet("platform", platformSet).apply();
|
||||
initMap();
|
||||
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
|
||||
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
String today = format.format(new Date());
|
||||
sp.edit().putString("refresh_time", today).apply();
|
||||
isUpdate = false;
|
||||
RetrofitManager.getInstance(context)
|
||||
.getApi()
|
||||
.getGamePlatform()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<List<PlatformEntity>>() {
|
||||
@Override
|
||||
public void onResponse(List<PlatformEntity> response) {
|
||||
Set<String> platformSet = new HashSet<>();
|
||||
for (PlatformEntity platformEntity : response) {
|
||||
platformSet.add(platformEntity.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(HttpException e) {
|
||||
isUpdate = false;
|
||||
}
|
||||
});
|
||||
SharedPreferences sp = context.getSharedPreferences("gh_platform", Context.MODE_PRIVATE);
|
||||
sp.edit().putStringSet("platform", platformSet).apply();
|
||||
initMap();
|
||||
EventBus.getDefault().post(new EBReuse("PlatformChanged"));
|
||||
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
String today = format.format(new Date());
|
||||
sp.edit().putString("refresh_time", today).apply();
|
||||
isUpdate = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(HttpException e) {
|
||||
isUpdate = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -48,9 +48,9 @@ object ReservationHelper {
|
||||
ReservationRepository.removeReservationFromMemoryAndRefresh(game.id)
|
||||
|
||||
if (deleteReservation) {
|
||||
MtaHelper.onEvent("预约游戏", "取消预约", game.name)
|
||||
// MtaHelper.onEvent("预约游戏", "取消预约", game.name)
|
||||
} else {
|
||||
MtaHelper.onEvent("预约游戏", "删除预约", game.name)
|
||||
// MtaHelper.onEvent("预约游戏", "删除预约", game.name)
|
||||
}
|
||||
|
||||
refreshCallback.onCallback()
|
||||
@ -73,9 +73,10 @@ object ReservationHelper {
|
||||
"暂不删除",
|
||||
{ emptyCallback.onCallback() },
|
||||
null,
|
||||
trackMtaEvent = true,
|
||||
mtaEvent = "预约游戏",
|
||||
mtaKey = "删除预约弹窗")
|
||||
trackMtaEvent = true
|
||||
// , mtaEvent = "预约游戏",
|
||||
// mtaKey = "删除预约弹窗"
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -88,9 +89,10 @@ object ReservationHelper {
|
||||
"暂不取消",
|
||||
{ emptyCallback.onCallback() },
|
||||
null,
|
||||
trackMtaEvent = true,
|
||||
mtaEvent = "预约游戏",
|
||||
mtaKey = "取消预约弹窗")
|
||||
trackMtaEvent = true
|
||||
// , mtaEvent = "预约游戏",
|
||||
// mtaKey = "取消预约弹窗"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -24,6 +24,9 @@ import android.widget.PopupWindow;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
import com.facebook.datasource.DataSource;
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||
@ -31,6 +34,7 @@ import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WeiBoShareActivity;
|
||||
import com.gh.gamecenter.entity.ShareEntity;
|
||||
import com.gh.gamecenter.eventbus.EBShare;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.sina.weibo.sdk.WbSdk;
|
||||
@ -53,9 +57,6 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import static com.gh.common.util.LoginHelper.WEIBO_SCOPE;
|
||||
|
||||
/**
|
||||
@ -83,24 +84,39 @@ public class ShareUtils {
|
||||
R.drawable.share_cancel_logo
|
||||
};
|
||||
|
||||
public enum ShareType {
|
||||
news,
|
||||
game, // 普通游戏
|
||||
plugin, // 插件游戏
|
||||
tools,
|
||||
askInvite,
|
||||
askNormal, // 问答问题/答案
|
||||
shareGh,
|
||||
communityArticle,
|
||||
video
|
||||
public enum ShareEntrance {
|
||||
news("资讯文章"),
|
||||
game("游戏详情"), // 普通游戏
|
||||
plugin("游戏详情"), // 插件游戏
|
||||
tools("工具箱"),
|
||||
askInvite("邀请回答"),
|
||||
askNormal("问题详情"), //问答问题
|
||||
answerNormal("回答详情"), //问答答案
|
||||
shareGh("APP分享"),
|
||||
communityArticle("文章详情"),
|
||||
video("视频"),
|
||||
web("web链接");
|
||||
|
||||
private String name;
|
||||
|
||||
ShareEntrance(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private String[] arrLabel = {"微信好友", "朋友圈", "QQ好友", "QQ空间", "新浪微博", "短信", "复制链接", "取消"};
|
||||
|
||||
private PopupWindow popupWindow;
|
||||
private WeakReference<PopupWindow> popupWindow;
|
||||
|
||||
private ShareType mShareType;
|
||||
public static ShareType shareType;//全局保存shareType,分享成功后判断分享的类型
|
||||
private ShareEntrance mShareEntrance;
|
||||
public static String shareType = "";//分享类型(事件上报用)
|
||||
public static ShareEntrance shareEntrance;//分享入口(事件上报和视频分享统计用)
|
||||
public static String resourceId = "";//分享内容的id(事件上报用)
|
||||
public static ShareEntity shareEntity;//分享信息(事件上报用)
|
||||
|
||||
private WeakReference<Activity> mActivity;
|
||||
|
||||
@ -110,25 +126,31 @@ public class ShareUtils {
|
||||
@Override
|
||||
public void onComplete(Object o) {
|
||||
Utils.toast(mContext, R.string.share_success_hint);
|
||||
EventBus.getDefault().post(new EBShare(ShareUtils.shareType));
|
||||
EventBus.getDefault().post(new EBShare(ShareUtils.shareEntrance));
|
||||
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "success",
|
||||
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(UiError uiError) {
|
||||
Utils.toast(mContext, R.string.share_fail_hint);
|
||||
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "fail",
|
||||
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Utils.toast(mContext, R.string.share_cancel_hint);
|
||||
LogUtils.uploadShareResult(shareType, ShareUtils.shareEntrance.getName(), "cancel",
|
||||
ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId);
|
||||
}
|
||||
};
|
||||
|
||||
private ShareUtils(Context context) {
|
||||
mTencent = Tencent.createInstance(Config.TENCENT_APPID, context); //初始化QQ分享
|
||||
mIWXAPI = WXAPIFactory.createWXAPI(context, Config.WECHAT_APPID); //初始化微信分享
|
||||
WbSdk.install(context, new AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
|
||||
mContext = context.getApplicationContext();
|
||||
mTencent = Tencent.createInstance(Config.TENCENT_APPID, mContext); //初始化QQ分享
|
||||
mIWXAPI = WXAPIFactory.createWXAPI(mContext, Config.WECHAT_APPID); //初始化微信分享
|
||||
WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE));
|
||||
}
|
||||
|
||||
public static ShareUtils getInstance(Context context) {
|
||||
@ -153,17 +175,20 @@ public class ShareUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void showShareWindowsCallback(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareType shareType, ShareCallBack callBack) {
|
||||
public void showShareWindowsCallback(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id, ShareCallBack callBack) {
|
||||
if (activity.isFinishing()) return;
|
||||
this.mActivity = new WeakReference<>(activity);
|
||||
this.shareIcon = icon;
|
||||
this.shareUrl = url;
|
||||
this.mSummary = shareSummary;
|
||||
this.mTitle = shareTitle;
|
||||
this.mShareType = shareType;
|
||||
ShareUtils.shareType = mShareType;
|
||||
this.mShareEntrance = shareEntrance;
|
||||
ShareUtils.shareEntrance = mShareEntrance;
|
||||
ShareUtils.resourceId = id;
|
||||
ShareUtils.shareEntity = new ShareEntity(shareUrl, mTitle, mSummary);
|
||||
LogUtils.uploadShareEnter(mShareEntrance.getName(), shareUrl, mTitle, mSummary, id);
|
||||
|
||||
View contentView = View.inflate(activity, R.layout.share_popup_layout, null);
|
||||
View contentView = View.inflate(mActivity.get(), R.layout.share_popup_layout, null);
|
||||
contentView.setFocusable(true);
|
||||
contentView.setFocusableInTouchMode(true);
|
||||
RecyclerView shareRecyclerView = contentView.findViewById(R.id.share_rv);
|
||||
@ -191,7 +216,7 @@ public class ShareUtils {
|
||||
}
|
||||
});
|
||||
|
||||
if (mShareType == ShareType.shareGh) {
|
||||
if (mShareEntrance == ShareEntrance.shareGh) {
|
||||
RelativeLayout layout = (RelativeLayout) view;
|
||||
layout.addView(contentView);
|
||||
arrLabel[6] = "邮件";
|
||||
@ -206,41 +231,41 @@ public class ShareUtils {
|
||||
arrLogo[7] = R.drawable.share_cancel_logo;
|
||||
}
|
||||
|
||||
popupWindow = new SharePopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
|
||||
, LinearLayout.LayoutParams.MATCH_PARENT, true);
|
||||
popupWindow.setAnimationStyle(R.style.popwindow_exit_only_anim_style);
|
||||
popupWindow = new WeakReference<>(new SharePopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
|
||||
, LinearLayout.LayoutParams.MATCH_PARENT, true));
|
||||
popupWindow.get().setAnimationStyle(R.style.popwindow_exit_only_anim_style);
|
||||
//解决PopupWindow无法覆盖状态栏
|
||||
popupWindow.setClippingEnabled(false);
|
||||
popupWindow.get().setClippingEnabled(false);
|
||||
|
||||
int bottomLocation = -DisplayUtils.retrieveNavigationHeight(activity);
|
||||
if (!DisplayUtils.isNavigationBarShow(activity)) {
|
||||
bottomLocation = 0;
|
||||
}
|
||||
try {
|
||||
popupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
|
||||
popupWindow.get().showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
contentView.setOnClickListener(v -> popupWindow.dismiss());
|
||||
contentView.setOnClickListener(v -> safelyDismiss());
|
||||
|
||||
contentView.setOnKeyListener((v, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK
|
||||
&& event.getRepeatCount() == 0
|
||||
&& popupWindow != null
|
||||
&& popupWindow.isShowing()) {
|
||||
&& popupWindow.get() != null
|
||||
&& popupWindow.get().isShowing()) {
|
||||
if (callBack != null) {
|
||||
callBack.onCancel();
|
||||
}
|
||||
popupWindow.dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void showShareWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareType shareType) {
|
||||
showShareWindowsCallback(activity, view, url, icon, shareTitle, shareSummary, shareType, null);
|
||||
public void showShareWindows(Activity activity, View view, String url, String icon, String shareTitle, String shareSummary, ShareEntrance shareEntrance, String id) {
|
||||
showShareWindowsCallback(activity, view, url, icon, shareTitle, shareSummary, shareEntrance, id, null);
|
||||
}
|
||||
|
||||
//QQ分享
|
||||
@ -248,11 +273,12 @@ public class ShareUtils {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
Bundle params = new Bundle();
|
||||
|
||||
switch (mShareType) {
|
||||
switch (mShareEntrance) {
|
||||
case plugin:
|
||||
mSummary += "(光环加速版)";
|
||||
break;
|
||||
case askNormal:
|
||||
case answerNormal:
|
||||
case video:
|
||||
case communityArticle:
|
||||
mTitle += " - 光环助手";
|
||||
@ -271,8 +297,8 @@ public class ShareUtils {
|
||||
mTencent.shareToQQ(activity, params, QqShareListener);
|
||||
}
|
||||
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,11 +315,12 @@ public class ShareUtils {
|
||||
WXMediaMessage msg = new WXMediaMessage(webpage);
|
||||
webpage.webpageUrl = shareUrl;
|
||||
|
||||
switch (mShareType) {
|
||||
switch (mShareEntrance) {
|
||||
case plugin:
|
||||
mSummary += "(光环加速版)";
|
||||
break;
|
||||
case askNormal:
|
||||
case answerNormal:
|
||||
case video:
|
||||
case communityArticle:
|
||||
mTitle += " - 光环助手";
|
||||
@ -309,9 +336,9 @@ public class ShareUtils {
|
||||
req.message = msg;
|
||||
req.scene = SendMessageToWX.Req.WXSceneSession;
|
||||
|
||||
loadBitMap(shareIcon, msg, req);
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
loadBitmapAndShare(shareIcon, msg, req);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,18 +346,18 @@ public class ShareUtils {
|
||||
return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private void loadBitMap(final String iconUrl, final WXMediaMessage msg, final SendMessageToWX.Req req) {
|
||||
ImageUtils.display(mContext, iconUrl, new BaseBitmapDataSubscriber() {
|
||||
private void loadBitmapAndShare(final String iconUrl, final WXMediaMessage msg, final SendMessageToWX.Req req) {
|
||||
ImageUtils.getBitmap(iconUrl, new BiCallback<Bitmap, Boolean>() {
|
||||
@Override
|
||||
protected void onNewResultImpl(Bitmap bitmap) {
|
||||
if (mShareType == ShareType.video) {
|
||||
public void onFirst(Bitmap bitmap) {
|
||||
if (mShareEntrance == ShareEntrance.video) {
|
||||
// 分享类型为视频时裁为正方形
|
||||
int dimension = Math.min(bitmap.getWidth(), bitmap.getHeight());
|
||||
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
|
||||
}
|
||||
|
||||
Bitmap compressBp = compressBitmap(bitmap);
|
||||
if (mShareType == ShareType.askNormal || mShareType == ShareType.askInvite) {
|
||||
if (mShareEntrance == ShareEntrance.askNormal || mShareEntrance == ShareEntrance.askInvite) {
|
||||
msg.thumbData = ImageUtils.bmpToByteArray(compressBp, true);
|
||||
} else {
|
||||
Bitmap resultBp = addBackGround(compressBp);
|
||||
@ -340,8 +367,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
|
||||
Utils.log("分享获取bitmap失败");
|
||||
public void onSecond(Boolean aBoolean) {
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -397,11 +423,12 @@ public class ShareUtils {
|
||||
Utils.toast(mContext, R.string.share_skip);
|
||||
Bundle params = new Bundle();
|
||||
|
||||
switch (mShareType) {
|
||||
switch (mShareEntrance) {
|
||||
case plugin:
|
||||
mSummary += "(光环加速版)";
|
||||
break;
|
||||
case askNormal:
|
||||
case answerNormal:
|
||||
case video:
|
||||
case communityArticle:
|
||||
mTitle += " - 光环助手";
|
||||
@ -425,8 +452,8 @@ public class ShareUtils {
|
||||
mTencent.shareToQzone(activity, params, QqShareListener);
|
||||
}
|
||||
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,7 +471,7 @@ public class ShareUtils {
|
||||
|
||||
webpage.webpageUrl = shareUrl;
|
||||
|
||||
switch (mShareType) {
|
||||
switch (mShareEntrance) {
|
||||
case plugin:
|
||||
msg.title = mSummary + "(光环加速版)";
|
||||
break;
|
||||
@ -452,6 +479,7 @@ public class ShareUtils {
|
||||
msg.title = mSummary;
|
||||
break;
|
||||
case askNormal:
|
||||
case answerNormal:
|
||||
case video:
|
||||
case communityArticle:
|
||||
msg.title = mTitle + " - 光环助手";
|
||||
@ -468,9 +496,9 @@ public class ShareUtils {
|
||||
req.message = msg;
|
||||
req.scene = SendMessageToWX.Req.WXSceneTimeline;
|
||||
|
||||
loadBitMap(shareIcon, msg, req);
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
loadBitmapAndShare(shareIcon, msg, req);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,22 +513,23 @@ public class ShareUtils {
|
||||
shareIcon,
|
||||
mTitle,
|
||||
mSummary,
|
||||
mShareType.toString());
|
||||
mShareEntrance.toString());
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
//短信分享
|
||||
private void shortMessageShare() {
|
||||
String smsBody;
|
||||
switch (mShareType) {
|
||||
switch (mShareEntrance) {
|
||||
case news:
|
||||
case tools:
|
||||
case web:
|
||||
smsBody = mTitle + shareUrl;
|
||||
break;
|
||||
case plugin:
|
||||
@ -514,6 +543,7 @@ public class ShareUtils {
|
||||
break;
|
||||
case askInvite:
|
||||
case askNormal:
|
||||
case answerNormal:
|
||||
case video:
|
||||
case communityArticle:
|
||||
smsBody = mTitle + " - 光环助手" + shareUrl;
|
||||
@ -531,18 +561,20 @@ public class ShareUtils {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
if (mShareEntrance != ShareEntrance.shareGh ) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
//复制文字链接
|
||||
private void copyLink(String copyContent) {
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
ClipboardManager cmb = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cmb.setText(copyContent);
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
Utils.toast(mContext, "复制成功");
|
||||
popupWindow.dismiss();
|
||||
safelyDismiss();
|
||||
} else {
|
||||
Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享");
|
||||
}
|
||||
@ -567,7 +599,7 @@ public class ShareUtils {
|
||||
holder.shareLogo.setImageResource(arrLogo[position]);
|
||||
holder.shareLabel.setText(arrLabel[position]);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mShareType == ShareUtils.ShareType.shareGh) {
|
||||
if (mShareEntrance == ShareEntrance.shareGh) {
|
||||
MtaHelper.onEvent("我的光环_新", "分享光环", arrLabel[position]);
|
||||
}
|
||||
if (listener != null) {
|
||||
@ -575,23 +607,33 @@ public class ShareUtils {
|
||||
}
|
||||
switch (holder.getPosition()) {
|
||||
case 0:
|
||||
shareType = "wechat_friend";
|
||||
MtaHelper.onEvent("内容分享", "微信好友", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
wechatShare();
|
||||
break;
|
||||
case 1:
|
||||
shareType = "wechat_moment";
|
||||
MtaHelper.onEvent("内容分享", "微信朋友圈", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
wechatMomentsShare();
|
||||
break;
|
||||
case 2:
|
||||
shareType = "qq_friend";
|
||||
MtaHelper.onEvent("内容分享", "QQ好友", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
qqShare();
|
||||
break;
|
||||
case 3:
|
||||
shareType = "qq_zone";
|
||||
MtaHelper.onEvent("内容分享", "QQ空间", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
qZoneShare();
|
||||
break;
|
||||
case 4:
|
||||
shareType = "sina_weibo";
|
||||
MtaHelper.onEvent("内容分享", "新浪微博", mTitle);
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
sinaWeiboShare();
|
||||
break;
|
||||
case 5:
|
||||
@ -600,11 +642,11 @@ public class ShareUtils {
|
||||
break;
|
||||
case 6:
|
||||
MtaHelper.onEvent("内容分享", "复制链接", mTitle);
|
||||
if (mShareType == ShareType.askInvite) {
|
||||
if (mShareEntrance == ShareEntrance.askInvite) {
|
||||
copyLink(mTitle + " - 光环助手" + shareUrl);
|
||||
} else if (mShareType == ShareType.askNormal) {
|
||||
} else if (mShareEntrance == ShareEntrance.askNormal || mShareEntrance == ShareEntrance.answerNormal) {
|
||||
copyLink(shareUrl);
|
||||
} else if (mShareType != ShareType.shareGh) {
|
||||
} else if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
copyLink(shareUrl);
|
||||
} else {
|
||||
try {
|
||||
@ -617,10 +659,11 @@ public class ShareUtils {
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (mShareType != ShareType.shareGh) {
|
||||
popupWindow.dismiss();
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
safelyDismiss();
|
||||
} else {
|
||||
copyLink("推荐光环助手,绿色安全的手游加速助手:" + shareUrl);
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -645,6 +688,12 @@ public class ShareUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void safelyDismiss() {
|
||||
if (popupWindow.get() != null) {
|
||||
popupWindow.get().dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
void onItemClick(int position);
|
||||
@ -655,12 +704,12 @@ public class ShareUtils {
|
||||
|
||||
void onCancel();
|
||||
}
|
||||
|
||||
|
||||
private static class SharePopupWindow extends PopupWindow {
|
||||
SharePopupWindow(View contentView, int width, int height, boolean focusable) {
|
||||
super(contentView, width, height, focusable);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
View backgroundView = getContentView().findViewById(R.id.share_container);
|
||||
@ -670,5 +719,5 @@ public class ShareUtils {
|
||||
getContentView().postDelayed(super::dismiss, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.gh.common.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object SPUtils {
|
||||
@ -90,7 +91,20 @@ object SPUtils {
|
||||
|
||||
@JvmStatic
|
||||
fun getStringSet(key: String): Set<String> {
|
||||
return sp.getStringSet(key, HashSet())?: HashSet()
|
||||
return sp.getStringSet(key, HashSet()) ?: HashSet()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setMap(key: String, map: Map<String, String>) {
|
||||
val mapJson = GsonUtils.toJson(map)
|
||||
setString(key, mapJson)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getMap(key: String): MutableMap<String, String> {
|
||||
val mapJson = getString(key)
|
||||
val type = object : TypeToken<MutableMap<String, String>>() {}.type
|
||||
return GsonUtils.gson.fromJson(mapJson, type) ?: mutableMapOf()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@ -5,13 +5,13 @@ import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.AbsoluteSizeSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StrikethroughSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.text.TextPaint
|
||||
import android.text.style.*
|
||||
import android.view.View
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.view.CenterImageSpan
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class SpanBuilder(content: String) {
|
||||
private var spannableString: SpannableStringBuilder = SpannableStringBuilder(content)
|
||||
@ -58,12 +58,29 @@ class SpanBuilder(content: String) {
|
||||
}
|
||||
|
||||
//添加图标
|
||||
fun image(context: Context, start: Int, end: Int, @DrawableRes res: Int): SpanBuilder {
|
||||
val imageSpan = CenterImageSpan(context, res)
|
||||
fun image(start: Int, end: Int, @DrawableRes res: Int): SpanBuilder {
|
||||
val imageSpan = CenterImageSpan(HaloApp.getInstance().application, res)
|
||||
spannableString.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return this
|
||||
}
|
||||
|
||||
fun click(start: Int, end: Int, colorRes: Int, onClick: () -> Unit): SpanBuilder {
|
||||
val clickSpan = object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(HaloApp.getInstance().application, colorRes)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
override fun onClick(widget: View) {
|
||||
onClick.invoke()
|
||||
}
|
||||
|
||||
}
|
||||
spannableString.setSpan(clickSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): SpannableStringBuilder {
|
||||
return spannableString
|
||||
}
|
||||
|
||||
@ -35,4 +35,19 @@ public class SpeedUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRemainSecondTime(long totalSize, long currentSize, long speed) {
|
||||
long remainSize = totalSize - currentSize;
|
||||
long remainTime;
|
||||
if (speed != 0) {
|
||||
remainTime = remainSize / speed;
|
||||
} else {
|
||||
return "-s";
|
||||
}
|
||||
int hour = (int) (remainTime / 3600);
|
||||
remainTime = (remainTime - hour * 3660);
|
||||
int minute = (int) (remainTime / 60);
|
||||
int second = (int) (remainTime - minute * 60);
|
||||
return second + "s";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public class TagUtils {
|
||||
return;
|
||||
}
|
||||
isUpdate = true;
|
||||
RetrofitManager.getInstance(context).getApi().getTags()
|
||||
RetrofitManager.getInstance(context).getSensitiveApi().getTags()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<List<TagEntity>>() {
|
||||
|
||||
@ -133,23 +133,38 @@ object TextHelper {
|
||||
Utils.toast(application, "已复制:$arg")
|
||||
}
|
||||
}): SpannableStringBuilder {
|
||||
val builder = SpannableStringBuilder(text)
|
||||
return updateSpannableStringWithHighlightedSpan(context, builder, wrapper, highlightColorId, highlightedTextClickListener)
|
||||
}
|
||||
|
||||
var modifiedText = text
|
||||
if (modifiedText.endsWith(wrapper)) {
|
||||
fun updateSpannableStringWithHighlightedSpan(
|
||||
context: Context,
|
||||
ssb: SpannableStringBuilder,
|
||||
wrapper: String = "###",
|
||||
@ColorRes
|
||||
highlightColorId: Int = R.color.theme_font,
|
||||
highlightedTextClickListener: SimpleCallback<String>? = object : SimpleCallback<String> {
|
||||
override fun onCallback(arg: String) {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
cmb.text = arg
|
||||
Utils.toast(application, "已复制:$arg")
|
||||
}
|
||||
}): SpannableStringBuilder {
|
||||
|
||||
if (ssb.endsWith(wrapper)) {
|
||||
// 若高亮符在最后一位就在后面加一个空格,避免整行都能点击
|
||||
modifiedText = "$modifiedText "
|
||||
ssb.append(" ")
|
||||
}
|
||||
|
||||
val sBuilder = SpannableStringBuilder(modifiedText)
|
||||
val wrapperTextLength = wrapper.length
|
||||
|
||||
val matcher = Pattern.compile("$wrapper(.+?)$wrapper", Pattern.DOTALL).matcher(modifiedText)
|
||||
val matcher = Pattern.compile("$wrapper(.+?)$wrapper", Pattern.DOTALL).matcher(ssb)
|
||||
|
||||
val pair = TreeMap<Int, Int>()
|
||||
while (matcher.find()) {
|
||||
// 保存起始位置和结束位置
|
||||
pair[matcher.start(1)] = matcher.end(1)
|
||||
sBuilder.setSpan(object : ClickableSpan() {
|
||||
ssb.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = ContextCompat.getColor(context, highlightColorId)
|
||||
@ -174,12 +189,12 @@ object TextHelper {
|
||||
val end = reversePair[key]
|
||||
|
||||
end?.let {
|
||||
sBuilder.replace(end, end + wrapperTextLength, "")
|
||||
sBuilder.replace(key - wrapperTextLength, key, "")
|
||||
ssb.replace(end, end + wrapperTextLength, "")
|
||||
ssb.replace(key - wrapperTextLength, key, "")
|
||||
}
|
||||
}
|
||||
|
||||
return sBuilder
|
||||
return ssb
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -23,6 +23,7 @@ object TimeUtils {
|
||||
|
||||
fun getFormatTime(time: Long, pattern: String = "yyyy-MM-dd"): String {
|
||||
val f = SimpleDateFormat(pattern, Locale.CHINA)
|
||||
f.timeZone = TimeZone.getTimeZone("Asia/Shanghai")
|
||||
return f.format(Date(time * 1000))
|
||||
}
|
||||
|
||||
@ -60,7 +61,7 @@ object TimeUtils {
|
||||
/**
|
||||
* 判断时间戳是多少天前
|
||||
*/
|
||||
fun getBeforeDays(timestamp: Long):Int{
|
||||
fun getBeforeDays(timestamp: Long): Int {
|
||||
var days: Long = 0
|
||||
val format = SimpleDateFormat("yyyyMMdd HH:mm", Locale.getDefault())
|
||||
try {
|
||||
@ -73,4 +74,30 @@ object TimeUtils {
|
||||
|
||||
return days.toInt()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 格式化视频时长
|
||||
*/
|
||||
@JvmStatic
|
||||
fun formatVideoDuration(length: Long): String {
|
||||
val minute = length / 60
|
||||
val second = length % 60
|
||||
return String.format(Locale.CHINA, "%02d:%02d", minute, second)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDayString(date: Long): String {
|
||||
val offSet = Calendar.getInstance().timeZone.rawOffset
|
||||
val today = (System.currentTimeMillis() + offSet) / 86400000
|
||||
val start = (date * 1000 + offSet) / 86400000
|
||||
return when ((start - today).toInt()) {
|
||||
-2 -> "(前天)"
|
||||
-1 -> "(昨天)"
|
||||
0 -> "(今天)"
|
||||
1 -> "(明天)"
|
||||
2 -> "(后天)"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,14 +3,18 @@ package com.gh.common.util
|
||||
import android.widget.Toast
|
||||
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.toast.ToastHandler
|
||||
|
||||
object ToastUtils {
|
||||
/** 之前显示的内容 */
|
||||
private var mOldMsg: String? = null
|
||||
|
||||
/** Toast对象 */
|
||||
private var mToast: Toast? = null
|
||||
|
||||
/** 第一次时间 */
|
||||
private var mOneTime: Long = 0
|
||||
|
||||
/** 第二次时间 */
|
||||
private var mTwoTime: Long = 0
|
||||
|
||||
@ -19,19 +23,34 @@ object ToastUtils {
|
||||
* @param message
|
||||
*/
|
||||
fun showToast(message: String) {
|
||||
showToast(message, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示Toast
|
||||
* @param message
|
||||
* @param gravity
|
||||
*/
|
||||
fun showToast(message: String, gravity: Int = -1, yOffset: Int = 0) {
|
||||
if (mToast == null) {
|
||||
mToast = Toast.makeText(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
|
||||
mToast = ToastHandler.INSTANCE.getToastInstance(HaloApp.getInstance().application, message, Toast.LENGTH_SHORT)
|
||||
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
|
||||
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
|
||||
mToast!!.show()
|
||||
mOneTime = System.currentTimeMillis()
|
||||
} else {
|
||||
mTwoTime = System.currentTimeMillis()
|
||||
if (message == mOldMsg) {
|
||||
if (mTwoTime - mOneTime > Toast.LENGTH_SHORT) {
|
||||
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
|
||||
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
|
||||
mToast!!.show()
|
||||
}
|
||||
} else {
|
||||
mOldMsg = message
|
||||
mToast!!.setText(message)
|
||||
if (gravity != -1) mToast!!.setGravity(gravity, 0, yOffset) else
|
||||
mToast!!.setGravity(DisplayUtils.getToastDefaultGravity(), 0, DisplayUtils.getToastOffset())
|
||||
mToast!!.show()
|
||||
}
|
||||
}
|
||||
|
||||
127
app/src/main/java/com/gh/common/util/UriUtils.java
Normal file
127
app/src/main/java/com/gh/common/util/UriUtils.java
Normal file
@ -0,0 +1,127 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
public class UriUtils {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static String getPath(final Context context, final Uri uri) {
|
||||
|
||||
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
|
||||
// DocumentProvider
|
||||
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
|
||||
// ExternalStorageProvider
|
||||
if (isExternalStorageDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
if ("primary".equalsIgnoreCase(type)) {
|
||||
return Environment.getExternalStorageDirectory() + "/" + split[1];
|
||||
}
|
||||
}
|
||||
// DownloadsProvider
|
||||
else if (isDownloadsDocument(uri)) {
|
||||
|
||||
final String id = DocumentsContract.getDocumentId(uri);
|
||||
final Uri contentUri = ContentUris.withAppendedId(
|
||||
Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
|
||||
|
||||
return getDataColumn(context, contentUri, null, null);
|
||||
}
|
||||
// MediaProvider
|
||||
else if (isMediaDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
Uri contentUri = null;
|
||||
if ("image".equals(type)) {
|
||||
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("video".equals(type)) {
|
||||
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("audio".equals(type)) {
|
||||
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
|
||||
final String selection = "_id=?";
|
||||
final String[] selectionArgs = new String[]{split[1]};
|
||||
|
||||
return getDataColumn(context, contentUri, selection, selectionArgs);
|
||||
}
|
||||
}
|
||||
// MediaStore (and general)
|
||||
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
return getDataColumn(context, uri, null, null);
|
||||
}
|
||||
// File
|
||||
else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return uri.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the data column for this Uri. This is useful for
|
||||
* MediaStore Uris, and other file-based ContentProviders.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param uri The Uri to query.
|
||||
* @param selection (Optional) Filter used in the query.
|
||||
* @param selectionArgs (Optional) Selection arguments used in the query.
|
||||
* @return The value of the _data column, which is typically a file path.
|
||||
*/
|
||||
private static String getDataColumn(Context context, Uri uri, String selection,
|
||||
String[] selectionArgs) {
|
||||
|
||||
Cursor cursor = null;
|
||||
final String column = "_data";
|
||||
final String[] projection = {column};
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
|
||||
null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int column_index = cursor.getColumnIndexOrThrow(column);
|
||||
return cursor.getString(column_index);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is ExternalStorageProvider.
|
||||
*/
|
||||
private static boolean isExternalStorageDocument(Uri uri) {
|
||||
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is DownloadsProvider.
|
||||
*/
|
||||
private static boolean isDownloadsDocument(Uri uri) {
|
||||
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is MediaProvider.
|
||||
*/
|
||||
private static boolean isMediaDocument(Uri uri) {
|
||||
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||
}
|
||||
}
|
||||
18
app/src/main/java/com/gh/common/videolog/VideoRecordDao.kt
Normal file
18
app/src/main/java/com/gh/common/videolog/VideoRecordDao.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package com.gh.common.videolog
|
||||
|
||||
import androidx.room.*
|
||||
|
||||
@Dao
|
||||
interface VideoRecordDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertMany(eventList: List<VideoRecordEntity>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(event: VideoRecordEntity)
|
||||
|
||||
@Query("SELECT * FROM VideoRecord")
|
||||
fun getAll(): List<VideoRecordEntity>
|
||||
|
||||
@Delete
|
||||
fun deleteMany(eventList: List<VideoRecordEntity>)
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.videolog
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
@Entity(tableName = "VideoRecord")
|
||||
data class VideoRecordEntity(
|
||||
@PrimaryKey
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
var videoId: String = "",
|
||||
var time: Long = 0
|
||||
) : Parcelable
|
||||
76
app/src/main/java/com/gh/common/videolog/VideoRecordUtils.kt
Normal file
76
app/src/main/java/com/gh/common/videolog/VideoRecordUtils.kt
Normal file
@ -0,0 +1,76 @@
|
||||
package com.gh.common.videolog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import com.gh.common.util.toRequestBody
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object VideoRecordUtils {
|
||||
private const val STORE_SIZE = 20
|
||||
private lateinit var mApplication: Application
|
||||
|
||||
private val videoRecordSet by lazy { hashSetOf<VideoRecordEntity>() }
|
||||
private val videoRecordExecutor by lazy { Executors.newSingleThreadExecutor() }
|
||||
private val videoRecordDao by lazy { AppDatabase.getInstance(mApplication).videoRecordDao() }
|
||||
|
||||
@JvmStatic
|
||||
fun init(application: Application) {
|
||||
mApplication = application
|
||||
|
||||
videoRecordExecutor.execute {
|
||||
val recordList = videoRecordDao.getAll()
|
||||
videoRecordSet.addAll(recordList)
|
||||
}
|
||||
}
|
||||
|
||||
fun log(videoId: String) {
|
||||
videoRecordExecutor.execute {
|
||||
try {
|
||||
val entity = VideoRecordEntity(videoId = videoId, time = System.currentTimeMillis() / 1000L)
|
||||
videoRecordSet.add(entity)
|
||||
videoRecordDao.insert(entity)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (videoRecordSet.size >= STORE_SIZE) {
|
||||
commitVideoRecord()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun commitVideoRecord() {
|
||||
if (videoRecordSet.isEmpty()) return
|
||||
videoRecordExecutor.execute {
|
||||
uploadVideoRecord()
|
||||
val exposureList = videoRecordSet.toList()
|
||||
videoRecordSet.removeAll(exposureList)
|
||||
videoRecordDao.deleteMany(exposureList)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun uploadVideoRecord(time: Long = 0) {
|
||||
if (!UserManager.getInstance().isLoggedIn) return
|
||||
val requestMap = HashMap<String, Any>()
|
||||
val videoIds = videoRecordSet.toList().map { it.videoId }
|
||||
requestMap["g_id"] = HaloApp.getInstance().gid ?: ""
|
||||
requestMap["time"] = time
|
||||
requestMap["video_id"] = videoIds
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
.uploadVideoLog(requestMap.toRequestBody())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -5,10 +5,12 @@ import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
@ -19,6 +21,7 @@ import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
import com.scwang.smartrefresh.layout.api.RefreshInternal;
|
||||
import com.scwang.smartrefresh.layout.api.RefreshKernel;
|
||||
import com.scwang.smartrefresh.layout.api.RefreshLayout;
|
||||
@ -74,21 +77,21 @@ public abstract class AbstractSwipeRefreshHeader<T extends AbstractSwipeRefreshH
|
||||
progressView.setId(ID_IMAGE_PROGRESS);
|
||||
centerLayout.setId(android.R.id.widget_frame);
|
||||
|
||||
LinearLayout.LayoutParams lpHeaderText = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
|
||||
centerLayout.addView(titleView, lpHeaderText);
|
||||
// LinearLayout.LayoutParams lpHeaderText = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
|
||||
// centerLayout.addView(titleView, lpHeaderText);
|
||||
|
||||
RelativeLayout.LayoutParams lpHeaderLayout = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
|
||||
lpHeaderLayout.addRule(CENTER_IN_PARENT);
|
||||
thisGroup.addView(centerLayout, lpHeaderLayout);
|
||||
|
||||
RelativeLayout.LayoutParams lpArrow = new RelativeLayout.LayoutParams(mDensityUtil.dip2px(15), mDensityUtil.dip2px(15));
|
||||
RelativeLayout.LayoutParams lpArrow = new RelativeLayout.LayoutParams(mDensityUtil.dip2px(35), mDensityUtil.dip2px(35));
|
||||
lpArrow.addRule(CENTER_VERTICAL);
|
||||
lpArrow.addRule(LEFT_OF, android.R.id.widget_frame);
|
||||
lpArrow.addRule(CENTER_IN_PARENT, android.R.id.widget_frame);
|
||||
thisGroup.addView(arrowView, lpArrow);
|
||||
|
||||
RelativeLayout.LayoutParams lpProgress = new RelativeLayout.LayoutParams((ViewGroup.LayoutParams) lpArrow);
|
||||
lpProgress.addRule(CENTER_VERTICAL);
|
||||
lpProgress.addRule(LEFT_OF, android.R.id.widget_frame);
|
||||
lpProgress.addRule(CENTER_IN_PARENT, android.R.id.widget_frame);
|
||||
progressView.animate().setInterpolator(new LinearInterpolator());
|
||||
thisGroup.addView(progressView, lpProgress);
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@ import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.rxTimer
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.SettingsEntity
|
||||
@ -188,8 +190,8 @@ class AdBannerView : LinearLayout {
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val ad = mDatas[position % mDatas.size]
|
||||
val view = holder.itemView as ImageView
|
||||
Picasso.with(context).load(ad.image).into(view)
|
||||
val view = holder.itemView as SimpleDraweeView
|
||||
ImageUtils.display(view,ad.image)
|
||||
holder.itemView.setOnClickListener {
|
||||
onItemClick?.invoke(position % mDatas.size)
|
||||
}
|
||||
|
||||
@ -21,8 +21,10 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
: ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var mSizeTv: TextView
|
||||
private var mNewestTv: TextView
|
||||
private var mRecommendedTv: TextView
|
||||
|
||||
var newestTv: TextView
|
||||
var ratingTv: TextView //目前只在专题页面显示
|
||||
var recommendedTv: TextView
|
||||
|
||||
private var mOnConfigFilterSetupListener: OnConfigFilterSetupListener? = null
|
||||
|
||||
@ -30,23 +32,33 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
View.inflate(context, R.layout.layout_config_filter, this)
|
||||
|
||||
mSizeTv = findViewById(R.id.size_tv)
|
||||
mNewestTv = findViewById(R.id.newest_tv)
|
||||
mRecommendedTv = findViewById(R.id.recommended_tv)
|
||||
newestTv = findViewById(R.id.newest_tv)
|
||||
ratingTv = findViewById(R.id.rating_tv)
|
||||
recommendedTv = findViewById(R.id.recommended_tv)
|
||||
|
||||
mSizeTv.setOnClickListener {
|
||||
showSelectionPopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
}
|
||||
|
||||
mNewestTv.setOnClickListener {
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.NEWEST)
|
||||
toggleHighlightedTextView(mNewestTv, true)
|
||||
toggleHighlightedTextView(mRecommendedTv, false)
|
||||
ratingTv.setOnClickListener {
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.RATING)
|
||||
toggleHighlightedTextView(ratingTv, true)
|
||||
toggleHighlightedTextView(newestTv, false)
|
||||
toggleHighlightedTextView(recommendedTv, false)
|
||||
}
|
||||
|
||||
mRecommendedTv.setOnClickListener {
|
||||
newestTv.setOnClickListener {
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.NEWEST)
|
||||
toggleHighlightedTextView(ratingTv, false)
|
||||
toggleHighlightedTextView(newestTv, true)
|
||||
toggleHighlightedTextView(recommendedTv, false)
|
||||
}
|
||||
|
||||
recommendedTv.setOnClickListener {
|
||||
mOnConfigFilterSetupListener?.onSetupSortType(SortType.RECOMMENDED)
|
||||
toggleHighlightedTextView(mNewestTv, false)
|
||||
toggleHighlightedTextView(mRecommendedTv, true)
|
||||
toggleHighlightedTextView(ratingTv, false)
|
||||
toggleHighlightedTextView(newestTv, false)
|
||||
toggleHighlightedTextView(recommendedTv, true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +66,7 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
mOnConfigFilterSetupListener = onConfigFilterSetupListener
|
||||
}
|
||||
|
||||
private fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
fun toggleHighlightedTextView(targetTextView: TextView, highlightIt: Boolean) {
|
||||
if (highlightIt) {
|
||||
targetTextView.background = ContextCompat.getDrawable(targetTextView.context, R.drawable.text_blue_background)
|
||||
targetTextView.setTextColor(Color.WHITE)
|
||||
@ -140,7 +152,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
|
||||
enum class SortType {
|
||||
RECOMMENDED,
|
||||
NEWEST
|
||||
NEWEST,
|
||||
RATING
|
||||
}
|
||||
|
||||
enum class SortSize(val value: String) {
|
||||
|
||||
@ -9,6 +9,8 @@ import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
|
||||
public class CropImageBorderView extends View {
|
||||
|
||||
/**
|
||||
@ -28,7 +30,7 @@ public class CropImageBorderView extends View {
|
||||
*/
|
||||
private int mBorderWidth = 1;
|
||||
|
||||
private Paint mPaint, mPaintRect;
|
||||
private Paint mPaint, mPaintRect, mAnglePaint;
|
||||
|
||||
private float mRatio = 1; // 宽高比
|
||||
|
||||
@ -48,7 +50,7 @@ public class CropImageBorderView extends View {
|
||||
|
||||
// 绘制阴影
|
||||
mPaintRect = new Paint();
|
||||
mPaintRect.setARGB(136, 0, 0, 0);
|
||||
mPaintRect.setARGB(80, 0, 0, 0);
|
||||
mPaintRect.setStyle(Style.FILL);
|
||||
|
||||
// 绘制边框
|
||||
@ -56,7 +58,12 @@ public class CropImageBorderView extends View {
|
||||
mPaint.setStyle(Style.STROKE);
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setColor(Color.WHITE);
|
||||
mPaint.setStrokeWidth(mBorderWidth);
|
||||
mPaint.setStrokeWidth(0.5F);
|
||||
|
||||
// 绘制边框
|
||||
mAnglePaint = new Paint();
|
||||
mAnglePaint.setStyle(Style.FILL);
|
||||
mAnglePaint.setColor(Color.WHITE);
|
||||
|
||||
}
|
||||
|
||||
@ -86,6 +93,45 @@ public class CropImageBorderView extends View {
|
||||
canvas.drawRect(mHorizontalPadding, mVerticalPadding,
|
||||
mHorizontalPadding + mWidth, getHeight() - mVerticalPadding, mPaint);
|
||||
|
||||
// 左上
|
||||
canvas.drawRect(mHorizontalPadding - DisplayUtils.dip2px(1F)
|
||||
, mVerticalPadding - DisplayUtils.dip2px(1F)
|
||||
, mHorizontalPadding + DisplayUtils.dip2px(16F)
|
||||
, mVerticalPadding + DisplayUtils.dip2px(1F), mAnglePaint);
|
||||
canvas.drawRect(mHorizontalPadding - DisplayUtils.dip2px(1F)
|
||||
, mVerticalPadding - DisplayUtils.dip2px(1F)
|
||||
, mHorizontalPadding + DisplayUtils.dip2px(1F)
|
||||
, mVerticalPadding + DisplayUtils.dip2px(16F), mAnglePaint);
|
||||
|
||||
// 右上
|
||||
canvas.drawRect(mHorizontalPadding + mWidth - DisplayUtils.dip2px(16F)
|
||||
, mVerticalPadding - DisplayUtils.dip2px(1F)
|
||||
, mHorizontalPadding + mWidth
|
||||
, mVerticalPadding + DisplayUtils.dip2px(1F), mAnglePaint);
|
||||
canvas.drawRect(mHorizontalPadding + mWidth - DisplayUtils.dip2px(1F)
|
||||
, mVerticalPadding - DisplayUtils.dip2px(1F)
|
||||
, mHorizontalPadding + mWidth + DisplayUtils.dip2px(1F)
|
||||
, mVerticalPadding + DisplayUtils.dip2px(16F), mAnglePaint);
|
||||
|
||||
// 左下
|
||||
canvas.drawRect(mHorizontalPadding - DisplayUtils.dip2px(1F)
|
||||
, getHeight() - mVerticalPadding - DisplayUtils.dip2px(16F)
|
||||
, mHorizontalPadding + DisplayUtils.dip2px(1F)
|
||||
, getHeight() - mVerticalPadding - DisplayUtils.dip2px(1F), mAnglePaint);
|
||||
canvas.drawRect(mHorizontalPadding - DisplayUtils.dip2px(1F)
|
||||
, getHeight() - mVerticalPadding - DisplayUtils.dip2px(1F)
|
||||
, mHorizontalPadding + DisplayUtils.dip2px(16F)
|
||||
, getHeight() - mVerticalPadding + DisplayUtils.dip2px(1F), mAnglePaint);
|
||||
|
||||
// 右下
|
||||
canvas.drawRect(mHorizontalPadding + mWidth - DisplayUtils.dip2px(16F)
|
||||
, getHeight() - mVerticalPadding - DisplayUtils.dip2px(1F)
|
||||
, mHorizontalPadding + mWidth
|
||||
, getHeight() - mVerticalPadding + DisplayUtils.dip2px(1F), mAnglePaint);
|
||||
canvas.drawRect(mHorizontalPadding + mWidth - DisplayUtils.dip2px(1F)
|
||||
, getHeight() - mVerticalPadding - DisplayUtils.dip2px(16F)
|
||||
, mHorizontalPadding + mWidth + DisplayUtils.dip2px(1F)
|
||||
, getHeight() - mVerticalPadding + DisplayUtils.dip2px(1F), mAnglePaint);
|
||||
}
|
||||
|
||||
public void setHorizontalPadding(int mHorizontalPadding, float ratio) {
|
||||
|
||||
@ -2,7 +2,6 @@ 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;
|
||||
@ -58,24 +57,17 @@ public class CropImageCustom extends RelativeLayout {
|
||||
return mZoomImageView.clip();
|
||||
}
|
||||
|
||||
// 用户头像压缩规则
|
||||
public boolean savePicture(String path) {
|
||||
float limitSize = 900;
|
||||
int quality = 90;
|
||||
Bitmap bitmap = mZoomImageView.clip();
|
||||
File file = new File(path);
|
||||
|
||||
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();
|
||||
Bitmap clip = mZoomImageView.clip();
|
||||
try {
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(path)));
|
||||
clip.compress(Bitmap.CompressFormat.WEBP, 100, bos);
|
||||
bos.flush();
|
||||
bos.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
|
||||
@ -318,11 +318,18 @@ public class CropImageZoomView extends AppCompatImageView implements
|
||||
|
||||
if (dw <= getWidth() - mHorizontalPadding * 2
|
||||
&& dh <= getHeight() - mVerticalPadding * 2) {// 如果图片的高度<截图区高度,并且图片宽度<截图区宽度时
|
||||
float scaleW = (getWidth() * 1.0f - mHorizontalPadding * 2)
|
||||
/ dw;
|
||||
float scaleW = (getWidth() * 1.0f - mHorizontalPadding * 2) / dw;
|
||||
float scaleH = (getHeight() * 1.0f - mVerticalPadding * 2) / dh;
|
||||
scale = Math.max(scaleW, scaleH);
|
||||
}
|
||||
|
||||
// 宽、高均超出截图区域
|
||||
if (dw > getWidth() - mHorizontalPadding * 2 && dh > getHeight() - mVerticalPadding * 2) {
|
||||
float scaleW = (getWidth() * 1.0f - mHorizontalPadding * 2) / dw;
|
||||
float scaleH = (getHeight() * 1.0f - mVerticalPadding * 2) / dh;
|
||||
scale = Math.max(scaleW, scaleH);
|
||||
}
|
||||
|
||||
initScale = scale;
|
||||
SCALE_MID = initScale * 2;
|
||||
SCALE_MAX = initScale * 4;
|
||||
|
||||
25
app/src/main/java/com/gh/common/view/CustomMarkerView.kt
Normal file
25
app/src/main/java/com/gh/common/view/CustomMarkerView.kt
Normal file
@ -0,0 +1,25 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.gamecenter.R
|
||||
import com.github.mikephil.charting.components.MarkerView
|
||||
import com.github.mikephil.charting.data.Entry
|
||||
import com.github.mikephil.charting.highlight.Highlight
|
||||
import com.github.mikephil.charting.utils.MPPointF
|
||||
|
||||
class CustomMarkerView(context: Context) : MarkerView(context, R.layout.layout_chart_markerview) {
|
||||
var markerView: TextView = findViewById(R.id.markerView)
|
||||
override fun refreshContent(e: Entry, highlight: Highlight?) {
|
||||
markerView.text = e.y.toInt().toString()
|
||||
super.refreshContent(e, highlight)
|
||||
}
|
||||
|
||||
|
||||
override fun getOffset(): MPPointF {
|
||||
return MPPointF((-(width / 2)).toFloat(), (-height).toFloat() - 3f.dip2px())
|
||||
}
|
||||
}
|
||||
@ -15,12 +15,12 @@ import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
public class DownloadProgressBar extends ProgressBar {
|
||||
public static final int MAX_LENGTH = 1000;
|
||||
public static final int DOWNLOAD_NORMAL_STYLE = 0;
|
||||
@ -38,7 +38,11 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
DOWNLOADING_PLUGIN,
|
||||
RESERVABLE,
|
||||
RESERVED,
|
||||
H5_GAME
|
||||
H5_GAME,
|
||||
|
||||
XAPK_UNZIPPING,
|
||||
XAPK_SUCCESS,
|
||||
XAPK_FAILURE,
|
||||
}
|
||||
|
||||
private PorterDuffXfermode mDuffXFerMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
|
||||
@ -214,6 +218,12 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.game_item_btn_pause_dn));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.all_white);
|
||||
break;
|
||||
case XAPK_FAILURE:
|
||||
case XAPK_SUCCESS:
|
||||
case XAPK_UNZIPPING:
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.progressbar_xapk_detail_style));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.all_white);
|
||||
break;
|
||||
}
|
||||
|
||||
mDownloadType = downloadType;
|
||||
|
||||
117
app/src/main/java/com/gh/common/view/DraggableBigImageView.kt
Normal file
117
app/src/main/java/com/gh/common/view/DraggableBigImageView.kt
Normal file
@ -0,0 +1,117 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewConfiguration
|
||||
import com.github.piasy.biv.view.BigImageView
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class DraggableBigImageView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: BigImageView(context, attrs, defStyle) {
|
||||
|
||||
private var mInitScale: Float? = null
|
||||
private val mScaledTouchSlop by lazy { ViewConfiguration.get(context).scaledTouchSlop }
|
||||
private val mDismissEdge by lazy { height * 0.12 }
|
||||
private var mSingleTouch = true
|
||||
private var mFakeDragOffset = 0F
|
||||
private var mLastX = 0F
|
||||
private var mLastY = 0F
|
||||
private var mListener: DragListener? = null
|
||||
|
||||
fun setDragListener(listener: DragListener) {
|
||||
mListener = listener
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
setSingleTouch(false)
|
||||
animate()
|
||||
.translationX(0F).translationY(0F).scaleX(1F).scaleY(1F)
|
||||
.setDuration(200).start()
|
||||
}
|
||||
MotionEvent.ACTION_DOWN -> if (mInitScale == null || mInitScale == 0F) mInitScale = ssiv?.scale
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> up()
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (mSingleTouch && mInitScale != 0F && ssiv?.scale == mInitScale) {
|
||||
if (mLastX == 0F) mLastX = event.rawX
|
||||
if (mLastY == 0F) mLastY = event.rawY
|
||||
val offsetX = event.rawX - mLastX
|
||||
val offsetY = event.rawY - mLastY
|
||||
fakeDrag(offsetX, offsetY)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.dispatchTouchEvent(event)
|
||||
}
|
||||
|
||||
private fun fakeDrag(offsetX: Float, offsetY: Float) {
|
||||
if (mFakeDragOffset == 0F) {
|
||||
// 大于60度才响应下拉消失
|
||||
if (abs(offsetY) / sqrt(3F) > abs(offsetX)) {
|
||||
if (offsetY > mScaledTouchSlop) {
|
||||
mFakeDragOffset = mScaledTouchSlop.toFloat()
|
||||
} else if (offsetY < -mScaledTouchSlop) {
|
||||
mFakeDragOffset = (-mScaledTouchSlop).toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mFakeDragOffset != 0F) {
|
||||
val fixedOffsetY = offsetY - mFakeDragOffset
|
||||
parent?.requestDisallowInterceptTouchEvent(true)
|
||||
val fraction = abs(max(-1F, min(1F, fixedOffsetY / height)))
|
||||
val fakeScale = 1 - min(0.4F, fraction)
|
||||
scaleX = fakeScale
|
||||
scaleY = fakeScale
|
||||
translationY = fixedOffsetY
|
||||
translationX = offsetX / 2
|
||||
mListener?.onDrag(this, fraction)
|
||||
}
|
||||
}
|
||||
|
||||
private fun up() {
|
||||
parent?.requestDisallowInterceptTouchEvent(false)
|
||||
setSingleTouch(true)
|
||||
mFakeDragOffset = 0F
|
||||
mLastX = 0F
|
||||
mLastY = 0F
|
||||
|
||||
if (abs(translationY) > mDismissEdge) {
|
||||
mListener?.onRelease(this, scaleX)
|
||||
} else {
|
||||
val offsetY = translationY
|
||||
val fraction = min(1F, offsetY / height)
|
||||
mListener?.onRestore(this, fraction)
|
||||
|
||||
animate().translationX(0F)
|
||||
.translationY(0F)
|
||||
.scaleX(1F)
|
||||
.scaleY(1F)
|
||||
.setDuration(200).start()
|
||||
}
|
||||
}
|
||||
|
||||
fun isDragging(): Boolean {
|
||||
return mFakeDragOffset != 0F
|
||||
}
|
||||
|
||||
private fun setSingleTouch(value: Boolean) {
|
||||
mSingleTouch = value
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
animate().cancel()
|
||||
}
|
||||
|
||||
interface DragListener {
|
||||
fun onDrag(draggableBigImageView: DraggableBigImageView, fraction: Float)
|
||||
fun onRelease(draggableBigImageView: DraggableBigImageView, scale: Float)
|
||||
fun onRestore(draggableBigImageView: DraggableBigImageView, fraction: Float)
|
||||
}
|
||||
|
||||
}
|
||||
@ -31,7 +31,7 @@ class EllipsizeTextView : AppCompatTextView {
|
||||
val width = paint.measureText(text.subSequence(secondLastLineEnd, lastLineEnd).toString() + "...")
|
||||
if (width > layout.width) {
|
||||
val lastLineText = text.subSequence(secondLastLineEnd, lastLineEnd)
|
||||
for (i in 0 until lastLineText.length) {
|
||||
for (i in lastLineText.indices) {
|
||||
val cutWidth = paint.measureText(text.subSequence(secondLastLineEnd, lastLineEnd - i).toString() + "...")
|
||||
if (cutWidth <= layout.width) {
|
||||
charSequence = text.subSequence(0, lastLineEnd - i)
|
||||
@ -41,7 +41,7 @@ class EllipsizeTextView : AppCompatTextView {
|
||||
}
|
||||
} else {
|
||||
charSequence = text.subSequence(0, lastLineEnd)
|
||||
text = charSequence
|
||||
text = SpannableStringBuilder().append(charSequence).append("...")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,100 +8,132 @@ import android.text.Layout;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
public class ExpandTextView extends AppCompatTextView {
|
||||
|
||||
|
||||
private CharSequence mSnapshotText;
|
||||
|
||||
|
||||
private String mEndText = "...";
|
||||
private CharSequence mShrankText = "";
|
||||
private String mExpandText = mEndText + "全文";
|
||||
private CharSequence mExpandedText = "";
|
||||
private boolean mUseGradientAlphaEndText = false;
|
||||
|
||||
private boolean mShowExpandTextRegardlessOfMaxLines = false; // 不论文字超过 maxLines 都显示"...展开"文字
|
||||
|
||||
private int mMaxLines = 3; // 由于sdk版本限制(getMaxLines) 这里设置默认值
|
||||
|
||||
private static int DEFAULT_ADDITIONAL_END_TEXT_COUNT = 2;
|
||||
|
||||
|
||||
private boolean mInitLayout = false;
|
||||
private boolean mIsExpanded = false; // 位于 recyclerView 时需要自行在外层管理是否已展开
|
||||
|
||||
|
||||
private ExpandCallback mExpandCallback;
|
||||
|
||||
private SelfCalculateMaxLinesCallback mMaxLinesCalculatedCallback;
|
||||
|
||||
private Rect mLastVisibleLineRect;
|
||||
private Rect mLastActualLineRect;
|
||||
|
||||
|
||||
private static int DEFAULT_ADDITIONAL_END_TEXT_COUNT = 2;
|
||||
|
||||
public ExpandTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
public ExpandTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
mMaxLines = getMaxLines();
|
||||
}
|
||||
|
||||
|
||||
mLastVisibleLineRect = new Rect();
|
||||
mLastActualLineRect = new Rect();
|
||||
|
||||
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandTextView);
|
||||
mUseGradientAlphaEndText = ta.getBoolean(R.styleable.ExpandTextView_useGradientAlphaEndText, false);
|
||||
mEndText = ta.getString(R.styleable.ExpandTextView_endText) == null ? mEndText : ta.getString(R.styleable.ExpandTextView_endText);
|
||||
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta
|
||||
.getString(R.styleable.ExpandTextView_expandText);
|
||||
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta.getString(R.styleable.ExpandTextView_expandText);
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (mShowExpandTextRegardlessOfMaxLines && !mIsExpanded) {
|
||||
updateMaxLines();
|
||||
}
|
||||
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() - getExtraBottomPadding());
|
||||
}
|
||||
|
||||
|
||||
private void updateMaxLines() {
|
||||
mMaxLines = getLineCount() - 1;
|
||||
setMaxLines(mMaxLines);
|
||||
mMaxLinesCalculatedCallback.onMaxLinesCalculated(mMaxLines);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (mInitLayout && !mIsExpanded && getLineCount() > mMaxLines) {
|
||||
if (mMaxLines > 0
|
||||
&& ((mShowExpandTextRegardlessOfMaxLines && !mIsExpanded) || (mInitLayout && !mIsExpanded && getLineCount() > mMaxLines))) {
|
||||
mSnapshotText = getText();
|
||||
mInitLayout = false;
|
||||
showExpandButton();
|
||||
}
|
||||
}
|
||||
|
||||
public void setExpendText(String text) {
|
||||
|
||||
public void setExpandText(String text) {
|
||||
this.mExpandText = text;
|
||||
}
|
||||
|
||||
|
||||
public void setExpandCallback(ExpandCallback callback) {
|
||||
this.mExpandCallback = callback;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 适用于不使用 maxLines 而是整段收起时的文字来确定“...更多”的位置的样式
|
||||
* @param shrankText 收起时的文字 (“...更多”跟在 shrankText 后)
|
||||
* @param expandedText 展开时的文字
|
||||
*/
|
||||
public void setShrankTextAndExpandedText(CharSequence shrankText, CharSequence expandedText) {
|
||||
mShrankText = shrankText;
|
||||
mExpandedText = expandedText;
|
||||
mShowExpandTextRegardlessOfMaxLines = !TextUtils.isEmpty(shrankText);
|
||||
|
||||
if (!mIsExpanded && mShowExpandTextRegardlessOfMaxLines) {
|
||||
setText(mShrankText);
|
||||
} else {
|
||||
setText(mExpandedText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(CharSequence text, BufferType type) {
|
||||
mInitLayout = true;
|
||||
super.setText(text, type);
|
||||
}
|
||||
|
||||
|
||||
private void showExpandButton() {
|
||||
String finalEndText = "";
|
||||
TextPaint paint = getPaint();
|
||||
|
||||
|
||||
Layout layout = getLayout();
|
||||
int start = layout.getLineStart(0);
|
||||
int lastLineEnd = layout.getLineEnd(mMaxLines - 1);
|
||||
int lastLineStart = layout.getLineStart(mMaxLines - 1);
|
||||
float lastLineRight = layout.getLineRight(mMaxLines - 1);
|
||||
|
||||
|
||||
int viewWidth = getWidth() - getPaddingRight() - getPaddingLeft();
|
||||
int additionalEndTextCount = 0;
|
||||
|
||||
|
||||
float expandTextWidth;
|
||||
if (mUseGradientAlphaEndText) {
|
||||
additionalEndTextCount = DEFAULT_ADDITIONAL_END_TEXT_COUNT;
|
||||
@ -109,15 +141,15 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
} else {
|
||||
expandTextWidth = paint.measureText(mExpandText);
|
||||
}
|
||||
|
||||
|
||||
CharSequence content = mSnapshotText.subSequence(start, lastLineEnd);
|
||||
|
||||
|
||||
if (viewWidth - lastLineRight > expandTextWidth) {
|
||||
if (mUseGradientAlphaEndText) {
|
||||
finalEndText = content.toString()
|
||||
.substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
|
||||
.substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
|
||||
finalEndText = finalEndText.replace("\n", "");
|
||||
|
||||
|
||||
content = content.subSequence(0, content.length() - additionalEndTextCount) + finalEndText + mExpandText;
|
||||
} else {
|
||||
content = content.toString().trim() + mExpandText;
|
||||
@ -130,10 +162,10 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
if (mUseGradientAlphaEndText) {
|
||||
subSequence = lastLineText.subSequence(0, i - additionalEndTextCount);
|
||||
subSequenceWidth = paint.measureText(subSequence.toString());
|
||||
|
||||
|
||||
finalEndText = lastLineText.subSequence(i - additionalEndTextCount, i) + mEndText;
|
||||
expandTextWidth = paint.measureText(finalEndText + mExpandText);
|
||||
|
||||
|
||||
if (viewWidth - subSequenceWidth > expandTextWidth) {
|
||||
finalEndText = finalEndText.replace("\n", "");
|
||||
content = mSnapshotText.subSequence(start, lastLineStart + i - additionalEndTextCount) + finalEndText + mExpandText;
|
||||
@ -142,7 +174,7 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
} else {
|
||||
subSequence = lastLineText.subSequence(0, i);
|
||||
subSequenceWidth = paint.measureText(subSequence.toString());
|
||||
|
||||
|
||||
if (viewWidth - subSequenceWidth > expandTextWidth) {
|
||||
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
|
||||
break;
|
||||
@ -150,18 +182,20 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SpannableStringBuilder msp = new SpannableStringBuilder(mSnapshotText);
|
||||
int length = msp.length();
|
||||
int startPosition;
|
||||
startPosition = content.length() - finalEndText.length() - mExpandText.length();
|
||||
startPosition = Math.max(startPosition, 0);
|
||||
|
||||
int expandTextStartPosition;
|
||||
expandTextStartPosition = content.length() - finalEndText.length() - mExpandText.length();
|
||||
expandTextStartPosition = Math.max(expandTextStartPosition, 0);
|
||||
|
||||
// 避免越界
|
||||
if (startPosition >= length) return;
|
||||
|
||||
msp.replace(startPosition, length, finalEndText + mExpandText);
|
||||
|
||||
if (expandTextStartPosition >= length) return;
|
||||
|
||||
msp.replace(expandTextStartPosition, length, finalEndText + mExpandText);
|
||||
|
||||
if (expandTextStartPosition + mEndText.length() >= msp.length()) return;
|
||||
|
||||
msp.setSpan(new ClickableSpan() {
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
@ -169,24 +203,49 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
ds.setColor(ContextCompat.getColor(getContext(), R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
mIsExpanded = true;
|
||||
setMaxLines(Integer.MAX_VALUE);
|
||||
setText(mSnapshotText);
|
||||
|
||||
if (mShowExpandTextRegardlessOfMaxLines) {
|
||||
setText(mExpandedText);
|
||||
} else {
|
||||
setText(mSnapshotText);
|
||||
}
|
||||
|
||||
if (mExpandCallback != null) {
|
||||
mExpandCallback.onExpand();
|
||||
}
|
||||
}
|
||||
}, startPosition + mEndText.length(), msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
msp.setSpan(new GradientAlphaTextSpan(), startPosition, startPosition + finalEndText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
}, expandTextStartPosition + mEndText.length(), msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
int paintColor = 0;
|
||||
|
||||
// 找到第一个位置与 endTextStartPosition 贴合的 ForegroundSpan / ClickableSpan ,
|
||||
// 获取颜色赋值给 GradientAlphaTextSpan
|
||||
Object[] objects = msp.getSpans(0, expandTextStartPosition, Object.class);
|
||||
if (objects.length != 0) {
|
||||
for (Object span : objects) {
|
||||
int startPosition = msp.getSpanStart(span);
|
||||
int endPosition = msp.getSpanEnd(span);
|
||||
if (expandTextStartPosition >= startPosition && expandTextStartPosition <= endPosition) {
|
||||
if (span instanceof ForegroundColorSpan) {
|
||||
paintColor = ((ForegroundColorSpan) span).getForegroundColor();
|
||||
break;
|
||||
} else if (span instanceof ClickableSpan) {
|
||||
paintColor = getResources().getColor(R.color.theme_font);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
msp.setSpan(new GradientAlphaTextSpan(paintColor), expandTextStartPosition, expandTextStartPosition + finalEndText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
setText(msp);
|
||||
setMovementMethod(CustomLinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取 maxLines + lineSpacingExtra + movementMethod 一起使用时产生的大小与 lineSpacingExtra 一样的底部空间
|
||||
*/
|
||||
@ -196,16 +255,16 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
int lastVisibleLineIndex = Math.min(getMaxLines(), getLineCount()) - 1;
|
||||
// 获取实际文字的最后一行的 index
|
||||
int lastActualLineIndex = getLineCount() - 1;
|
||||
|
||||
|
||||
if (lastVisibleLineIndex >= 0) {
|
||||
Layout layout = getLayout();
|
||||
int lastVisibleLineBaseline = getLineBounds(lastVisibleLineIndex, mLastVisibleLineRect);
|
||||
getLineBounds(lastActualLineIndex, mLastActualLineRect);
|
||||
int heightBetweenLastVisibleLineRectAndLastActualLineRect = (mLastActualLineRect.bottom - mLastVisibleLineRect.bottom);
|
||||
|
||||
|
||||
if (getMeasuredHeight() == getLayout().getHeight() - heightBetweenLastVisibleLineRectAndLastActualLineRect) {
|
||||
result = mLastVisibleLineRect.bottom - (lastVisibleLineBaseline + layout.getPaint()
|
||||
.getFontMetricsInt().descent + getPaddingBottom());
|
||||
.getFontMetricsInt().descent + getPaddingBottom());
|
||||
if (getLineSpacingExtra() > result) {
|
||||
result = 0;
|
||||
} else {
|
||||
@ -215,21 +274,29 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 此方法仅更改标记,不做实际展开的操作
|
||||
*/
|
||||
public void setIsExpanded(boolean isExpanded) {
|
||||
mIsExpanded = isExpanded;
|
||||
}
|
||||
|
||||
|
||||
public void setExpandMaxLines(int maxLines) {
|
||||
mMaxLines = maxLines;
|
||||
setMaxLines(maxLines);
|
||||
}
|
||||
|
||||
|
||||
public void setSelfCalculateMaxLinesCallback(SelfCalculateMaxLinesCallback callback) {
|
||||
mMaxLinesCalculatedCallback = callback;
|
||||
}
|
||||
|
||||
public interface ExpandCallback {
|
||||
void onExpand();
|
||||
}
|
||||
|
||||
|
||||
public interface SelfCalculateMaxLinesCallback {
|
||||
void onMaxLinesCalculated(int maxLines);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
53
app/src/main/java/com/gh/common/view/GameIconView.kt
Normal file
53
app/src/main/java/com/gh/common/view/GameIconView.kt
Normal file
@ -0,0 +1,53 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.facebook.drawee.generic.RoundingParams
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import kotlinx.android.synthetic.main.layout_game_icon.view.*
|
||||
|
||||
class GameIconView : ConstraintLayout {
|
||||
|
||||
private var mCornerRadius = 10
|
||||
|
||||
constructor(context: Context) : super(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs, 0) {
|
||||
initView(attrs)
|
||||
}
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||
initView(attrs)
|
||||
}
|
||||
|
||||
fun initView(attrs: AttributeSet) {
|
||||
View.inflate(context, R.layout.layout_game_icon, this)
|
||||
|
||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView)
|
||||
mCornerRadius = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconCornerRadius, DisplayUtils.dip2px(10F))
|
||||
ta.recycle()
|
||||
|
||||
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
|
||||
gameIconIv.hierarchy.roundingParams = roundingParams
|
||||
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
|
||||
}
|
||||
|
||||
fun setGameEntity(game: GameEntity) {
|
||||
if (!TextUtils.isEmpty(game.rawIcon)) {
|
||||
ImageUtils.display(gameIconIv, game.rawIcon)
|
||||
ImageUtils.display(gameIconDecoratorIv, game.iconSubscript)
|
||||
} else {
|
||||
ImageUtils.display(gameIconIv, game.icon)
|
||||
}
|
||||
}
|
||||
|
||||
fun getIconIv(): SimpleDraweeView = gameIconIv
|
||||
|
||||
fun getIconDecoratorIv(): SimpleDraweeView = gameIconDecoratorIv
|
||||
|
||||
}
|
||||
32
app/src/main/java/com/gh/common/view/GameTagContainerView.kt
Normal file
32
app/src/main/java/com/gh/common/view/GameTagContainerView.kt
Normal file
@ -0,0 +1,32 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.LinearLayout
|
||||
import com.gh.common.util.tryCatchInRelease
|
||||
|
||||
/**
|
||||
* 游戏列表标签的容器(特定功能的View)
|
||||
*
|
||||
* 一行内,防止标签显示越界
|
||||
*/
|
||||
class GameTagContainerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {
|
||||
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||
super.onLayout(changed, l, t, r, b)
|
||||
tryCatchInRelease {
|
||||
var childContentWidth = 0
|
||||
for (i in 0 until childCount) {
|
||||
val tag = getChildAt(i)
|
||||
val tagLp = tag.layoutParams
|
||||
if (tagLp is LayoutParams) {
|
||||
tag.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
|
||||
val tagWidth = tagLp.leftMargin + tagLp.rightMargin + tag.measuredWidth
|
||||
childContentWidth += tagWidth
|
||||
}
|
||||
}
|
||||
if (childContentWidth > width && childCount > 1) {
|
||||
removeViewAt(childCount - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,17 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.LinearGradient
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Shader
|
||||
import android.graphics.*
|
||||
import android.text.style.ReplacementSpan
|
||||
import androidx.core.graphics.ColorUtils
|
||||
|
||||
class GradientAlphaTextSpan() : ReplacementSpan() {
|
||||
class GradientAlphaTextSpan(var textColor: Int) : ReplacementSpan() {
|
||||
|
||||
override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
|
||||
return paint.measureText(text, start, end).toInt()
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
|
||||
val originalColor = paint.color
|
||||
val originalColor = if (textColor == 0) paint.color else textColor
|
||||
val originalColorWithAlphaChanged = ColorUtils.setAlphaComponent(paint.color, 1)
|
||||
|
||||
val textWidth = paint.measureText(text, start, end).toInt()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user