Compare commits
445 Commits
v4.0.2
...
v4.2.0-202
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ce04241f6 | |||
| f29b8da6d0 | |||
| de968a4820 | |||
| ddddda10a5 | |||
| 30d6dabe4f | |||
| 7655cc25be | |||
| 52824e5baa | |||
| 014c80cd18 | |||
| 99eddec84a | |||
| 6b382ab080 | |||
| d492cfdace | |||
| 256f0af0e9 | |||
| 58d2290e12 | |||
| 547e6da027 | |||
| c3e34ba644 | |||
| 077e17c5aa | |||
| f264875b7d | |||
| 351b8a331c | |||
| 479f7c464b | |||
| e04a7fc4b9 | |||
| 595f7747f4 | |||
| 8c1343fdba | |||
| c3717869bd | |||
| 1e56dc533d | |||
| 1444531830 | |||
| 4e759e446b | |||
| ef6c09d27b | |||
| efc241429c | |||
| 07be540ba1 | |||
| 50479d2e87 | |||
| 2934c9dc38 | |||
| 30a60797e6 | |||
| 53562297d5 | |||
| 144ee3ea8c | |||
| e0c8697e75 | |||
| 6aba2906f6 | |||
| 7bb468a1b1 | |||
| 871be728bf | |||
| bbac0c8d93 | |||
| 6b361ed077 | |||
| 1cfa54f8e8 | |||
| 5bd028cbe9 | |||
| b8f8711ba4 | |||
| c1f899f0d5 | |||
| e4fd74da7d | |||
| bf9cc93daa | |||
| 3b974268a9 | |||
| 822853a4be | |||
| f699841427 | |||
| c700910b15 | |||
| 3c8d0cb3ec | |||
| 8492c762b5 | |||
| b2d70392bb | |||
| eb9cb08624 | |||
| a4ca2628dc | |||
| 727d78d0e5 | |||
| 693d8c4385 | |||
| d46e3fac2d | |||
| 7f0ec7f128 | |||
| 73eb2f6ecb | |||
| 6bd7ced28c | |||
| 086c31a7d4 | |||
| 3a839f6770 | |||
| b67c7e2803 | |||
| b7dbf30845 | |||
| ec86970cbe | |||
| 956755b985 | |||
| fe2779196d | |||
| 9eeeba93d0 | |||
| d7df019d6d | |||
| 68bfc26ddc | |||
| 94a1cfe4b2 | |||
| 936c3b00bb | |||
| b34229e4c4 | |||
| b51322b473 | |||
| e0657ccdcc | |||
| 4b67d8b5aa | |||
| 5b8cc49349 | |||
| 612f71e18c | |||
| 6239ccb8ab | |||
| 9680bea412 | |||
| a21d9096c8 | |||
| e6f3ad5cc2 | |||
| c41e996add | |||
| 58f230038c | |||
| bda41d8a26 | |||
| e3f41543a4 | |||
| 78c4d7acef | |||
| 8c884b6d23 | |||
| a5f9af2df2 | |||
| e2fd6dbf97 | |||
| e430b4e2de | |||
| caa3f46c5c | |||
| b2beba4d36 | |||
| 3a9c7fc71d | |||
| a5f8275f64 | |||
| 8fa3f3d832 | |||
| 97472b8259 | |||
| ee07889b30 | |||
| 8582860116 | |||
| b8903e7814 | |||
| b47bcfc2c3 | |||
| 35a987a835 | |||
| 6f413b27d4 | |||
| 92173b4794 | |||
| 89e79154aa | |||
| de9145cd70 | |||
| 8bf509ee2d | |||
| d7144265e1 | |||
| cc6c759658 | |||
| 8e5d482f9e | |||
| 5ed8f2499a | |||
| a8c9bcc1b0 | |||
| 21aabcc561 | |||
| a2b86a9e21 | |||
| 74882f56ee | |||
| 1eb9ec1dd3 | |||
| 9e95c0cc7e | |||
| 877238d2d5 | |||
| 9c6f69b16a | |||
| 64af456182 | |||
| 1a84477700 | |||
| a0b6285596 | |||
| 951c139062 | |||
| 99efcd6bbf | |||
| 3482f58b1b | |||
| 6b4f751a16 | |||
| 3be1308230 | |||
| b7710cffa3 | |||
| dc4fe89521 | |||
| c33eb6829a | |||
| e1793d57eb | |||
| cc4c48f718 | |||
| aa20ed9744 | |||
| b6d8688a40 | |||
| d1da2bb7fa | |||
| 7828bce732 | |||
| 026a8d7093 | |||
| 6a9a29c5ff | |||
| 16b4b6cc81 | |||
| 863e570b61 | |||
| c9e8408804 | |||
| 31984f1737 | |||
| ad2a0debdd | |||
| 4c45657092 | |||
| 5d7fc94d51 | |||
| 641b430fe5 | |||
| e1bb02f4e0 | |||
| 36fd8cf408 | |||
| e48b47b315 | |||
| 46935e4cad | |||
| b8a6b4baea | |||
| 8a8f0a95ed | |||
| cdbefd2d4f | |||
| 7e79b4e328 | |||
| 11dc9f9be0 | |||
| ec255099eb | |||
| 64738dceaf | |||
| 7d518696f0 | |||
| fcd97b66df | |||
| 47f5c3b7c1 | |||
| b64fee9d25 | |||
| 498efdf5ea | |||
| 59d6450ded | |||
| 7da206af7e | |||
| 8bd669e11a | |||
| 62570aed9e | |||
| bfe9c04384 | |||
| b27d007d47 | |||
| 7e50e6570d | |||
| 336d449889 | |||
| 3dfea1e6f9 | |||
| 3c1780d9b5 | |||
| 35ee7cf03d | |||
| 72e8c18f9c | |||
| f3f876d213 | |||
| 398907db90 | |||
| 5dd251eaa8 | |||
| 2c73e55f43 | |||
| f4406d7960 | |||
| 3e0a620ac5 | |||
| 9ea8c32608 | |||
| e2ea197f9e | |||
| f92038b5bf | |||
| fa9eee2c4a | |||
| 3e62fb61e1 | |||
| 5d71e0ccc1 | |||
| 4699923058 | |||
| 9206938938 | |||
| 46ac569f70 | |||
| b90d1b4f38 | |||
| 592b7bbc5e | |||
| 3ccb8b3772 | |||
| 422abe1b87 | |||
| a14f35a4f0 | |||
| 3bebc92106 | |||
| 21413cf250 | |||
| 04a34af370 | |||
| e1e6924b6e | |||
| fbd3a42e81 | |||
| 80a2cbb8cd | |||
| 96fc6cc183 | |||
| b5ff891db1 | |||
| d2171e7a3b | |||
| c3a06f57b1 | |||
| 18f41743bf | |||
| fcc647a1f8 | |||
| e80b198aa5 | |||
| 52efa96e2c | |||
| 816dd60298 | |||
| a181292f80 | |||
| 1b946c325c | |||
| befb323721 | |||
| e62c0aaaad | |||
| 4ecc0c073b | |||
| faa41248eb | |||
| 6dca13e80b | |||
| f3fab1b3f6 | |||
| 5340a41298 | |||
| 553ebc137b | |||
| caf2a379d9 | |||
| c59b79427c | |||
| dd2338021e | |||
| 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 | |||
| e63a374da1 | |||
| 6564de8a72 | |||
| d57ac57f43 | |||
| 942291d7c5 | |||
| de597bdd36 | |||
| e1fc23a1bb | |||
| 2d551a3f73 | |||
| 9b205366f7 |
@ -67,6 +67,8 @@ android {
|
||||
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
|
||||
buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\""
|
||||
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
|
||||
buildConfigField "String", "DOUYIN_CLIENTKEY", "\"${DOUYIN_CLIENTKEY}\""
|
||||
buildConfigField "String", "DOUYIN_CLIENTSECRET", "\"${DOUYIN_CLIENTSECRET}\""
|
||||
|
||||
buildConfigField "String", "MIPUSH_APPID", "\"${MIPUSH_APPID}\""
|
||||
buildConfigField "String", "MIPUSH_APPKEY", "\"${MIPUSH_APPKEY}\""
|
||||
@ -266,6 +268,7 @@ dependencies {
|
||||
// for video streaming
|
||||
implementation("com.shuyu:gsyVideoPlayer-java:$gsyVideo", {
|
||||
exclude module: "gsyvideoplayer-androidvideocache"
|
||||
exclude group: "tv.danmaku.ijk.media"
|
||||
})
|
||||
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
|
||||
|
||||
@ -283,14 +286,21 @@ dependencies {
|
||||
debugImplementation "com.github.nichbar.chucker:library:$chucker"
|
||||
releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"
|
||||
implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bytedanceApplog"
|
||||
implementation "com.bytedance.ies.ugc.aweme:opensdk-china-external:$bytedanceAweme"
|
||||
implementation "com.bytedance.ies.ugc.aweme:opensdk-common:$bytedanceAweme"
|
||||
|
||||
implementation "com.aliyun.dpa:oss-android-sdk:${oss}"
|
||||
|
||||
implementation "com.airbnb.android:lottie:$lottie"
|
||||
|
||||
implementation "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')
|
||||
@ -300,7 +310,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()) {
|
||||
@ -331,7 +340,7 @@ if (propFile.exists()) {
|
||||
android.buildTypes.release.signingConfig = null
|
||||
}
|
||||
|
||||
// 用于测试读取 META-INF 里的 JSON 的代码
|
||||
// 用于测试读取 META-INF 里的文件
|
||||
//task generateMetaJson {
|
||||
// def resDir = new File(buildDir, 'generated/FILES_FOR_META_INF/')
|
||||
// def destDir = new File(resDir, 'META-INF/')
|
||||
|
||||
Binary file not shown.
BIN
app/libs/gid-1.1.jar
Normal file
BIN
app/libs/gid-1.1.jar
Normal file
Binary file not shown.
@ -40,7 +40,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
|
||||
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
|
||||
|
||||
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
@ -52,14 +52,8 @@
|
||||
com.shuyu.gsy.base,
|
||||
com.google.android.exoplayer2,
|
||||
tv.danmaku.ijk.media.exo2,
|
||||
shuyu.com.androidvideocache,
|
||||
pl.droidsonroids.gif,
|
||||
com.ledong.lib.minigame,
|
||||
com.ledong.lib.leto,
|
||||
com.leto.game.base.glide4,
|
||||
com.leto.game.ad.gdt,
|
||||
com.leto.game.fcm,
|
||||
com.leto.game.ad.toutiao" />
|
||||
com.donkingliang.consecutivescroller" />
|
||||
|
||||
<!-- 去掉 SDK 一些流氓权限 -->
|
||||
<uses-permission
|
||||
@ -113,7 +107,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"
|
||||
@ -168,6 +164,10 @@
|
||||
android:name="com.gh.gamecenter.WebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.FullScreenWebActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.ShareCardPicActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -177,9 +177,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,10 +207,18 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CommentDetailActivity"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:name="com.gh.gamecenter.security.SecurityActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.security.BindPhoneActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CommentDetailActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.mygame.MyGameActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -389,6 +397,10 @@
|
||||
android:name="com.gh.gamecenter.qa.article.detail.ArticleDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.article.detail.comment.ArticleDetailCommentActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.qa.draft.CommunityDraftWrapperActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
@ -419,9 +431,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"
|
||||
@ -449,7 +461,8 @@
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.upload.view.UploadVideoActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateHidden"/>
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.video.game.GameVideoActivity"
|
||||
@ -514,6 +527,40 @@
|
||||
<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=".forum.select.ForumSelectActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.follow.ForumMyFollowActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.detail.ForumDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.moderator.ModeratorListActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".video.label.VideoLabelActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
|
||||
<activity
|
||||
@ -542,6 +589,12 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
|
||||
|
||||
<activity
|
||||
android:name="${applicationId}.douyinapi.DouYinEntryActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:taskAffinity="${applicationId}"
|
||||
android:exported="true" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}"
|
||||
@ -607,7 +660,9 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<meta-data android:name="com.huawei.hms.client.appid" android:value="@string/huawei_push_appid"/>
|
||||
<meta-data
|
||||
android:name="com.huawei.hms.client.appid"
|
||||
android:value="@string/huawei_push_appid" />
|
||||
|
||||
<service
|
||||
android:name="com.gh.base.GHUmengNotificationService"
|
||||
|
||||
1
app/src/main/assets/lottie/tab_forum.json
Normal file
1
app/src/main/assets/lottie/tab_forum.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.6.9","fr":30,"ip":0,"op":20,"w":66,"h":66,"nm":"bottom bar tab/论坛/选中/E","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"矩形","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":4,"s":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":9,"s":[110,110,100]},{"t":13,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":0,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-2.5],[1.5,-2.5],[2.5,-1.5],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.5]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-1.25],[1.5,-1.25],[2.5,-0.25],[2.5,0],[0,1.896],[-2.5,0],[-2.5,-0.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":9,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-2.938],[1.5,-2.938],[2.5,-1.938],[2.5,0],[0,2.833],[-2.5,0],[-2.5,-1.938]],"c":true}]},{"t":13,"s":[{"i":[[-0.55,0],[0,0],[0,-0.55],[0,0],[1.38,0],[0,1.38],[0,0]],"o":[[0,0],[0.55,0],[0,0],[0,1.38],[-1.38,0],[0,0],[0,-0.55]],"v":[[-1.5,-2.5],[1.5,-2.5],[2.5,-1.5],[2.5,0],[0,2.5],[-2.5,0],[-2.5,-1.5]],"c":true}]}],"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":20,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"路径 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,34.599,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.2,0],[2.19,-0.35],[0,-1.82],[0,0],[0,0],[-1.98,0],[0,0],[0,0],[0,0],[-0.72,0.53],[0,0],[0,0],[0,2.05],[0,0],[1.8,0.28]],"o":[[-2.19,0],[-1.8,0.28],[0,0],[0,0],[0.1,1.96],[0,0],[0,0],[0,0],[0.58,0.65],[0,0],[0,0],[2.05,0],[0,0],[0,-1.82],[-2.2,-0.35]],"v":[[-0.003,-9.745],[-6.583,-9.215],[-9.712,-5.555],[-9.712,3.465],[-9.702,3.665],[-6.003,7.175],[-3.383,7.175],[-2.122,9.065],[-2.023,9.185],[0.277,9.405],[3.238,7.175],[5.997,7.175],[9.717,3.465],[9.717,-5.555],[6.587,-9.215]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.266,0.638,1,0.5,0.242,0.595,1,1,0.217,0.552,1],"ix":9}},"s":{"a":0,"k":[-9.712,-9.745],"ix":5},"e":{"a":0,"k":[9.712,9.745],"ix":6},"t":1,"nm":"color","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"路径","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"预合成 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[33,33,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[70,70,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[110,110,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[90,90,100]},{"t":16,"s":[100,100,100]}],"ix":6}},"ao":0,"w":66,"h":66,"ip":0,"op":20,"st":0,"bm":0}],"markers":[]}
|
||||
132
app/src/main/assets/notification_style.json
Normal file
132
app/src/main/assets/notification_style.json
Normal file
@ -0,0 +1,132 @@
|
||||
[
|
||||
{
|
||||
"login": {
|
||||
"title": "开启消息通知",
|
||||
"content": "新游上线、互动回复,重要推送不错过",
|
||||
"image": "bg_notification_login_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景1"
|
||||
},
|
||||
"question": {
|
||||
"title": "开启消息通知",
|
||||
"content": "及时查看大神回答",
|
||||
"image": "bg_notification_question_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景2"
|
||||
},
|
||||
"answer": {
|
||||
"title": "开启消息通知",
|
||||
"content": "及时查看点赞与评论",
|
||||
"image": "bg_notification_answer_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景3"
|
||||
},
|
||||
"article": {
|
||||
"title": "开启消息通知",
|
||||
"content": "及时查看点赞与评论",
|
||||
"image": "bg_notification_article_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景4"
|
||||
},
|
||||
"video": {
|
||||
"title": "开启消息通知",
|
||||
"content": "实时获取审核与推荐进度",
|
||||
"image": "bg_notification_video_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景5"
|
||||
},
|
||||
"rating": {
|
||||
"title": "开启消息通知",
|
||||
"content": "成功上墙立即知道",
|
||||
"image": "bg_notification_rating_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景6"
|
||||
},
|
||||
"gift": {
|
||||
"title": "开启消息通知",
|
||||
"content": "新上礼包不再错过",
|
||||
"image": "bg_notification_gift_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景7"
|
||||
},
|
||||
"reserveGame": {
|
||||
"title": "开启消息通知",
|
||||
"content": "新游上线即时体验",
|
||||
"image": "bg_notification_reserve_game_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景8"
|
||||
},
|
||||
"feedback": {
|
||||
"title": "开启消息通知",
|
||||
"content": "及时查看客服回复",
|
||||
"image": "bg_notification_feedback_style_1",
|
||||
"styleNo": "样式A",
|
||||
"scenes": "场景9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login": {
|
||||
"title": "咦!是新的小伙伴耶!",
|
||||
"content": "打开<font color=\"#1383EB\">通知开关</font>,游戏、礼包、抽奖活动不错过",
|
||||
"image": "bg_notification_login_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景1"
|
||||
},
|
||||
"question": {
|
||||
"title": "发布成功!答案马上来!",
|
||||
"content": "为了第一时间通知您,需要打开<font color=\"#1383EB\">通知开关</font>",
|
||||
"image": "bg_notification_question_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景2"
|
||||
},
|
||||
"answer": {
|
||||
"title": "精彩的回答!大佬牛啤!",
|
||||
"content": "打开<font color=\"#1383EB\">通知开关</font>,可以第一时间收获赞美和感谢哟!",
|
||||
"image": "bg_notification_answer_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景3"
|
||||
},
|
||||
"article": {
|
||||
"title": "发布成功!不愧是你!",
|
||||
"content": "打开<font color=\"#1383EB\">通知开关</font>,可以第一时间收获赞美和互动哟!",
|
||||
"image": "bg_notification_article_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景4"
|
||||
},
|
||||
"video": {
|
||||
"title": "“百万”播放预定!",
|
||||
"content": "<font color=\"#1383EB\">打开通知!</font>第一时间知道审核结果和互动信息哟!",
|
||||
"image": "bg_notification_video_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景5"
|
||||
},
|
||||
"rating": {
|
||||
"title": "这游戏超好玩,我说的!",
|
||||
"content": "想知道有多少人吃下安利?<font color=\"#1383EB\">打开通知</font>,马上知道!",
|
||||
"image": "bg_notification_rating_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景6"
|
||||
},
|
||||
"gift": {
|
||||
"title": "获得道具:神奇的游戏礼包!",
|
||||
"content": "<font color=\"#1383EB\">打开通知!</font>礼包上线,马上知道!",
|
||||
"image": "bg_notification_gift_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景7"
|
||||
},
|
||||
"reserveGame": {
|
||||
"title": "玩最新的游戏,做游戏圈最靓的仔",
|
||||
"content": "<font color=\"#1383EB\">打开通知!</font>游戏上线,更快知道!",
|
||||
"image": "bg_notification_reserve_game_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景8"
|
||||
},
|
||||
"feedback": {
|
||||
"title": "真是重要的反馈!",
|
||||
"content": "感恩有你,光环更精彩!<font color=\"#1383EB\">打开通知</font>,客服回复,马上知道!",
|
||||
"image": "bg_notification_feedback_style_2",
|
||||
"styleNo": "样式B",
|
||||
"scenes": "场景9"
|
||||
}
|
||||
}
|
||||
]
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@ -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
@ -18,12 +18,19 @@ 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.EntranceUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
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;
|
||||
@ -44,10 +51,6 @@ import org.json.JSONObject;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import butterknife.ButterKnife;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
|
||||
@ -97,10 +100,13 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == com.tencent.connect.common.Constants.REQUEST_QQ_SHARE
|
||||
|| requestCode == com.tencent.connect.common.Constants.REQUEST_QZONE_SHARE) {
|
||||
Tencent.onActivityResultData(requestCode, resultCode, data, ShareUtils.getInstance(this).QqShareListener);
|
||||
}
|
||||
ExtensionsKt.tryCatchInRelease(() -> {
|
||||
if (requestCode == com.tencent.connect.common.Constants.REQUEST_QQ_SHARE
|
||||
|| requestCode == com.tencent.connect.common.Constants.REQUEST_QZONE_SHARE) {
|
||||
Tencent.onActivityResultData(requestCode, resultCode, data, ShareUtils.getInstance(this).QqShareListener);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,14 +174,15 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
LinearLayout ll = new LinearLayout(this);
|
||||
TextView tv = new TextView(this);
|
||||
String envText = "正式环境";
|
||||
tv.setBackground(ContextCompat.getDrawable(this, R.color.theme));
|
||||
if (BuildConfig.FLAVOR.equals("internal")) {
|
||||
envText = "测试环境";
|
||||
tv.setBackground(ContextCompat.getDrawable(this, R.color.red));
|
||||
}
|
||||
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();
|
||||
@ -186,6 +193,13 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
ll.addView(tv);
|
||||
ll.setPadding(0, (width - height) / 2, 0, (width - height) / 2);
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
tv.setOnLongClickListener(v -> {
|
||||
EntranceUtils.saveShortcut(this.getClass().getName(), getIntent().getExtras());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
screenRootView.addView(view);
|
||||
screenRootView.addView(ll);
|
||||
|
||||
@ -206,7 +220,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())) {
|
||||
|
||||
@ -95,7 +95,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
|
||||
mDraftBtn.text = if (this is AnswerEditActivity) {
|
||||
"回答草稿"
|
||||
} else "文章草稿"
|
||||
} else "帖子草稿"
|
||||
}
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,
|
||||
|
||||
@ -14,6 +14,13 @@ 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.download.DownloadManager;
|
||||
import com.gh.gamecenter.DownloadManagerActivity;
|
||||
@ -31,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>
|
||||
@ -49,7 +49,7 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
@Nullable
|
||||
private PackageViewModel mPackageViewModel;
|
||||
|
||||
protected RelativeLayout mToolbarContainer;
|
||||
protected View mToolbarContainer;
|
||||
|
||||
protected Toolbar mToolbar;
|
||||
|
||||
|
||||
@ -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())
|
||||
|
||||
|
||||
@ -1,21 +1,24 @@
|
||||
package com.gh.common
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
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.constant.Constants
|
||||
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.entity.NotificationUgc
|
||||
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.gh.gamecenter.user.LoginTag
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
@ -24,6 +27,8 @@ import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class DefaultJsApi(var context: Context) {
|
||||
|
||||
@ -46,7 +51,7 @@ class DefaultJsApi(var context: Context) {
|
||||
|
||||
@JavascriptInterface
|
||||
fun getUserInfo(msg: Any): String {
|
||||
return UserManager.getInstance().userInfoEntity.toJson()
|
||||
return UserManager.getInstance().userInfoEntity?.toJson() ?: ""
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -65,12 +70,11 @@ class DefaultJsApi(var context: Context) {
|
||||
val userInfoEntity = UserManager.getInstance().userInfoEntity
|
||||
if (msg.toString().isNotEmpty()) {
|
||||
val badge = msg.toString().toObject() ?: Badge()
|
||||
userInfoEntity.badge = badge
|
||||
userInfoEntity?.badge = badge
|
||||
} else {
|
||||
userInfoEntity.badge = null
|
||||
userInfoEntity?.badge = null
|
||||
}
|
||||
UserManager.getInstance().userInfoEntity = userInfoEntity
|
||||
AppDatabase.getInstance(context).userInfoDao().updateUserInfo(userInfoEntity)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -83,6 +87,11 @@ class DefaultJsApi(var context: Context) {
|
||||
return BuildConfig.VERSION_NAME
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getAppVersionCode(msg: Any): Int {
|
||||
return PackageUtils.getVersionCode()
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun bindWechat(msg: Any, handler: CompletionHandler<Any>) {
|
||||
context.ifLogin("浏览器") {
|
||||
@ -139,7 +148,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 +171,48 @@ 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, NotificationUgc.LOGIN)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun useDarkStatusBarText(msg: Any) {
|
||||
runOnUiThread {
|
||||
DisplayUtils.transparentStatusBar(context as AppCompatActivity)
|
||||
DisplayUtils.setLightStatusBar(context as AppCompatActivity, msg.toString() == "true")
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun exitWebView(msg: Any) {
|
||||
runOnUiThread { (context as Activity).finish() }
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun updateRegulationTestStatus(msg: Any) {
|
||||
if (msg.toString().toLowerCase(Locale.getDefault()) == "pass") {
|
||||
SPUtils.setString(Constants.SP_REGULATION_TEST_PASS_STATUS, "pass")
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getStatusBarHeight(msg: Any): String {
|
||||
val statusBarHeight = DisplayUtils.getStatusBarHeight(context.resources)
|
||||
return "$statusBarHeight"
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun getGid(msg: Any): String {
|
||||
return HaloApp.getInstance().gid
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun showIncompatibleVersionDialog(msg: Any) {
|
||||
DialogUtils.showLowVersionDialog(context)
|
||||
}
|
||||
|
||||
@Keep
|
||||
|
||||
@ -4,20 +4,23 @@ 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 android.util.Base64
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
|
||||
import com.gh.common.util.DirectUtils.directToGameServerCalendar
|
||||
import com.gh.common.util.DirectUtils.directToGameVideo
|
||||
import com.gh.common.util.DirectUtils.directToLinkPage
|
||||
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.SubjectRecommendEntity
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity
|
||||
import com.gh.common.util.GsonUtils.gson
|
||||
import com.gh.gamecenter.LibaoDetailActivity
|
||||
import com.gh.gamecenter.MainActivity
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.lightgame.utils.Utils
|
||||
import java.nio.charset.Charset
|
||||
|
||||
object DefaultUrlHandler {
|
||||
|
||||
@ -37,7 +40,7 @@ object DefaultUrlHandler {
|
||||
when (host) {
|
||||
"article" -> context.startActivity(NewsDetailActivity.getIntentById(context, id, entrance))
|
||||
|
||||
"game" -> GameDetailActivity.startGameDetailActivity(context, id, "libao" == uri.getQueryParameter("to"), entrance)
|
||||
"game" -> DirectUtils.directToGameDetail(context, id = id, tab = uri.getQueryParameter("to"), autoDownload = uri.getQueryParameter("auto_download") == "true", entrance = entrance)
|
||||
|
||||
"column" -> SubjectActivity.startSubjectActivity(context, id, uri.getQueryParameter("name"), false, entrance)
|
||||
|
||||
@ -50,7 +53,7 @@ object DefaultUrlHandler {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
"qqqun" -> {
|
||||
EntranceUtils.HOST_QQ_QUN -> {
|
||||
val key = uri.getQueryParameter("key")
|
||||
if (!DirectUtils.directToQqGroup(context, key)) {
|
||||
Utils.toast(context, "请检查是否已经安装手机QQ")
|
||||
@ -124,12 +127,14 @@ object DefaultUrlHandler {
|
||||
val title = if (titleParameter.isNullOrEmpty()) "" else "#$titleParameter#"
|
||||
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 tagActivityId = uri.getQueryParameter("tagActivityId") ?: ""
|
||||
val tagActivityName = uri.getQueryParameter("tagActivityName") ?: ""
|
||||
val linkEntity = VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName)
|
||||
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 -> {
|
||||
@ -140,8 +145,19 @@ object DefaultUrlHandler {
|
||||
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 paginationType = uri.getQueryParameter("paginationType")
|
||||
?: "page"//活动分页方式 page filter
|
||||
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, paginationType, fieldId, sectionName)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_SINGLE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
@ -191,7 +207,7 @@ object DefaultUrlHandler {
|
||||
val name = uri.getQueryParameter("name")
|
||||
?: ""
|
||||
val entity = SubjectRecommendEntity(link = id, name = name, text = name)
|
||||
DirectUtils.directToBlock(context, entity)
|
||||
DirectUtils.directToBlock(context, entity, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_SERVER_BLOCK -> {
|
||||
@ -215,14 +231,161 @@ object DefaultUrlHandler {
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_UPLOAD -> {
|
||||
DirectUtils.directGameUpload(context,entrance = entrance, path = "")
|
||||
DirectUtils.directGameUpload(context, entrance = entrance, path = "")
|
||||
}
|
||||
EntranceUtils.HOST_GAME_ZONE -> {
|
||||
val zoneUrl = uri.getQueryParameter("url") ?: ""
|
||||
DirectUtils.directGameZone(context, id, zoneUrl, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_LINK -> {
|
||||
try {
|
||||
val dataString = uri.getQueryParameter("data")
|
||||
if (!TextUtils.isEmpty(dataString)) {
|
||||
val linkData = Base64.decode(dataString, Base64.DEFAULT)
|
||||
val linkDataString = String(linkData, Charset.defaultCharset())
|
||||
val le = gson.fromJson(linkDataString, LinkEntity::class.java)
|
||||
directToLinkPage(context, le, entrance, "")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_NEWS -> {
|
||||
DirectUtils.directToGameNews(
|
||||
context,
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
|
||||
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
|
||||
entrance);
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_CALENDAR -> {
|
||||
directToGameServerCalendar(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID))
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_HISTORY_APK -> {
|
||||
DirectUtils.directToHistoryApk(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID))
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_FORUM_DETAIL -> {
|
||||
DirectUtils.directForumDetail(context, id, entrance)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_GAME_RATING_DETAIL -> {
|
||||
DirectUtils.directToGameRatingDetail(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID), uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID), EntranceUtils.ENTRANCE_BROWSER)
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_FORUM -> {
|
||||
DirectUtils.directToForum(context);
|
||||
}
|
||||
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"
|
||||
|| uri.host == "m.ghzs666.com") {
|
||||
Utils.log(uri.path)
|
||||
uri.path?.apply {
|
||||
when {
|
||||
contains("game") -> {
|
||||
val gameId = uri.getQueryParameter("gameId") ?: ""
|
||||
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = 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
|
||||
}
|
||||
}
|
||||
@ -4,22 +4,26 @@ 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.util.tryCatchInRelease
|
||||
import com.gh.common.videolog.VideoRecordUtils
|
||||
import com.gh.download.DownloadDataHelper
|
||||
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
|
||||
|
||||
object FixedRateJobHelper {
|
||||
private const val CHECKER_PERIOD: Long = 60 * 1000L
|
||||
private const val CHECKER_PERIOD: Long = 15 * 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 const val DOWNLOAD_HEARTBEAT_PERIOD: Long = 60 * 1000L
|
||||
private const val DOWNLOAD_HEARTBEAT_SHEET_PERIOD: Long = 15 * 1000L
|
||||
|
||||
private var mExecuteCount: Int = 0
|
||||
|
||||
var timeDeltaBetweenServerAndClient: Long = 0
|
||||
@ -31,7 +35,7 @@ object FixedRateJobHelper {
|
||||
// 时间校对,10分钟一次
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api.time
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribeOn(AppExecutor.cachedScheduler)
|
||||
.subscribe(object : Response<TimeEntity>() {
|
||||
override fun onResponse(response: TimeEntity?) {
|
||||
val serverTime = response?.time
|
||||
@ -45,6 +49,14 @@ object FixedRateJobHelper {
|
||||
ExposureManager.commitSavedExposureEvents(true)
|
||||
}
|
||||
|
||||
// 分片检测下载进度
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_SHEET_PERIOD == 0L) {
|
||||
tryCatchInRelease {
|
||||
val upload = (mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_PERIOD == 0L
|
||||
DownloadDataHelper.uploadDownloadHeartbeat(upload)
|
||||
}
|
||||
}
|
||||
|
||||
// 提交普通 loghub 数据
|
||||
if ((mExecuteCount * CHECKER_PERIOD) % LOGHUB_PERIOD == 0L) {
|
||||
LoghubUtils.commitSavedLoghubEvents()
|
||||
|
||||
@ -95,6 +95,7 @@ object PushManager {
|
||||
jsonObject.put("os", meta.os)
|
||||
jsonObject.put("os_version", meta.android_version)
|
||||
jsonObject.put("mac", meta.mac)
|
||||
jsonObject.put("gid", meta.gid)
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
|
||||
|
||||
|
||||
@ -51,6 +51,8 @@ public class Config {
|
||||
public static final String BUGLY_APPID = BuildConfig.BUGLY_APPID;
|
||||
public static final String LETO_APPID = BuildConfig.LETO_APPID;
|
||||
public static final String TTAD_APPID = BuildConfig.TTAD_APPID;
|
||||
public static final String DOUYIN_CLIENTKEY = BuildConfig.DOUYIN_CLIENTKEY;
|
||||
public static final String DOUYIN_CLIENTSECRET = BuildConfig.DOUYIN_CLIENTSECRET;
|
||||
// http://www.ghzs666.com/article/${articleId}.html
|
||||
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.constant;
|
||||
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.halo.assistant.HaloApp;
|
||||
|
||||
public class Constants {
|
||||
|
||||
@ -12,11 +13,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 +30,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";
|
||||
// 游戏详情进入时的自定义栏目标签是否已经显示过一次展开更多的浮窗提示
|
||||
@ -42,7 +44,15 @@ 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 EXTRA_DOWNLOAD_TYPE = "extra_download_type";
|
||||
public static final String SILENT_UPDATE = "静默更新";
|
||||
public static final String LAST_GHZS_UPDATE_FILE_SIZE = "last_ghzs_update_file_size";
|
||||
|
||||
// 新用户首次启动光环的时间
|
||||
public static final String SP_INITIAL_USAGE_TIME = "initial_usage_time";
|
||||
|
||||
@ -53,6 +63,9 @@ public class Constants {
|
||||
public static final String SP_SHOWED_NOTIFICATION_ARTICLE = "show_notification_article_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_VIDEO = "show_notification_video_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_RATING = "show_notification_rating_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_GIFT = "show_notification_gift_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_RESERVE_GAME = "show_notification_reserve_game_hint";
|
||||
public static final String SP_SHOWED_NOTIFICATION_FEEDBACK = "show_notification_feedback_hint";
|
||||
// 新版本 也要触发一次“通知管理” 引导弹窗
|
||||
public static final String SP_SHOWED_NOTIFICATION_NEW_VERSION = "show_notification_new_version";
|
||||
// 今天是否已经触发了 “通知管理” 引导弹窗
|
||||
@ -91,6 +104,17 @@ public class Constants {
|
||||
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 SP_FORUM_GUIDE = "forum_guide";
|
||||
//礼仪考试开启状态
|
||||
public static final String SP_REGULATION_TEST_LAST_REMIND_TIME = "regulation_test_last_remind_time";
|
||||
public static final String SP_REGULATION_TEST_STATUS = "regulation_test_status";
|
||||
public static final String SP_REGULATION_TEST_PASS_STATUS = "regulation_test_pass_status";
|
||||
//相同设备号,每一种第三方登录方式登录后弹出绑定手机页面的次数
|
||||
public static final String SP_QQ_SHOW_BIND_PHONE_TIME = "qq_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
public static final String SP_WECHAT_SHOW_BIND_PHONE_TIME = "wechat_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
public static final String SP_WEIBO_SHOW_BIND_PHONE_TIME = "weibo_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
public static final String SP_DOUYIN_SHOW_BIND_PHONE_TIME = "douyin_show_bind_phone_time" + HaloApp.getInstance().getGid();
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
@ -100,14 +124,24 @@ public class Constants {
|
||||
//输入规则
|
||||
public static final String INPUT_RULE = "0123456789abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ_";
|
||||
|
||||
// 微信绑定地址地址
|
||||
// 微信绑定地址
|
||||
public static final String WECHAT_BIND_ADDRESS_DEV = "https://resource.ghzs.com/page/wechat_dev/index.html#/";
|
||||
public static final String WECHAT_BIND_ADDRESS = "https://resource.ghzs.com/page/wechat_pro/index.html#/";
|
||||
|
||||
// 礼仪考试地址
|
||||
public static final String REGULATION_TEST_ADDRESS_DEV = "https://static-web.ghzs.com/etiquette-dev/index.html#/";
|
||||
public static final String REGULATION_TEST_ADDRESS = "https://static-web.ghzs.com/etiquette/index.html#/";
|
||||
|
||||
// 徽章
|
||||
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 String FORUM_REGULATIONS_NEWS_ID = "5f4db9cc34d44d01b92fd670";
|
||||
|
||||
//最少需要多少数据才能上传
|
||||
public static final int DATA_AMOUNT = 20;
|
||||
|
||||
|
||||
@ -40,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;
|
||||
@ -313,6 +315,13 @@ public class BindingAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("game")
|
||||
public static void setGame(View view, GameEntity gameEntity) {
|
||||
if (gameEntity != null && view instanceof GameIconView) {
|
||||
((GameIconView) view).displayGameIcon(gameEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("articleType")
|
||||
public static void setArticleType(TextView view, String articleType) {
|
||||
NewsUtils.setNewsType(view, articleType, 0, 0);
|
||||
@ -427,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, () -> {
|
||||
@ -467,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;
|
||||
@ -506,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;
|
||||
}
|
||||
@ -775,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("-");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,28 +2,34 @@ package com.gh.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.content.res.AssetManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.GsonUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.PermissionHelper
|
||||
import com.gh.common.util.fromHtml
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.NotificationHint
|
||||
import com.gh.gamecenter.entity.NotificationStyleEntity
|
||||
import com.gh.gamecenter.entity.NotificationUgc
|
||||
import com.lightgame.utils.Utils
|
||||
import kotlinx.android.synthetic.main.dialog_notification_hint.*
|
||||
import org.json.JSONArray
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import kotlin.random.Random
|
||||
|
||||
// 通知权限弹窗
|
||||
class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
private var mNotificationHint: NotificationHint? = null
|
||||
private var mNotificationUgc: NotificationUgc? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_notification_hint, null)
|
||||
@ -34,23 +40,34 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
titleTv.text = mNotificationHint?.title
|
||||
|
||||
contentContainer.removeAllViews()
|
||||
for (item in mNotificationHint?.content ?: arrayListOf()) {
|
||||
val tv = TextView(context)
|
||||
|
||||
tv.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = if (contentContainer.childCount == 0) 0 else DisplayUtils.dip2px(12f)
|
||||
}
|
||||
tv.text = item
|
||||
tv.setTextColor(Color.parseColor("#1383EB"))
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
|
||||
contentContainer.addView(tv)
|
||||
val jsonString = getJsonFromAssets()
|
||||
if (jsonString.isNullOrEmpty()) {
|
||||
Utils.log("Failed to obtain configuration file")
|
||||
return
|
||||
}
|
||||
val index = Random.nextInt(2)
|
||||
val jsonArray = JSONArray(jsonString)
|
||||
val jsonObj = jsonArray.getJSONObject(index)
|
||||
if (!jsonObj.has(mNotificationUgc?.value)) {
|
||||
Utils.log("ugc type error")
|
||||
return
|
||||
}
|
||||
val styleEntityJson = jsonObj.getJSONObject(mNotificationUgc!!.value)
|
||||
val styleEntity = GsonUtils.fromJson(styleEntityJson.toString(), NotificationStyleEntity::class.java)
|
||||
val drawableId = resources.getIdentifier(styleEntity.image, "drawable", requireContext().packageName)
|
||||
notificationIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), drawableId))
|
||||
notificationTitle.text = styleEntity.title
|
||||
notificationContent.text = styleEntity.content.fromHtml()
|
||||
if (index == 0) {
|
||||
closeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_notification_close_1))
|
||||
} else {
|
||||
activateTv.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_notification_open_btn_style_1)
|
||||
activateTv.text = "优雅的开启"
|
||||
}
|
||||
|
||||
activateTv.setOnClickListener {
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击立即开启")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击立即开启")
|
||||
dismiss()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
//这种方案适用于 API 26, 即8.0(含8.0)以上可以用
|
||||
@ -63,9 +80,10 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
laterTv.setOnClickListener {
|
||||
closeIv.setOnClickListener {
|
||||
dismiss()
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击以后再说")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "点击关闭")
|
||||
MtaHelper.onEventWithBasicDeviceInfo(getEvent(), getKey(), "${styleEntity.scenes}_${styleEntity.styleNo}_点击关闭")
|
||||
}
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
@ -81,10 +99,30 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
override fun trackWithBasicDeviceInfo() = true
|
||||
|
||||
private fun getJsonFromAssets(): String? {
|
||||
val stringBuilder = StringBuilder()
|
||||
var bufferedReader: BufferedReader? = null
|
||||
var inputStreamReader: InputStreamReader? = null
|
||||
try {
|
||||
inputStreamReader = InputStreamReader(requireContext().assets.open("notification_style.json"))
|
||||
bufferedReader = BufferedReader(inputStreamReader)
|
||||
var line: String?
|
||||
while (bufferedReader.readLine().also { line = it } != null) {
|
||||
stringBuilder.append(line)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
inputStreamReader?.close()
|
||||
bufferedReader?.close()
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(hint: NotificationHint) = NotificationHintDialogFragment().apply {
|
||||
mNotificationHint = hint
|
||||
fun getInstance(ugc: NotificationUgc) = NotificationHintDialogFragment().apply {
|
||||
mNotificationUgc = ugc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,51 +4,80 @@ 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.AppExecutor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.common.repository.ReservationRepository
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.NotificationUgc
|
||||
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
|
||||
: BaseDialogFragment() {
|
||||
: 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
|
||||
@ -57,10 +86,19 @@ class ReserveDialogFragment
|
||||
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? {
|
||||
@ -81,11 +119,14 @@ class ReserveDialogFragment
|
||||
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) {
|
||||
@ -94,6 +135,11 @@ class ReserveDialogFragment
|
||||
HistoryHelper.insertGameEntity(mGame!!)
|
||||
}
|
||||
}
|
||||
|
||||
mViewModel.reserveMobile.observe(viewLifecycleOwner, Observer {
|
||||
setMobileIndexHint(it)
|
||||
})
|
||||
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
|
||||
@ -123,18 +169,57 @@ class ReserveDialogFragment
|
||||
}
|
||||
}
|
||||
|
||||
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("预约游戏", "预约功能操作", "点击无手机号预约")
|
||||
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, "手机号格式错误,请检查并重新输入")
|
||||
@ -148,7 +233,65 @@ class ReserveDialogFragment
|
||||
R.id.close_btn -> {
|
||||
// MtaHelper.onEvent("预约游戏", "预约功能操作", "点击关闭")
|
||||
dismissAllowingStateLoss()
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable {
|
||||
NotificationHelper.showNotificationHintDialog(NotificationUgc.RESERVE_GAME)
|
||||
}, 1000)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,6 +313,12 @@ class ReserveDialogFragment
|
||||
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 = "") {
|
||||
|
||||
@ -201,5 +350,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)
|
||||
}
|
||||
@ -15,5 +15,11 @@ data class ExposureEntity(
|
||||
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
|
||||
@ -39,7 +39,10 @@ data class ExposureEvent(
|
||||
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 }
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
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.debounceActionWithInterval
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.R
|
||||
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 {
|
||||
|
||||
@ -49,7 +51,7 @@ object RegionSettingHelper {
|
||||
list
|
||||
}
|
||||
|
||||
fun shouldGameOfThisCategoryUseMirrorInfo(category: String) : Boolean {
|
||||
fun shouldGameOfThisCategoryUseMirrorInfo(category: String): Boolean {
|
||||
return if (mChannelControl == null || mChannelControl?.effect == false || !isUserUsedLessThan24Hours()) {
|
||||
false
|
||||
} else {
|
||||
@ -60,23 +62,26 @@ object RegionSettingHelper {
|
||||
@SuppressLint("CheckResult")
|
||||
@JvmStatic
|
||||
fun getRegionSetting() {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.sensitiveApi
|
||||
.getRegionSetting(HaloApp.getInstance().channel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.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)
|
||||
debounceActionWithInterval(R.string.name, 3000) {
|
||||
// 使用默认的 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) {
|
||||
|
||||
@ -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 = 6, 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,
|
||||
@ -63,12 +63,19 @@ abstract class HistoryDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -109,6 +110,7 @@ object HistoryHelper {
|
||||
clearHtmlFormatCompletely().
|
||||
replace(" +".toRegex()," ")
|
||||
articleEntity.count = articleDetailEntity.count
|
||||
articleDetailEntity.community.id = articleDetailEntity.communityId
|
||||
articleEntity.community = articleDetailEntity.community
|
||||
articleEntity.time = articleDetailEntity.time
|
||||
articleEntity.title = articleDetailEntity.title
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
package com.gh.common.iinterface
|
||||
|
||||
interface IScrollable {
|
||||
fun scrollToTop()
|
||||
}
|
||||
@ -45,7 +45,7 @@ object ImManager {
|
||||
HaloApp.getInstance().application,
|
||||
ImReceiver.UNIQUE_BROADCAST_ACTION,
|
||||
IM_KEY,
|
||||
UserManager.getInstance().userInfoEntity.name + "(" + UserManager.getInstance().userId + ")",
|
||||
UserManager.getInstance().userInfoEntity?.name + "(" + UserManager.getInstance().userId + ")",
|
||||
UserManager.getInstance().userId)
|
||||
|
||||
shouldShowFloatingWindow = SPUtils.getBoolean(SP_FLOATING_WINDOW_KEY + UserManager.getInstance().userId)
|
||||
@ -75,11 +75,11 @@ object ImManager {
|
||||
try {
|
||||
SPUtils.setBoolean(SP_FLOATING_WINDOW_DOT_KEY + UserManager.getInstance().userId, false)
|
||||
shouldShowFloatingWindowDot = false
|
||||
val chatHelper = KfStartHelper(activity, UserManager.getInstance().userInfoEntity.icon, inputContent, requestCode)
|
||||
val chatHelper = KfStartHelper(activity, UserManager.getInstance().userInfoEntity?.icon, inputContent, requestCode)
|
||||
chatHelper.initSdkChat(
|
||||
ImReceiver.UNIQUE_BROADCAST_ACTION,
|
||||
IM_KEY,
|
||||
UserManager.getInstance().userInfoEntity.name + "(" + UserManager.getInstance().userId + ")"
|
||||
UserManager.getInstance().userInfoEntity?.name + "(" + UserManager.getInstance().userId + ")"
|
||||
+ "[" + BuildConfig.VERSION_NAME + "]",
|
||||
UserManager.getInstance().userId)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
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
|
||||
@ -43,6 +46,23 @@ 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)
|
||||
}
|
||||
@ -86,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)
|
||||
@ -5,14 +5,17 @@ object SyncFieldConstants {
|
||||
// 是否点赞
|
||||
const val ANSWER_VOTE = "ANSWER_VOTE"
|
||||
const val ARTICLE_VOTE = "ARTICLE_VOTE"
|
||||
const val ARTICLE_COMMENT_VOTE = "ARTICLE_COMMENT_VOTE"
|
||||
|
||||
// 赞同数量
|
||||
const val ANSWER_VOTE_COUNT = "ANSWER_VOTE_COUNT"
|
||||
const val ARTICLE_VOTE_COUNT = "ARTICLE_VOTE_COUNT"
|
||||
const val ARTICLE_COMMENT_VOTE_COUNT = "ARTICLE_COMMENT_VOTE_COUNT"
|
||||
|
||||
// 评论数量
|
||||
const val ANSWER_COMMENT_COUNT = "ANSWER_COMMENT_COUNT"
|
||||
const val ARTICLE_COMMENT_COUNT = "ARTICLE_COMMENT_COUNT"
|
||||
const val ARTICLE_COMMENT_REPLY_COUNT = "ARTICLE_COMMENT_REPLY_COUNT"
|
||||
|
||||
// 回答数量
|
||||
const val ANSWER_COUNT = "ANSWER_COUNT"
|
||||
|
||||
@ -21,9 +21,7 @@ object ActivationHelper {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendActivationInfo() {
|
||||
// 能获取到 IMEI 并且之前没发送过激活信息才发
|
||||
if (!mHasSentActivatedInfo
|
||||
&& Util_System_Phone_State.canGetImei(HaloApp.getInstance().application)) {
|
||||
if (!mHasSentActivatedInfo) {
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application)
|
||||
.api.postActivationInfo()
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
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)
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.gh.gamecenter.room.dao.CommentDraftDao
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
object CommentDraftContainer {
|
||||
val commentDraftDao: CommentDraftDao by lazy { AppDatabase.getInstance(HaloApp.getInstance().application).commentDraftDao() }
|
||||
}
|
||||
@ -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,27 +28,29 @@ 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,
|
||||
ignoreModerator: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?) {
|
||||
showCommentOptions(view = view,
|
||||
commentEntity = commentEntity,
|
||||
showConversation = showConversation,
|
||||
articleId = articleId,
|
||||
communityId = communityId,
|
||||
ignoreModerator = ignoreModerator,
|
||||
listener = listener)
|
||||
}
|
||||
|
||||
@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,31 +58,41 @@ 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) {
|
||||
ignoreModerator: Boolean = false,
|
||||
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("投诉")
|
||||
|
||||
commentEntity.me?.let {
|
||||
if (ignoreModerator) return@let
|
||||
|
||||
if (it.isModerator || (it.moderatorPermissions.hideAnswerComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.topAnswerComment > Permissions.GUEST
|
||||
|| it.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST
|
||||
@ -88,55 +105,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,
|
||||
|
||||
@ -12,6 +12,8 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.gh.gamecenter.CommentDetailActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
|
||||
@ -38,7 +40,6 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.ResponseBody;
|
||||
@ -50,9 +51,13 @@ import retrofit2.HttpException;
|
||||
public class CommentUtils {
|
||||
|
||||
public static void setCommentTime(TextView textView, long time) {
|
||||
textView.setText(getCommentTime(time));
|
||||
}
|
||||
|
||||
public static String getCommentTime(long timestamp) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
try {
|
||||
long day = time * 1000;
|
||||
long day = timestamp * 1000;
|
||||
String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
|
||||
format.applyPattern("yyyy");
|
||||
String currentYear = format.format(day);
|
||||
@ -63,35 +68,34 @@ public class CommentUtils {
|
||||
int hour = (int) (min / (60 * 60));
|
||||
if (hour == 0) {
|
||||
if (min < 60) {
|
||||
textView.setText("刚刚");
|
||||
return "刚刚";
|
||||
} else {
|
||||
textView.setText(String.format(Locale.getDefault(), "%d分钟前", (int) (min / 60)));
|
||||
return String.format(Locale.getDefault(), "%d分钟前", (int) (min / 60));
|
||||
}
|
||||
} else {
|
||||
textView.setText(String.format(Locale.getDefault(), "%d小时前", hour));
|
||||
return String.format(Locale.getDefault(), "%d小时前", hour);
|
||||
}
|
||||
} else if (day >= today - 86400 * 1000 && day < today) {
|
||||
format.applyPattern("HH:mm");
|
||||
textView.setText("昨天 ");
|
||||
return "昨天 ";
|
||||
} else if (day >= today - 86400 * 1000 * 7 && day < today - 86400 * 1000) {
|
||||
format.applyPattern("HH:mm");
|
||||
long days = (today - day) / 86400000 + 1;
|
||||
textView.setText(String.format(Locale.getDefault(), "%d天前 ", days));
|
||||
return String.format(Locale.getDefault(), "%d天前 ", days);
|
||||
} else if (day < today - 86400 * 1000 * 7 && year.equals(currentYear)) {
|
||||
format.applyPattern("MM-dd");
|
||||
textView.setText(format.format(day));
|
||||
return format.format(day);
|
||||
} else {
|
||||
format.applyPattern("yyyy-MM-dd");
|
||||
textView.setText(format.format(day));
|
||||
return format.format(day);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
format.applyPattern("yyyy-MM-dd");
|
||||
textView.setText(format.format(time * 1000));
|
||||
return format.format(timestamp * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void showReportDialog(final CommentEntity commentEntity,
|
||||
final Context context,
|
||||
final boolean showConversation,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -141,7 +141,7 @@ public class DataUtils {
|
||||
|
||||
@Override
|
||||
public void onFailure(String s) {
|
||||
Utils.log(s);
|
||||
MtaHelper.onEventWithBasicDeviceInfo("开发辅助", "GID 获取异常", s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -29,6 +29,12 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Config;
|
||||
@ -39,8 +45,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;
|
||||
@ -48,22 +56,19 @@ 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.Util_System_Keyboard;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class DialogUtils {
|
||||
|
||||
public static Dialog showWaitDialog(Context context, String msg) {
|
||||
@ -80,7 +85,6 @@ public class DialogUtils {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
public static void showInstallHintDialog(Context context, final ConfirmListener cmListener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
@ -539,8 +543,6 @@ public class DialogUtils {
|
||||
clListener.onCancel();
|
||||
});
|
||||
dialog.show();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -584,7 +586,6 @@ public class DialogUtils {
|
||||
dialog.setContentView(contentView);
|
||||
dialog.setCancelable(false);
|
||||
dialog.show();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -665,7 +666,6 @@ public class DialogUtils {
|
||||
TextPaint tp = mesage.getPaint();
|
||||
tp.setFakeBoldText(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void showSignDialog(Context context, String title, CharSequence message, CharSequence message2
|
||||
@ -1099,6 +1099,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,
|
||||
@ -1110,7 +1125,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);
|
||||
@ -1265,6 +1290,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);
|
||||
@ -1341,6 +1405,41 @@ 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);
|
||||
|
||||
@ -1368,6 +1467,142 @@ public class DialogUtils {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showRegulationTestDialog(Context context, @NonNull ConfirmListener confirmListener, @NonNull CancelListener cancelListener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new TrackableDialog(
|
||||
context,
|
||||
R.style.GhAlertDialog,
|
||||
"礼仪考试",
|
||||
"礼仪考试弹窗",
|
||||
null, null, null,
|
||||
true);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_regulation_test, null);
|
||||
|
||||
View cancelBtn = contentView.findViewById(R.id.cancel);
|
||||
View confirmBtn = contentView.findViewById(R.id.confirm);
|
||||
View linkTv = contentView.findViewById(R.id.link);
|
||||
|
||||
Context finalContext = context;
|
||||
linkTv.setOnClickListener(v -> {
|
||||
|
||||
MtaHelper.onEvent("礼仪考试", "礼仪考试弹窗", "了解更多");
|
||||
DirectUtils.directToArticle(finalContext, "5f4477be25e07e19be4e2a22", "(礼仪测试弹窗)");
|
||||
});
|
||||
|
||||
cancelBtn.setOnClickListener(v -> {
|
||||
cancelListener.onCancel();
|
||||
|
||||
MtaHelper.onEvent("礼仪考试", "礼仪考试弹窗", "跳过");
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
Context finalContext1 = context;
|
||||
confirmBtn.setOnClickListener(v -> {
|
||||
Util_System_Keyboard.hideSoftKeyboard((Activity) finalContext1);
|
||||
|
||||
MtaHelper.onEvent("礼仪考试", "礼仪考试弹窗", "确定");
|
||||
confirmListener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
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 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();
|
||||
}
|
||||
|
||||
public static void showNoticeDialog(Context context, String title, String content, @NonNull ConfirmListener listener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_notice, null);
|
||||
TextView titleTv = contentView.findViewById(R.id.dialog_title);
|
||||
TextView contentTv = contentView.findViewById(R.id.dialog_content);
|
||||
|
||||
if (title == null) {
|
||||
titleTv.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleTv.setVisibility(View.VISIBLE);
|
||||
titleTv.setText(title);
|
||||
}
|
||||
contentTv.setText(content);
|
||||
|
||||
contentView.findViewById(R.id.dialog_ok).setOnClickListener(v -> {
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public static void showUploadVideoChangeLabelDialog(Context context, @NonNull ConfirmListener confirmListener) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_upload_video_change_label, null);
|
||||
|
||||
View cancelBtn = contentView.findViewById(R.id.cancel);
|
||||
View confirmBtn = contentView.findViewById(R.id.confirm);
|
||||
|
||||
cancelBtn.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
confirmBtn.setOnClickListener(v -> {
|
||||
confirmListener.onConfirm();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
}
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context may be is application context
|
||||
* @return activity context
|
||||
|
||||
@ -12,6 +12,7 @@ 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.constant.Constants
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.exposure.ExposureEvent.Companion.createEvent
|
||||
import com.gh.common.exposure.ExposureManager.log
|
||||
@ -25,10 +26,14 @@ import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.eventbus.EBReuse
|
||||
import com.gh.gamecenter.eventbus.EBSkip
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.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.gamedetail.fuli.kaifu.ServersCalendarActivity
|
||||
import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity
|
||||
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.mygame.PlayedGameActivity
|
||||
import com.gh.gamecenter.personalhome.UserHomeActivity
|
||||
@ -39,17 +44,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
|
||||
|
||||
/**
|
||||
* 跳转用的方法
|
||||
@ -86,9 +98,6 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到特定页面,只支持App内部跳转
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String) {
|
||||
directToLinkPage(context, linkEntity, entrance, path, null)
|
||||
@ -153,7 +162,10 @@ object DirectUtils {
|
||||
|
||||
"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", "社区文章" -> directToCommunityArticle(context, linkEntity.community!!, linkEntity.link!!, entrance, path)
|
||||
|
||||
@ -185,11 +197,14 @@ object DirectUtils {
|
||||
"category", "分类" -> directCategoryDirectory(context, linkEntity.link!!, linkEntity.text!!)
|
||||
|
||||
"block", "版块" -> {
|
||||
directToBlock(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)
|
||||
@ -224,6 +239,8 @@ object DirectUtils {
|
||||
|
||||
"game_upload", "游戏投稿" -> directGameUpload(context, entrance, path)
|
||||
|
||||
"bbs_detail" -> directForumDetail(context, linkEntity.link ?: "", entrance)
|
||||
|
||||
//"h5_game_center" -> directLetoGameCenter(context)
|
||||
|
||||
"" -> {
|
||||
@ -244,7 +261,7 @@ object DirectUtils {
|
||||
*/
|
||||
@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)
|
||||
@ -257,7 +274,7 @@ object DirectUtils {
|
||||
*/
|
||||
@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)
|
||||
@ -270,13 +287,52 @@ 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)
|
||||
bundle.putString(KEY_COLLECTION_ID, id)
|
||||
bundle.putString(KEY_COLUMNNAME, columnName)
|
||||
bundle.putInt(KEY_POSITION, position)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至资讯文章列表
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameNews(context: Context, gameId: String?, gameName: String?, entrance: String?) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, GameNewsActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
bundle.putString(KEY_GAMEID, gameId)
|
||||
bundle.putString(KEY_GAMENAME, gameName)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至游戏日历表
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameServerCalendar(context: Context, gameId: String?) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, ServersCalendarActivity::class.java.name)
|
||||
bundle.putParcelable(GameEntity::class.java.simpleName, GameEntity().apply {
|
||||
id = gameId ?: ""
|
||||
})
|
||||
bundle.putParcelable(GameDetailServer::class.java.simpleName, GameDetailServer())
|
||||
bundle.putParcelable(MeEntity::class.java.simpleName, MeEntity())
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至游戏历史版本页面
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToHistoryApk(context: Context, gameId: String?) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, HistoryApkListActivity::class.java.name)
|
||||
bundle.putString(KEY_GAMEID, gameId)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@ -285,6 +341,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)
|
||||
@ -327,14 +384,19 @@ object DirectUtils {
|
||||
* 跳转到游戏详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, scrollToLibao: Boolean = false, traceEvent: ExposureEvent? = null) {
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, tab: String? = "", 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)
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
if (scrollToLibao) {
|
||||
bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_TRENDES)
|
||||
bundle.putBoolean(KEY_SCROLL_TO_LIBAO, scrollToLibao)
|
||||
if (!TextUtils.isEmpty(tab)) {
|
||||
when (tab) {
|
||||
"comment" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_RATING)
|
||||
"desc" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_DESC)
|
||||
"forum" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_BBS)
|
||||
"zone" -> bundle.putInt(KEY_TARGET, GameDetailFragment.INDEX_TRENDES)
|
||||
}
|
||||
}
|
||||
if (traceEvent != null) {
|
||||
val clickEvent = createEvent(GameEntity(id), traceEvent.source, appendTrace(traceEvent), ExposureType.CLICK)
|
||||
@ -345,6 +407,19 @@ object DirectUtils {
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到游戏评分详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameRatingDetail(context: Context, gameId: String? = "", commentId: String? = "", entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_GAMEID, gameId)
|
||||
bundle.putString(KEY_COMMENTID, commentId)
|
||||
bundle.putString(KEY_TO, RatingReplyActivity::class.java.name)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转视频流-游戏介绍进入
|
||||
*/
|
||||
@ -356,7 +431,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)
|
||||
}
|
||||
|
||||
@ -368,6 +452,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)
|
||||
@ -444,6 +529,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)
|
||||
@ -454,6 +540,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)
|
||||
@ -464,6 +551,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)
|
||||
@ -482,8 +570,9 @@ 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){
|
||||
if (context !is AppCompatActivity) {
|
||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(browserIntent)
|
||||
@ -507,7 +596,7 @@ object DirectUtils {
|
||||
}
|
||||
val str = "mqqwpa://im/chat?chat_type=$chatType&uin=$qq&version=1&src_type=web"
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(str))
|
||||
if (context !is AppCompatActivity){
|
||||
if (context !is AppCompatActivity) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
@ -521,12 +610,13 @@ object DirectUtils {
|
||||
// 跳转 QQ 群
|
||||
@JvmStatic
|
||||
fun directToQqGroup(context: Context, groupNumber: String? = null): Boolean {
|
||||
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){
|
||||
if (context !is AppCompatActivity) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
@ -534,7 +624,7 @@ object DirectUtils {
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
Utils.toast(context, "请安装QQ客户端")
|
||||
return false
|
||||
}
|
||||
@ -546,10 +636,12 @@ 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)
|
||||
bundle.putString(EntranceUtils.KEY_ID, giftId)
|
||||
HaloApp.put(LibaoEntity.TAG, null)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@ -600,6 +692,7 @@ object DirectUtils {
|
||||
|
||||
@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)
|
||||
@ -614,6 +707,7 @@ object DirectUtils {
|
||||
*/
|
||||
@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)
|
||||
@ -627,7 +721,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 = "", paginationType: String = "", fieldId: String = "", sectionName: String = "") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
@ -640,6 +735,9 @@ object DirectUtils {
|
||||
bundle.putString(KEY_REFERER, referer)
|
||||
bundle.putString(KEY_TYPE, type)
|
||||
bundle.putString(KEY_ACTIVITY_NAME, act)
|
||||
bundle.putString(KEY_PAGINATION_TYPE, paginationType)
|
||||
bundle.putString(KEY_FIELD_ID, fieldId)
|
||||
bundle.putString(KEY_SECTION_NAME, sectionName)
|
||||
jumpActivity(context, bundle)
|
||||
} else {
|
||||
DialogUtils.showLowSystemVersionDialog(context)
|
||||
@ -677,20 +775,37 @@ 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)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToFullScreenWebPage(context: Context, url: String, webViewHandleBackPressed: Boolean = false) {
|
||||
context.startActivity(FullScreenWebActivity.getIntent(context, url, webViewHandleBackPressed))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directToRegulationTestPage(context: Context) {
|
||||
val url = if ("internal" == BuildConfig.FLAVOR) {
|
||||
Constants.REGULATION_TEST_ADDRESS_DEV
|
||||
} else {
|
||||
Constants.REGULATION_TEST_ADDRESS
|
||||
}
|
||||
directToFullScreenWebPage(context, url, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转视频合集
|
||||
*/
|
||||
@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)
|
||||
@ -738,6 +853,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)
|
||||
@ -766,6 +882,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)
|
||||
@ -779,10 +896,11 @@ object DirectUtils {
|
||||
* 跳转到板块
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToBlock(context: Context, blockData: SubjectRecommendEntity) {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -814,6 +932,7 @@ object DirectUtils {
|
||||
*/
|
||||
@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)
|
||||
@ -821,4 +940,69 @@ object DirectUtils {
|
||||
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)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directForumDetail(context: Context, bbsId: String? = "", entrance: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, ForumDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_BBS_ID, bbsId)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 到首页论坛 tab
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToForum(context: Context) {
|
||||
if (RunningUtils.isRunning(context)
|
||||
&& MainActivity::class.java.name == RunningUtils.getBaseActivity(context)) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
context.startActivity(intent)
|
||||
|
||||
// 这里换个线程操作是为了做一点延时
|
||||
AppExecutor.ioExecutor.execute {
|
||||
EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_ASK))
|
||||
}
|
||||
} else {
|
||||
jumpActivity(context, Bundle().apply { putInt(KEY_POSITION, MainWrapperFragment.INDEX_ASK) })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
@ -272,13 +273,23 @@ public class DisplayUtils {
|
||||
}
|
||||
|
||||
public static int getToastOffset() {
|
||||
int i = Resources.getSystem().getIdentifier("toast_y_offset", "dimen", "android");
|
||||
return HaloApp.getInstance().getApplication().getResources().getDimensionPixelSize(i);
|
||||
try {
|
||||
int i = Resources.getSystem().getIdentifier("toast_y_offset", "dimen", "android");
|
||||
return HaloApp.getInstance().getApplication().getResources().getDimensionPixelSize(i);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return dip2px(24);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getToastDefaultGravity() {
|
||||
int i = Resources.getSystem().getIdentifier("config_toastDefaultGravity", "integer", "android");
|
||||
return HaloApp.getInstance().getApplication().getResources().getInteger(i);
|
||||
try {
|
||||
int i = Resources.getSystem().getIdentifier("config_toastDefaultGravity", "integer", "android");
|
||||
return HaloApp.getInstance().getApplication().getResources().getInteger(i);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasSoftKeys(Context context) {
|
||||
|
||||
@ -8,12 +8,6 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.DeviceRemindDialog;
|
||||
@ -21,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;
|
||||
@ -40,6 +36,12 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
|
||||
*/
|
||||
@ -261,6 +263,7 @@ public class DownloadItemUtils {
|
||||
boolean isShowPlatform, boolean isNormal) {
|
||||
|
||||
updateItemViewStatus(holder, true, null);
|
||||
holder.gameProgressbar.setProgressDrawable(context.getResources().getDrawable(R.drawable.progressbar_bg_style));
|
||||
|
||||
String platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.getPlatform());
|
||||
|
||||
@ -321,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));
|
||||
@ -454,7 +468,7 @@ public class DownloadItemUtils {
|
||||
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) {
|
||||
@ -520,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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -530,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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -559,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());
|
||||
@ -571,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] + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,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,12 @@ object DownloadNotificationHelper {
|
||||
var requireUpdateNotificationGroupDelay = false
|
||||
val notificationManager = getNotificationManager()
|
||||
val downloadNotificationId = (entity.gameId + entity.packageName).hashCode()
|
||||
val xapkStatus = entity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
|
||||
|
||||
if (entity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.SILENT_UPDATE) return
|
||||
|
||||
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
|
||||
@ -53,7 +58,6 @@ object DownloadNotificationHelper {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// importance == IMPORTANCE_DEFAULT 时每次更新都会触发震动
|
||||
val channel = NotificationChannel(DOWNLOAD_CHANNEL_ID, DOWNLOAD_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
@ -65,18 +69,22 @@ 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 {
|
||||
@ -91,6 +99,11 @@ object DownloadNotificationHelper {
|
||||
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 {
|
||||
notification.flags = notification.flags or Notification.FLAG_NO_CLEAR
|
||||
}
|
||||
|
||||
if (entity.status == DownloadStatus.delete
|
||||
|| entity.status == DownloadStatus.cancel
|
||||
@ -98,7 +111,8 @@ object DownloadNotificationHelper {
|
||||
|| entity.status == DownloadStatus.notfound
|
||||
|| entity.status == DownloadStatus.overflow
|
||||
|| (entity.status == DownloadStatus.done // 触发安装事件以后也 cancel 掉通知
|
||||
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty())) {
|
||||
&& !entity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION].isNullOrEmpty()
|
||||
&& xapkStatus != XapkUnzipStatus.FAILURE.name)) {
|
||||
requireUpdateNotificationGroupDelay = true
|
||||
notificationManager.cancel(entity.path, DOWNLOAD_NOTIFICATION_ID)
|
||||
} else {
|
||||
@ -125,32 +139,35 @@ object DownloadNotificationHelper {
|
||||
}
|
||||
|
||||
private fun updateNotificationGroup() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val notificationManager = getNotificationManager()
|
||||
val activeNotifications = notificationManager.activeNotifications
|
||||
var downloadNotificationSize = 0
|
||||
var downloadGroupNotificationSize = 0
|
||||
for (activeNotification in activeNotifications) {
|
||||
if (activeNotification.id == DOWNLOAD_NOTIFICATION_ID) {
|
||||
downloadNotificationSize++
|
||||
// 部分华为设备调用 getActiveNotifications() 方法时会触发方法内的空指针,这里整体包裹处理了
|
||||
tryCatchInRelease {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val notificationManager = getNotificationManager()
|
||||
val activeNotifications = notificationManager.activeNotifications
|
||||
var downloadNotificationSize = 0
|
||||
var downloadGroupNotificationSize = 0
|
||||
for (activeNotification in activeNotifications) {
|
||||
if (activeNotification.id == DOWNLOAD_NOTIFICATION_ID) {
|
||||
downloadNotificationSize++
|
||||
}
|
||||
if (activeNotification.id == DOWNLOAD_NOTIFICATION_FOLD_ID) {
|
||||
downloadGroupNotificationSize++
|
||||
}
|
||||
}
|
||||
if (activeNotification.id == DOWNLOAD_NOTIFICATION_FOLD_ID) {
|
||||
downloadGroupNotificationSize++
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadNotificationSize == 0 && downloadGroupNotificationSize != 0) {
|
||||
// 删除组可能会把组内所有通知一并删除
|
||||
notificationManager.cancel(DOWNLOAD_NOTIFICATION_FOLD_ID)
|
||||
} else if (downloadNotificationSize != 0 && downloadGroupNotificationSize == 0) {
|
||||
val groupBuilder = NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.logo)
|
||||
.setGroup(DOWNLOAD_GROUP_KEY)
|
||||
.setGroupSummary(true)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText("下载任务"))
|
||||
val groupNotification = groupBuilder.build()
|
||||
groupNotification.flags = groupNotification.flags or Notification.FLAG_NO_CLEAR
|
||||
notificationManager.notify(DOWNLOAD_NOTIFICATION_FOLD_ID, groupNotification)
|
||||
if (downloadNotificationSize == 0 && downloadGroupNotificationSize != 0) {
|
||||
// 删除组可能会把组内所有通知一并删除
|
||||
notificationManager.cancel(DOWNLOAD_NOTIFICATION_FOLD_ID)
|
||||
} else if (downloadNotificationSize != 0 && downloadGroupNotificationSize == 0) {
|
||||
val groupBuilder = NotificationCompat.Builder(HaloApp.getInstance().application, DOWNLOAD_CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.logo)
|
||||
.setGroup(DOWNLOAD_GROUP_KEY)
|
||||
.setGroupSummary(true)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText("下载任务"))
|
||||
val groupNotification = groupBuilder.build()
|
||||
groupNotification.flags = groupNotification.flags or Notification.FLAG_NO_CLEAR
|
||||
notificationManager.notify(DOWNLOAD_NOTIFICATION_FOLD_ID, groupNotification)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
@ -101,11 +107,13 @@ object DownloadObserver {
|
||||
if (DownloadStatus.done == downloadEntity.status) {
|
||||
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
|
||||
MtaHelper.onEvent("软件更新", "下载完成")
|
||||
// 会有 ActivityNotFoundException 异常,catch 掉不管了
|
||||
tryWithDefaultCatch {
|
||||
// 会有 ActivityNotFoundException 异常,catch 掉不管了
|
||||
mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path, true))
|
||||
if (Constants.SILENT_UPDATE != downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)) {
|
||||
PackageInstaller.install(mApplication, downloadEntity)
|
||||
DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据
|
||||
}
|
||||
}
|
||||
DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据
|
||||
} else {
|
||||
statDoneEvent(downloadEntity)
|
||||
|
||||
@ -131,7 +139,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 {
|
||||
// 弹出卸载提示框
|
||||
|
||||
@ -1,18 +1,32 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.MainActivity;
|
||||
import com.gh.gamecenter.NormalActivity;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
* @Date 2017/4/25
|
||||
@ -25,8 +39,10 @@ public class EntranceUtils {
|
||||
public static final String KEY_NEXT_TO = "next_to";
|
||||
public static final String KEY_NEWSID = "newsId";
|
||||
public static final String KEY_GAMEID = "gameId";
|
||||
public static final String KEY_GAME_ID = "game_id";
|
||||
public static final String KEY_ID = "id";
|
||||
public static final String KEY_URL = "url";
|
||||
public static final String KEY_BUNDLE = "bundle";
|
||||
public static final String KEY_GAMENAME = "gameName";
|
||||
public static final String KEY_PACKAGE_MD5 = "package_md5";
|
||||
public static final String HOST_ARTICLE = "article";
|
||||
@ -38,6 +54,7 @@ public class EntranceUtils {
|
||||
public static final String HOST_VIDEO_COLLECTION = "video_collection";//视频合集
|
||||
public static final String HOST_USERHOME = "userhome";//个人主页
|
||||
public static final String HOST_VIDEO = "video";
|
||||
public static final String HOST_FORUM = "forum";
|
||||
public static final String HOST_CATEGORY = "category";//分类
|
||||
public static final String HOST_COLUMN_COLLECTION = "column_collection";//专题合集
|
||||
public static final String HOST_COMMUNITY_QUESTION_LABEL_DETAIL = "community_question_label_detail";//问题标签详情
|
||||
@ -45,25 +62,33 @@ public class EntranceUtils {
|
||||
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_GAME_CALENDAR = "game_calendar";// 指定游戏的开服表页面
|
||||
public static final String HOST_HISTORY_APK = "history_apk"; // 历史版本页面
|
||||
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";
|
||||
public static final String HOST_GAME_DOWNLOAD = "game_download";
|
||||
public static final String HOST_GAME_NEWS = "game_news";
|
||||
public static final String HOST_COLUMN = "column";
|
||||
public static final String HOST_WEB = "web";
|
||||
public static final String HOST_QQ = "qq";
|
||||
public static final String HOST_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_LINK = "link";
|
||||
public static final String HOST_LIBAO = "libao";
|
||||
public static final String HOST_COMMUNITY = "community";
|
||||
public static final String HOST_SUGGESTION = "suggestion";
|
||||
public static final String HOST_ANSWER = "answer";
|
||||
public static final String HOST_QUESTION = "question";
|
||||
public static final String HOST_TOOLBOX = "toolbox";
|
||||
public static final String HOST_FORUM_DETAIL = "forum_detail";
|
||||
public static final String HOST_GAME_RATING_DETAIL = "game_rating_detail";
|
||||
public static final String KEY_DATA = "data";
|
||||
public static final String KEY_MESSAGE = "message";
|
||||
public static final String KEY_MESSAGE_ID = "message_id";
|
||||
@ -81,6 +106,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";
|
||||
@ -91,6 +117,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_LOCATION = "location";
|
||||
public static final String KEY_CURRENTITEM = "currentItem";
|
||||
public static final String KEY_COMMENTID = "commentId";
|
||||
public static final String KEY_COMMENT_ID = "comment_id";
|
||||
public static final String KEY_SHOW_KEYBOARD_IF_NEEDED = "show_key_board_if_needed";
|
||||
public static final String KEY_PATH = "path";
|
||||
public static final String KEY_OUTER_INFO = "outerInfo";
|
||||
@ -140,6 +167,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_COMMUNITY_ARTICLE_ID = "communityArticleId";
|
||||
public static final String KEY_ARTICLE_COMMENT_ID = "articleCommentId";
|
||||
public static final String KEY_SHOW_ARTICLE_COMMENT = "showArticleComment";
|
||||
public static final String KEY_SCROLL_TO_COMMENT_AREA = "scroll_to_comment_area";
|
||||
public static final String KEY_RATING_STAR_COUNT = "ratingStarCount";
|
||||
public static final String KEY_QUESTION_MODERATOR_PATCH = "questionModeratorPatch";
|
||||
public static final String KEY_SKIP_GAME_COMMENT = "skipGameComment";
|
||||
@ -161,7 +189,10 @@ public class EntranceUtils {
|
||||
public static final String KEY_IS_HOME = "isHome";
|
||||
public static final String KEY_WEB_SHARE = "webShare";
|
||||
public static final String KEY_ACTIVITY_NAME = "activityName";//活动名称
|
||||
public static final String KEY_PAGINATION_TYPE = "paginationType";//活动分页方式
|
||||
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";
|
||||
@ -169,6 +200,13 @@ public class EntranceUtils {
|
||||
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 final String KEY_FROM_LOGIN = "fromLogin";
|
||||
public static final String KEY_CHANGE_PHONE = "changePhone";
|
||||
public static final String KEY_CONFLICT_PHONE = "conflictPhone";
|
||||
public static final String KEY_CONFLICT_USER = "conflictUser";
|
||||
public static final String KEY_BBS_ID = "bbs_id";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
@ -224,4 +262,82 @@ public class EntranceUtils {
|
||||
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveShortcut(String activityName, @Nullable Bundle bundle) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
if (activityName.contains("MainActivity")) {
|
||||
SPUtils.setString(EntranceUtils.KEY_BUNDLE, "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bundle == null) bundle = new Bundle();
|
||||
try {
|
||||
Set<String> keys = bundle.keySet();
|
||||
json.put(KEY_TO, activityName);
|
||||
for (String key : keys) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
Object object = bundle.get(key);
|
||||
if (object instanceof Parcelable) {
|
||||
if (object.toString().toLowerCase().contains("gameentity")) {
|
||||
Utils.toast(HaloApp.getInstance().getApplication(), "暂不支持带游戏实体的页面保存捷径");
|
||||
return;
|
||||
}
|
||||
|
||||
String parcelableName = key + ":parcelable";
|
||||
String parcelableType = object.getClass().getName();
|
||||
String objectJsonString = GsonUtils.toJson(object);
|
||||
JSONObject jObject = new JSONObject(objectJsonString);
|
||||
json.put(parcelableName, parcelableType);
|
||||
json.put(key, jObject);
|
||||
} else {
|
||||
json.put(key, JSONObject.wrap(bundle.get(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.toast(HaloApp.getInstance().getApplication(), "保存捷径成功");
|
||||
SPUtils.setString(EntranceUtils.KEY_BUNDLE, json.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
SPUtils.setString(EntranceUtils.KEY_BUNDLE, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void jumpShortcut(Activity activity) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (!hasShortcut()) return;
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(SPUtils.getString(EntranceUtils.KEY_BUNDLE));
|
||||
Iterator iter = jsonObject.keys();
|
||||
String parcelableName = "";
|
||||
while (iter.hasNext()) {
|
||||
String key = (String) iter.next();
|
||||
String value = jsonObject.getString(key);
|
||||
if (key.contains(":parcelable")) {
|
||||
parcelableName = value;
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(parcelableName)) {
|
||||
Class<?> gClass = Class.forName(parcelableName);
|
||||
bundle.putParcelable(key, ((Parcelable) GsonUtils.fromJson(value, gClass)));
|
||||
} else {
|
||||
bundle.putString(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
jumpActivity(activity, bundle);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasShortcut() {
|
||||
return !TextUtils.isEmpty(SPUtils.getString(EntranceUtils.KEY_BUNDLE));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -116,6 +116,8 @@ object ErrorHelper {
|
||||
403078 -> Utils.toast(context, "已点赞")
|
||||
403072 -> Utils.toast(context, R.string.comment_failed_userblocked)
|
||||
403082 -> Utils.toast(context, "作者已关闭评论")
|
||||
403022 -> Utils.toast(context, "不能回复自己")
|
||||
403056 -> Utils.toast(context, "发布失败,字数已达上限")
|
||||
|
||||
403020 -> if (showHighPriorityHint) {
|
||||
DialogUtils.showAlertDialog(context,
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.common.util
|
||||
import android.animation.Animator
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.text.*
|
||||
import android.text.style.ClickableSpan
|
||||
@ -11,6 +12,8 @@ import android.text.style.URLSpan
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorRes
|
||||
@ -19,6 +22,7 @@ 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
|
||||
@ -32,8 +36,10 @@ import com.gh.common.view.ExpandTextView
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
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
|
||||
@ -41,6 +47,7 @@ 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
|
||||
@ -61,6 +68,14 @@ inline fun <reified VM : ViewModel> Fragment.viewModelProviderFromParent(
|
||||
) =
|
||||
ViewModelProviders.of(requireActivity(), provider).get(VM::class.java)
|
||||
|
||||
/**
|
||||
* 创建以 activity 为观察者上下文的 viewModel
|
||||
*/
|
||||
inline fun <reified VM : ViewModel> FragmentActivity.viewModelProviderFromParent(
|
||||
provider: ViewModelProvider.Factory? = null
|
||||
) =
|
||||
ViewModelProviders.of(this, provider).get(VM::class.java)
|
||||
|
||||
/**
|
||||
* 创建以 fragment 为观察者上下文的 viewModel
|
||||
*/
|
||||
@ -159,6 +174,17 @@ fun View.removeSelectableItemBackground() {
|
||||
background = null
|
||||
}
|
||||
|
||||
fun View.setRoundedColorBackground(@ColorRes color: Int, radius: Float) {
|
||||
val shape = GradientDrawable()
|
||||
shape.cornerRadius = radius.dip2px().toFloat()
|
||||
shape.setColor(ContextCompat.getColor(context, color))
|
||||
background = shape
|
||||
}
|
||||
|
||||
fun View.setDebouncedClickListener(action: () -> Unit) {
|
||||
setOnClickListener { debounceActionWithInterval(interval = 300L) { action.invoke() } }
|
||||
}
|
||||
|
||||
/**
|
||||
* LiveData Extensions
|
||||
*/
|
||||
@ -220,6 +246,28 @@ fun String.containHtmlTag(): Boolean {
|
||||
return matcher.find()
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户行为相关
|
||||
*/
|
||||
fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
|
||||
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
|
||||
DialogUtils.showRegulationTestDialog(requireContext(),
|
||||
{ DirectUtils.directToRegulationTestPage(requireContext()) },
|
||||
{ action.invoke() })
|
||||
} else {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
|
||||
if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) {
|
||||
DialogUtils.showRegulationTestDialog(this,
|
||||
{ DirectUtils.directToRegulationTestPage(this) },
|
||||
{ action.invoke() })
|
||||
} else {
|
||||
action()
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 在限定 interval 里只触发一次 action
|
||||
*/
|
||||
@ -275,6 +323,15 @@ fun throwExceptionInDebug(message: String = "", predicate: Boolean = true) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动抛出异常
|
||||
*/
|
||||
fun throwException(message: String = "", predicate: Boolean = true) {
|
||||
if (predicate) {
|
||||
throw RuntimeException(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String related
|
||||
*/
|
||||
@ -314,6 +371,10 @@ 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]
|
||||
@ -364,6 +425,11 @@ fun Float.px2dip(): Int {
|
||||
return (this / scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
fun Float.sp2px():Int{
|
||||
val scale: Float = HaloApp.getInstance().application.resources.displayMetrics.scaledDensity
|
||||
return (this * scale + 0.5f).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* PopupWindow 自动适配方向
|
||||
* 弹出与锚点右对齐
|
||||
@ -444,6 +510,15 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* List related.
|
||||
*/
|
||||
|
||||
// Returns the second element, or `null` if the list is empty.
|
||||
fun <T> List<T>.secondOrNull(): T? {
|
||||
return if (isEmpty() || size == 1) null else this[1]
|
||||
}
|
||||
|
||||
/**
|
||||
* TextView related.
|
||||
*/
|
||||
@ -566,6 +641,21 @@ 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] ?: ""
|
||||
}
|
||||
|
||||
fun DownloadEntity.isSilentUpdate(): Boolean {
|
||||
return Constants.SILENT_UPDATE == getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process related
|
||||
*/
|
||||
@ -682,6 +772,17 @@ 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:不同
|
||||
@ -706,4 +807,15 @@ fun List<String>?.checkSameFromStringArray(check2: List<String>?): Boolean {
|
||||
if (!this.contains(tag)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* EditText弹出软键盘
|
||||
*/
|
||||
fun EditText.showKeyBoard() {
|
||||
this.postDelayed({
|
||||
this.requestFocus()
|
||||
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.showSoftInput(this, 0)
|
||||
}, 300)
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -23,7 +23,7 @@ object GdtHelper {
|
||||
const val PLATFORM = "PLATFORM"
|
||||
|
||||
fun init(application: Application) {
|
||||
GDTAction.init(application, "1110071928", "7fe03caa04ed382e9dce401312b1d0ae")
|
||||
GDTAction.init(application, "1110680399", "f5ddaafbf520d7d7385499232a408d0a")
|
||||
}
|
||||
|
||||
fun logAction(type: String) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
|
||||
@ -31,6 +32,10 @@ object ImageUtils {
|
||||
|
||||
private const val PIC_MAX_FILE_SIZE: Long = 10 * 1024 * 1024
|
||||
|
||||
private val TINY_GIF_SIZE = 30F.dip2px()
|
||||
private val LARGE_GIF_SIZE = 80F.dip2px()
|
||||
private val STANDARD_GIF_SIZE = 60F.dip2px()
|
||||
|
||||
@JvmStatic
|
||||
fun getUploadFileMaxSize(): Long {
|
||||
val uploadLimitSize = Config.getSettings()?.image?.uploadLimitSize
|
||||
@ -216,17 +221,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()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,12 +249,23 @@ object ImageUtils {
|
||||
// 图片是以 gif 结尾的就
|
||||
if (it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false) {
|
||||
if (view?.tag == url) return@let
|
||||
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(url)
|
||||
.setAutoPlayAnimations(true)
|
||||
.build()
|
||||
view?.controller = controller
|
||||
val width = view?.layoutParams?.width
|
||||
val height = view?.layoutParams?.height
|
||||
if (width != null && width > 0) {
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(resizeGif(url, width, height ?: 0))
|
||||
.setAutoPlayAnimations(true)
|
||||
.build()
|
||||
view.controller = controller
|
||||
} else {
|
||||
view?.post {
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(resizeGif(url, view.width, view.height))
|
||||
.setAutoPlayAnimations(true)
|
||||
.build()
|
||||
view.controller = controller
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val width = view?.layoutParams?.width
|
||||
if (width != null && width > 0) {
|
||||
@ -327,14 +347,34 @@ 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)
|
||||
}
|
||||
|
||||
private fun resizeGif(url: String, width: Int, height: Int): String {
|
||||
val idealSize = getIdealGifSize(width, height)
|
||||
return "$url?x-oss-process=image/resize,h_$idealSize,w_$idealSize"
|
||||
}
|
||||
|
||||
private fun getIdealGifSize(width: Int, height: Int): String {
|
||||
return if (width > LARGE_GIF_SIZE || height > LARGE_GIF_SIZE) {
|
||||
"256"
|
||||
} else if (width >= STANDARD_GIF_SIZE || height >= STANDARD_GIF_SIZE) {
|
||||
"192"
|
||||
} else if (width > TINY_GIF_SIZE || height > TINY_GIF_SIZE) {
|
||||
"128"
|
||||
} else {
|
||||
"64"
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnImageloadListener {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import com.gh.gamecenter.entity.ApkEntity;
|
||||
import com.gh.gamecenter.entity.LibaoEntity;
|
||||
import com.gh.gamecenter.entity.LibaoStatusEntity;
|
||||
import com.gh.gamecenter.entity.MeEntity;
|
||||
import com.gh.gamecenter.entity.NotificationUgc;
|
||||
import com.gh.gamecenter.entity.UserDataLibaoEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.eventbus.EBUISwitch;
|
||||
@ -455,20 +456,26 @@ public class LibaoUtils {
|
||||
|
||||
adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context)));
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
final String finalLibaoCode = libaoCode;
|
||||
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, libaoCode))
|
||||
, "关闭", " 复制礼包码"
|
||||
, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
}, null);
|
||||
NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> {
|
||||
if (!isShow){
|
||||
DialogUtils.showWarningDialog(context, "领取成功", Html.fromHtml(context.getString(R.string.linged_dialog, finalLibaoCode))
|
||||
, "关闭", " 复制礼包码"
|
||||
, () -> {
|
||||
copyLink(finalLibaoCode, context);
|
||||
if (isInstallRequired) {
|
||||
libaoBtn.postDelayed(() -> {
|
||||
Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode));
|
||||
lunningAppDialog(context
|
||||
, msg, libaoEntity);
|
||||
}, 300);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,25 +1,32 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
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;
|
||||
import com.gh.gamecenter.entity.ShareResultEntity;
|
||||
import com.gh.gamecenter.entity.SpecialColumn;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.gamecenter.retrofit.EmptyResponse;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
@ -29,7 +36,9 @@ import org.json.JSONObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
/**
|
||||
* Created by khy on 2/01/18.
|
||||
@ -53,55 +62,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 {
|
||||
@ -420,6 +380,55 @@ 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();
|
||||
@ -486,6 +495,7 @@ public class LogUtils {
|
||||
uploadShare(object);
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
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();
|
||||
@ -503,5 +513,13 @@ public class LogUtils {
|
||||
e.printStackTrace();
|
||||
}
|
||||
uploadShare(object);
|
||||
|
||||
ShareResultEntity entity = new ShareResultEntity(new ShareResultEntity.Content(url, title, summary), shareType, shareResult);
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), GsonUtils.toJson(entity));
|
||||
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().getApplication()).getApi()
|
||||
.postShareResult(body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new EmptyResponse<>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@ package com.gh.common.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import com.bytedance.sdk.open.aweme.authorize.model.Authorization
|
||||
import com.bytedance.sdk.open.douyin.DouYinOpenApiFactory
|
||||
import com.bytedance.sdk.open.douyin.DouYinOpenConfig
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.user.LoginTag
|
||||
@ -89,6 +91,8 @@ object LoginHelper {
|
||||
|
||||
WbSdk.install(context, AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE))
|
||||
|
||||
DouYinOpenApiFactory.init(DouYinOpenConfig(Config.DOUYIN_CLIENTKEY))
|
||||
|
||||
Utils.log("LoginHelper initialization")
|
||||
}
|
||||
|
||||
@ -107,6 +111,16 @@ object LoginHelper {
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.wechat, error)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun onDouYinLoginSuccess(content: JSONObject) {
|
||||
mLoginCallback?.get()?.onLoginSuccess(LoginTag.douyin, content)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun onDouYinLoginFailure(error: String) {
|
||||
mLoginCallback?.get()?.onLoginFailure(LoginTag.douyin, error)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun onWeiboLoginCallback(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
mSsoHandler?.get()?.authorizeCallBack(requestCode, resultCode, data)
|
||||
@ -159,7 +173,7 @@ object LoginHelper {
|
||||
if (mAccessToken?.isSessionValid == true) {
|
||||
// 保存 Token 到 SharedPreferences
|
||||
AccessTokenKeeper.writeAccessToken(context, mAccessToken)
|
||||
Toast.makeText(context, "授权成功", Toast.LENGTH_SHORT).show()
|
||||
Utils.toast(context, "授权成功")
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +201,19 @@ object LoginHelper {
|
||||
mAccessToken = AccessTokenKeeper.readAccessToken(context)
|
||||
}
|
||||
|
||||
// 抖音登录
|
||||
@JvmStatic
|
||||
fun loginWithDouYin(loginCallback: LoginCallback, context: Activity) {
|
||||
mLoginCallback = WeakReference(loginCallback)
|
||||
val douYinOpenApi = DouYinOpenApiFactory.create(context)
|
||||
|
||||
val request = Authorization.Request()
|
||||
request.scope = "user_info" // 用户授权时必选权限
|
||||
//request.state = "ww"; // 用于保持请求和回调的状态,授权请求后原样带回给第三方。
|
||||
//request.callerLocalEntry = "com.xxx.xxx...activity";
|
||||
douYinOpenApi.authorize(request)
|
||||
}
|
||||
|
||||
interface LoginCallback {
|
||||
fun onLoginSuccess(loginType: LoginTag, jsonContent: JSONObject)
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -18,7 +18,7 @@ import io.reactivex.schedulers.Schedulers
|
||||
object NotificationHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun showNotificationHintDialog(ugc: NotificationUgc) {
|
||||
fun showNotificationHintDialog(ugc: NotificationUgc, callBack: ((isShow: Boolean) -> Unit)? = null) {
|
||||
val showedNewVersion = SPUtils.getInt(Constants.SP_SHOWED_NOTIFICATION_NEW_VERSION, 0)
|
||||
val currentVersion = PackageUtils.getVersionCode()
|
||||
// 版本升级后重置数据
|
||||
@ -29,6 +29,9 @@ object NotificationHelper {
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ARTICLE, false)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_VIDEO, false)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RATING, false)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_GIFT, false)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RESERVE_GAME, false)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_FEEDBACK, false)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, "")
|
||||
|
||||
SPUtils.setInt(Constants.SP_SHOWED_NOTIFICATION_NEW_VERSION, currentVersion)
|
||||
@ -37,7 +40,10 @@ object NotificationHelper {
|
||||
|
||||
val isShowedToday = SPUtils.getString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, "")
|
||||
// 每天最多只需提示一次
|
||||
if (isShowedToday == TimeUtils.getToday()) return
|
||||
if (isShowedToday == TimeUtils.getToday()){
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
|
||||
val isShowedLogin = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_LOGIN, false)
|
||||
val isShowedQuestion = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_QUESTION, false)
|
||||
@ -45,78 +51,115 @@ object NotificationHelper {
|
||||
val isShowedArticle = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_ARTICLE, false)
|
||||
val isShowedVideo = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_VIDEO, false)
|
||||
val isShowedRating = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_RATING, false)
|
||||
val isShowedGift = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_GIFT, false)
|
||||
val isShowedReserveGame = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_RESERVE_GAME, false)
|
||||
val isShowedFeedback = SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_FEEDBACK, false)
|
||||
|
||||
if (isShowedLogin && isShowedQuestion && isShowedAnswer && isShowedArticle && isShowedVideo && isShowedRating) return
|
||||
if (isShowedLogin && isShowedQuestion && isShowedAnswer && isShowedArticle && isShowedVideo && isShowedRating && isShowedGift && isShowedReserveGame && isShowedFeedback) {
|
||||
callBack?.invoke(false)
|
||||
return
|
||||
}
|
||||
|
||||
when (ugc) {
|
||||
NotificationUgc.LOGIN -> {
|
||||
if (!isShowedLogin) {
|
||||
show(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_LOGIN, true)
|
||||
// 设置今天的时间,表示今天已经触发过了
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.QUESTION -> {
|
||||
if (!isShowedQuestion) {
|
||||
show(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_QUESTION, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.ANSWER -> {
|
||||
if (!isShowedAnswer) {
|
||||
show(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ANSWER, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.ARTICLE -> {
|
||||
if (!isShowedArticle) {
|
||||
show(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_ARTICLE, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.VIDEO -> {
|
||||
if (!isShowedVideo) {
|
||||
show(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_VIDEO, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.RATING -> {
|
||||
if (!isShowedRating) {
|
||||
show(AppManager.getInstance().currentActivity() as AppCompatActivity)
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RATING, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.GIFT -> {
|
||||
if (!isShowedGift) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_GIFT, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.RESERVE_GAME -> {
|
||||
if (!isShowedReserveGame) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_RESERVE_GAME, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
NotificationUgc.FEEDBACK -> {
|
||||
if (!isShowedFeedback) {
|
||||
show(AppManager.getInstance().recentActiveActivity as AppCompatActivity, ugc, callBack)
|
||||
SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_FEEDBACK, true)
|
||||
SPUtils.setString(Constants.SP_IS_SHOWED_NOTIFICATION_TODAY, TimeUtils.getToday())
|
||||
} else {
|
||||
callBack?.invoke(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun show(activity: AppCompatActivity?) {
|
||||
fun show(activity: AppCompatActivity?, ugc: NotificationUgc, callBack: ((isShow: Boolean) -> Unit)? = null) {
|
||||
if (activity == null) return
|
||||
RetrofitManager.getInstance(activity).api.bootPopup
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<NotificationHint>() {
|
||||
override fun onSuccess(data: NotificationHint) {
|
||||
try {
|
||||
showEnableNotificationDialogIfItsDisabled(activity, data)
|
||||
} catch (ignore: Exception) {
|
||||
}
|
||||
}
|
||||
})
|
||||
showEnableNotificationDialogIfItsDisabled(activity, ugc, callBack)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showEnableNotificationDialogIfItsDisabled(activity: AppCompatActivity, notificationHint: NotificationHint) {
|
||||
fun showEnableNotificationDialogIfItsDisabled(activity: AppCompatActivity, ugc: NotificationUgc, callBack: ((isShow: Boolean) -> Unit)? = null) {
|
||||
if (notificationIsEnable()) {
|
||||
Utils.log("notification is enable")
|
||||
callBack?.invoke(false)
|
||||
} else {
|
||||
NotificationHintDialogFragment.getInstance(notificationHint).show(activity.supportFragmentManager, "notification")
|
||||
callBack?.invoke(true)
|
||||
NotificationHintDialogFragment.getInstance(ugc).show(activity.supportFragmentManager, "notification")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -120,7 +120,6 @@ public class PostCommentUtils {
|
||||
final String commentId,
|
||||
final PostCommentListener listener) {
|
||||
|
||||
|
||||
Observable<ResponseBody> observable;
|
||||
|
||||
if (!TextUtils.isEmpty(answerId)) {
|
||||
@ -260,7 +259,6 @@ public class PostCommentUtils {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public interface PostCommentListener {
|
||||
void postSuccess(JSONObject response);
|
||||
|
||||
|
||||
@ -24,10 +24,9 @@ import android.widget.PopupWindow;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
import com.facebook.datasource.DataSource;
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||
import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.WeiBoShareActivity;
|
||||
@ -54,9 +53,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;
|
||||
|
||||
/**
|
||||
@ -72,7 +68,6 @@ public class ShareUtils {
|
||||
private String mTitle;
|
||||
private String mSummary;
|
||||
|
||||
|
||||
private int[] arrLogo = {
|
||||
R.drawable.share_wechat_logo,
|
||||
R.drawable.share_wechatmoments_logo,
|
||||
@ -247,17 +242,17 @@ public class ShareUtils {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
contentView.setOnClickListener(v -> popupWindow.get().dismiss());
|
||||
contentView.setOnClickListener(v -> safelyDismiss());
|
||||
|
||||
contentView.setOnKeyListener((v, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK
|
||||
&& event.getRepeatCount() == 0
|
||||
&& popupWindow != null
|
||||
&& popupWindow.get() != null
|
||||
&& popupWindow.get().isShowing()) {
|
||||
if (callBack != null) {
|
||||
callBack.onCancel();
|
||||
}
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@ -298,7 +293,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,9 +331,9 @@ public class ShareUtils {
|
||||
req.message = msg;
|
||||
req.scene = SendMessageToWX.Req.WXSceneSession;
|
||||
|
||||
loadBitMap(shareIcon, msg, req);
|
||||
loadBitmapAndShare(shareIcon, msg, req);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,10 +341,10 @@ 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) {
|
||||
public void onFirst(Bitmap bitmap) {
|
||||
if (mShareEntrance == ShareEntrance.video) {
|
||||
// 分享类型为视频时裁为正方形
|
||||
int dimension = Math.min(bitmap.getWidth(), bitmap.getHeight());
|
||||
@ -367,8 +362,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
|
||||
Utils.log("分享获取bitmap失败");
|
||||
public void onSecond(Boolean aBoolean) {
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -454,7 +448,7 @@ public class ShareUtils {
|
||||
}
|
||||
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -497,9 +491,9 @@ public class ShareUtils {
|
||||
req.message = msg;
|
||||
req.scene = SendMessageToWX.Req.WXSceneTimeline;
|
||||
|
||||
loadBitMap(shareIcon, msg, req);
|
||||
loadBitmapAndShare(shareIcon, msg, req);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,7 +514,7 @@ public class ShareUtils {
|
||||
|
||||
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,8 +556,8 @@ public class ShareUtils {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
if (mShareEntrance != ShareEntrance.shareGh ) {
|
||||
safelyDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,7 +569,7 @@ public class ShareUtils {
|
||||
cmb.setText(copyContent);
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
Utils.toast(mContext, "复制成功");
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
} else {
|
||||
Utils.toast(mContext, "复制成功,请到微信/QQ粘贴分享");
|
||||
}
|
||||
@ -661,7 +655,7 @@ public class ShareUtils {
|
||||
break;
|
||||
case 7:
|
||||
if (mShareEntrance != ShareEntrance.shareGh) {
|
||||
popupWindow.get().dismiss();
|
||||
safelyDismiss();
|
||||
} else {
|
||||
shareType = "copy_link";
|
||||
LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId);
|
||||
@ -689,6 +683,12 @@ public class ShareUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void safelyDismiss() {
|
||||
if (popupWindow.get() != null) {
|
||||
popupWindow.get().dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
void onItemClick(int position);
|
||||
|
||||
@ -5,10 +5,9 @@ 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
|
||||
@ -23,6 +22,12 @@ class SpanBuilder(content: String) {
|
||||
return this
|
||||
}
|
||||
|
||||
fun color(start: Int, end: Int, colorRes: Int): SpanBuilder {
|
||||
val colorSpan = ForegroundColorSpan(ContextCompat.getColor(HaloApp.getInstance().application, colorRes))
|
||||
spannableString.setSpan(colorSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return this
|
||||
}
|
||||
|
||||
fun color(start: Int, end: Int, colorHexInString: String): SpanBuilder {
|
||||
tryWithDefaultCatch {
|
||||
val colorSpan = ForegroundColorSpan(Color.parseColor(colorHexInString))
|
||||
@ -65,6 +70,23 @@ class SpanBuilder(content: String) {
|
||||
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
|
||||
}
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -84,4 +85,19 @@ object TimeUtils {
|
||||
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,6 +3,7 @@ package com.gh.common.util
|
||||
import android.widget.Toast
|
||||
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.toast.ToastHandler
|
||||
|
||||
object ToastUtils {
|
||||
/** 之前显示的内容 */
|
||||
@ -32,7 +33,7 @@ object ToastUtils {
|
||||
*/
|
||||
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()
|
||||
|
||||
@ -61,7 +61,7 @@ object VideoRecordUtils {
|
||||
if (!UserManager.getInstance().isLoggedIn) return
|
||||
val requestMap = HashMap<String, Any>()
|
||||
val videoIds = videoRecordSet.toList().map { it.videoId }
|
||||
requestMap["g_id"] = HaloApp.getInstance().gid
|
||||
requestMap["g_id"] = HaloApp.getInstance().gid ?: ""
|
||||
requestMap["time"] = time
|
||||
requestMap["video_id"] = videoIds
|
||||
RetrofitManager.getInstance(HaloApp.getInstance().application).api
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -190,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)
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ public class ClearEditTextNormal extends androidx.appcompat.widget.AppCompatEdit
|
||||
mClearDrawable = getCompoundDrawables()[2];
|
||||
if (mClearDrawable == null) {
|
||||
// throw new NullPointerException("You can add drawableRight attribute in XML");
|
||||
mClearDrawable = getResources().getDrawable(R.drawable.icon_close);
|
||||
mClearDrawable = getResources().getDrawable(R.drawable.icon_input_close);
|
||||
}
|
||||
|
||||
// mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
|
||||
|
||||
@ -13,8 +13,8 @@ import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.view.ConfigFilterView.SortSize.Companion.SORT_SIZE_LIST
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.SubjectSettingEntity
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
|
||||
class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
|
||||
@ -26,6 +26,8 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
var ratingTv: TextView //目前只在专题页面显示
|
||||
var recommendedTv: TextView
|
||||
|
||||
var sizeFilterArray: ArrayList<SubjectSettingEntity.Size>? = null
|
||||
|
||||
private var mOnConfigFilterSetupListener: OnConfigFilterSetupListener? = null
|
||||
|
||||
init {
|
||||
@ -37,6 +39,7 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
recommendedTv = findViewById(R.id.recommended_tv)
|
||||
|
||||
mSizeTv.setOnClickListener {
|
||||
mOnConfigFilterSetupListener?.onShowSortSize()
|
||||
showSelectionPopupWindow(this, mSizeTv, mSizeTv.text.toString())
|
||||
}
|
||||
|
||||
@ -98,12 +101,21 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
val flexboxLayout = layout.findViewById<FlexboxLayout>(R.id.flexbox)
|
||||
val backgroundView = layout.findViewById<View>(R.id.background)
|
||||
|
||||
sizeFilterArray = if (sizeFilterArray == null) {
|
||||
getDefaultSizeFilterArray()
|
||||
} else {
|
||||
sizeFilterArray?.apply {
|
||||
if (firstOrNull()?.text != "全部大小") {
|
||||
add(0, SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backgroundView.setOnClickListener {
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
for ((index, sortSizeText) in SORT_SIZE_LIST.withIndex()) {
|
||||
|
||||
for (size in sizeFilterArray!!) {
|
||||
val item = inflater.inflate(R.layout.item_filter_size, flexboxLayout, false)
|
||||
|
||||
// 单列 4 个,强行设置宽度为屏幕的 1/4
|
||||
@ -114,22 +126,22 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
flexboxLayout.addView(item)
|
||||
|
||||
val tv = item.findViewById<TextView>(R.id.size_tv)
|
||||
tv.text = sortSizeText
|
||||
tv.text = size.text
|
||||
|
||||
if (sizeText == sortSizeText) {
|
||||
if (sizeText == size.text) {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
} else {
|
||||
toggleHighlightedTextView(tv, false)
|
||||
}
|
||||
|
||||
tv.tag = SortSize.values()[index]
|
||||
tv.tag = size.text
|
||||
|
||||
item.setOnClickListener {
|
||||
toggleHighlightedTextView(tv, true)
|
||||
popupWindow.dismiss()
|
||||
sizeTv.text = sortSizeText
|
||||
sizeTv.text = size.text
|
||||
|
||||
mOnConfigFilterSetupListener?.onSetupSortSize(tv.tag as SortSize)
|
||||
mOnConfigFilterSetupListener?.onSetupSortSize(size)
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,8 +157,20 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
popupWindow.showAsDropDown(containerView, 0, 0)
|
||||
}
|
||||
|
||||
private fun getDefaultSizeFilterArray(): ArrayList<SubjectSettingEntity.Size> {
|
||||
return arrayListOf<SubjectSettingEntity.Size>().apply {
|
||||
add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小"))
|
||||
add(SubjectSettingEntity.Size(min = -1, max = 20, text = "20M以下"))
|
||||
add(SubjectSettingEntity.Size(min = 20, max = 50, text = "20-50M"))
|
||||
add(SubjectSettingEntity.Size(min = 50, max = 100, text = "50-100M"))
|
||||
add(SubjectSettingEntity.Size(min = 100, max = 500, text = "100-500M"))
|
||||
add(SubjectSettingEntity.Size(min = 500, max = -1, text = "500M以上"))
|
||||
}
|
||||
}
|
||||
|
||||
interface OnConfigFilterSetupListener {
|
||||
fun onSetupSortSize(sortSize: SortSize)
|
||||
fun onShowSortSize()
|
||||
fun onSetupSortSize(sortSize: SubjectSettingEntity.Size)
|
||||
fun onSetupSortType(sortType: SortType)
|
||||
}
|
||||
|
||||
@ -156,41 +180,4 @@ class ConfigFilterView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
RATING
|
||||
}
|
||||
|
||||
enum class SortSize(val value: String) {
|
||||
UNSPECIFIED("全部大小"),
|
||||
|
||||
SMALLER_THAN_20M("20M以下"),
|
||||
|
||||
BETWEEN_20M_AND_50M("20-50M"),
|
||||
|
||||
BETWEEN_50M_AND_100M("50-100M"),
|
||||
|
||||
BETWEEN_100M_AND_500M("100-500M"),
|
||||
|
||||
LARGER_THAN_500M("500M以上");
|
||||
|
||||
override fun toString() = value
|
||||
|
||||
fun toSize(): Size {
|
||||
return when (this) {
|
||||
UNSPECIFIED -> Size(minSize = -1, maxSize = -1)
|
||||
SMALLER_THAN_20M -> Size(minSize = -1, maxSize = 20)
|
||||
BETWEEN_20M_AND_50M -> Size(minSize = 20, maxSize = 50)
|
||||
BETWEEN_50M_AND_100M -> Size(minSize = 50, maxSize = 100)
|
||||
BETWEEN_100M_AND_500M -> Size(minSize = 100, maxSize = 500)
|
||||
LARGER_THAN_500M -> Size(minSize = 500, maxSize = -1)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val SORT_SIZE_LIST = arrayListOf<String>().apply {
|
||||
values().iterator().forEach {
|
||||
this.add(it.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Size(var minSize: Int = -1, var maxSize: Int = -1)
|
||||
}
|
||||
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.LinearLayout
|
||||
|
||||
/**
|
||||
* 自定义ViewGroup中child绘制顺序
|
||||
*/
|
||||
class CustomOrderDrawChildLinearLayout(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
|
||||
|
||||
override fun isChildrenDrawingOrderEnabled(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getChildDrawingOrder(childCount: Int, i: Int): Int {
|
||||
return childCount - i - 1//倒序
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@ -194,6 +194,8 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
|
||||
msp.replace(expandTextStartPosition, length, finalEndText + mExpandText);
|
||||
|
||||
if (expandTextStartPosition + mEndText.length() >= msp.length()) return;
|
||||
|
||||
msp.setSpan(new ClickableSpan() {
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
|
||||
@ -24,7 +24,8 @@ public class FixLinearLayoutManager extends LinearLayoutManager {
|
||||
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||
try {
|
||||
super.onLayoutChildren(recycler, state);
|
||||
} catch (Exception ignore) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
24
app/src/main/java/com/gh/common/view/FixedScrollView.kt
Normal file
24
app/src/main/java/com/gh/common/view/FixedScrollView.kt
Normal file
@ -0,0 +1,24 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.ScrollView
|
||||
|
||||
/**
|
||||
* 不能滑动的 ScrollView
|
||||
*/
|
||||
class FixedScrollView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ScrollView(context, attrs) {
|
||||
|
||||
override fun onTouchEvent(ev: MotionEvent?): Boolean {
|
||||
return when (ev?.action) {
|
||||
MotionEvent.ACTION_DOWN -> true
|
||||
else -> super.onTouchEvent(ev)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
68
app/src/main/java/com/gh/common/view/GameIconView.kt
Normal file
68
app/src/main/java/com/gh/common/view/GameIconView.kt
Normal file
@ -0,0 +1,68 @@
|
||||
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.common.util.goneIf
|
||||
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
|
||||
private var mBorderColor = 0
|
||||
private var mBorderWidth = 1
|
||||
|
||||
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))
|
||||
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
|
||||
mBorderWidth = ta.getDimensionPixelSize(R.styleable.GameIconView_gameIconBorderWidth, 1)
|
||||
ta.recycle()
|
||||
|
||||
val roundingParams = RoundingParams.fromCornersRadius(mCornerRadius.toFloat())
|
||||
|
||||
if (mBorderColor != 0) {
|
||||
roundingParams.setBorder(mBorderColor, mBorderWidth.toFloat())
|
||||
}
|
||||
gameIconIv.hierarchy.roundingParams = roundingParams
|
||||
gameIconDecoratorIv.hierarchy.roundingParams = roundingParams
|
||||
}
|
||||
|
||||
fun displayGameIcon(game: GameEntity) {
|
||||
if (!TextUtils.isEmpty(game.rawIcon)) {
|
||||
displayGameIcon(game.rawIcon ?: "", game.iconSubscript)
|
||||
} else {
|
||||
displayGameIcon(game.icon ?: "", null)
|
||||
}
|
||||
}
|
||||
|
||||
fun displayGameIcon(icon: String?, iconSubscript: String?) {
|
||||
ImageUtils.display(gameIconIv, icon)
|
||||
ImageUtils.display(gameIconDecoratorIv, iconSubscript)
|
||||
gameIconDecoratorIv.goneIf(TextUtils.isEmpty(iconSubscript))
|
||||
}
|
||||
|
||||
fun getIconIv(): SimpleDraweeView = gameIconIv
|
||||
|
||||
fun getIconDecoratorIv(): SimpleDraweeView = gameIconDecoratorIv
|
||||
|
||||
}
|
||||
@ -4,9 +4,10 @@ import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
|
||||
public class HorizontalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
@ -14,6 +15,7 @@ public class HorizontalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
private Paint paint;
|
||||
private int mInterval = 0;
|
||||
private int mSize = 0;
|
||||
private boolean mIncludeEnd = false;
|
||||
|
||||
public HorizontalItemDecoration(Context context, int interval, int size) {
|
||||
paint = new Paint();
|
||||
@ -22,6 +24,15 @@ public class HorizontalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public HorizontalItemDecoration(Context context, int interval, int size, boolean includeEnd) {
|
||||
paint = new Paint();
|
||||
paint.setColor(Color.WHITE);
|
||||
mInterval = DisplayUtils.dip2px(context, interval);
|
||||
mSize = size;
|
||||
mIncludeEnd = includeEnd;
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
// int top = parent.getPaddingTop();
|
||||
@ -39,7 +50,7 @@ public class HorizontalItemDecoration extends RecyclerView.ItemDecoration {
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state) {
|
||||
if (parent.getChildPosition(view) == mSize - 1) {
|
||||
if (!mIncludeEnd && parent.getChildPosition(view) == mSize - 1) {
|
||||
outRect.set(0, 0, 0, 0);
|
||||
} else {
|
||||
outRect.set(0, 0, mInterval, 0);
|
||||
|
||||
@ -9,13 +9,14 @@ import android.text.style.ClickableSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class MessageSpannableTextView extends androidx.appcompat.widget.AppCompatTextView {
|
||||
public class MessageSpannableTextView extends AppCompatTextView {
|
||||
|
||||
private OnSpannableClickListener mSpannableClickListener;
|
||||
|
||||
|
||||
@ -269,6 +269,7 @@ public class NestedScrollWebView2 extends DWebView implements NestedScrollingChi
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
returnValue = super.onTouchEvent(ev);
|
||||
}
|
||||
initVelocityTrackerIfNotExists();
|
||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package com.gh.common.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
public class NoScrollFocusScrollView extends ScrollView {
|
||||
|
||||
public NoScrollFocusScrollView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public NoScrollFocusScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public NoScrollFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -14,11 +14,11 @@ import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import com.gh.common.DefaultJsApi;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.util.DeviceUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EmptyCallback;
|
||||
import com.gh.common.util.GsonUtils;
|
||||
import com.gh.common.util.HtmlUtils;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
@ -69,6 +69,10 @@ public class RichEditor extends WebView {
|
||||
private int mDefaultImageWidth;
|
||||
private int mThumbnailImageWidth;
|
||||
|
||||
private EmptyCallback mInitialLayoutCallback;
|
||||
|
||||
private String mCurrentContent = "";
|
||||
|
||||
public enum Type {
|
||||
BOLD,
|
||||
ITALIC,
|
||||
@ -173,6 +177,10 @@ public class RichEditor extends WebView {
|
||||
mChromeClientListener = chromeClientListener;
|
||||
}
|
||||
|
||||
public void setLayoutCallback(EmptyCallback layoutCallback) {
|
||||
mInitialLayoutCallback = layoutCallback;
|
||||
}
|
||||
|
||||
private void callback(String text) {
|
||||
mContents = text.replaceFirst(CALLBACK_SCHEME, "");
|
||||
if (mTextChangeListener != null) {
|
||||
@ -594,6 +602,10 @@ public class RichEditor extends WebView {
|
||||
this.mContentOwner = contentOwner;
|
||||
}
|
||||
|
||||
public String getCurrentContent() {
|
||||
return mCurrentContent;
|
||||
}
|
||||
|
||||
public interface WebChromeClientListener {
|
||||
void onPageFinished(WebView view, String url);
|
||||
|
||||
@ -720,4 +732,15 @@ public class RichEditor extends WebView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
|
||||
if (mInitialLayoutCallback != null &&getHeight() > 0) {
|
||||
// 仅初次 layout 完成会有回调
|
||||
mInitialLayoutCallback.onCallback();
|
||||
mInitialLayoutCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
package com.gh.common.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
@ -11,6 +10,9 @@ import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.scwang.smartrefresh.layout.R;
|
||||
import com.scwang.smartrefresh.layout.api.RefreshHeader;
|
||||
import com.scwang.smartrefresh.layout.api.RefreshLayout;
|
||||
@ -23,6 +25,7 @@ import com.scwang.smartrefresh.layout.util.DensityUtil;
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressWarnings({"unused", "UnusedReturnValue"})
|
||||
public class SwipeRefreshHeader extends AbstractSwipeRefreshHeader<SwipeRefreshHeader> implements RefreshHeader {
|
||||
|
||||
@ -83,7 +86,7 @@ public class SwipeRefreshHeader extends AbstractSwipeRefreshHeader<SwipeRefreshH
|
||||
} else {
|
||||
mArrowDrawable = new ArrowDrawable();
|
||||
mArrowDrawable.setColor(0xff666666);
|
||||
mArrowView.setImageDrawable(mArrowDrawable);
|
||||
mArrowView.setImageResource(com.gh.gamecenter.R.drawable.refresh_icon);
|
||||
}
|
||||
|
||||
if (ta.hasValue(R.styleable.ClassicsHeader_srlDrawableProgress)) {
|
||||
@ -91,7 +94,7 @@ public class SwipeRefreshHeader extends AbstractSwipeRefreshHeader<SwipeRefreshH
|
||||
} else {
|
||||
mProgressDrawable = new ProgressDrawable();
|
||||
mProgressDrawable.setColor(0xff666666);
|
||||
mProgressView.setImageDrawable(mProgressDrawable);
|
||||
mProgressView.setImageResource(com.gh.gamecenter.R.drawable.refresh_anim);
|
||||
}
|
||||
|
||||
if (ta.hasValue(R.styleable.ClassicsHeader_srlTextSizeTitle)) {
|
||||
@ -140,7 +143,7 @@ public class SwipeRefreshHeader extends AbstractSwipeRefreshHeader<SwipeRefreshH
|
||||
mCenterLayout.setVisibility(VISIBLE);
|
||||
mTitleText.setText(REFRESH_HEADER_PULLING);
|
||||
mArrowView.setVisibility(VISIBLE);
|
||||
mArrowView.animate().rotation(0);
|
||||
// mArrowView.animate().rotation(0);
|
||||
break;
|
||||
case Refreshing:
|
||||
case RefreshReleased:
|
||||
@ -153,7 +156,7 @@ public class SwipeRefreshHeader extends AbstractSwipeRefreshHeader<SwipeRefreshH
|
||||
successView.setVisibility(GONE);
|
||||
mCenterLayout.setVisibility(VISIBLE);
|
||||
mTitleText.setText(REFRESH_HEADER_RELEASE);
|
||||
mArrowView.animate().rotation(180);
|
||||
// mArrowView.animate().rotation(180);
|
||||
break;
|
||||
case Loading:
|
||||
successView.setVisibility(GONE);
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* 如非特殊情况请勿使用,会强行改变RecyclerView的拦截事件,可能会出现意料之外的问题
|
||||
*/
|
||||
class TouchSlopRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
|
||||
: RecyclerView(context, attrs) {
|
||||
|
||||
private var mPrevX = 0f
|
||||
|
||||
// 触控角度,用来控制触发左右滑动的敏感度
|
||||
var touchSlop = ViewConfiguration.get(context).scaledTouchSlop
|
||||
|
||||
// 默认关闭,否则会误杀上下滑动事件
|
||||
var touchSlopEnabled = false
|
||||
|
||||
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> mPrevX = event.x
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val eventX = event.x
|
||||
val xDiff = abs(eventX - mPrevX)
|
||||
if (touchSlopEnabled && xDiff > touchSlop) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onInterceptTouchEvent(event)
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.TimeElapsedHelper
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.constant.Constants.SP_LAST_OPENING_ID
|
||||
import com.gh.common.constant.Constants.SP_LAST_OPENING_TIME
|
||||
import com.gh.common.util.*
|
||||
@ -15,12 +16,19 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.DialogWelcomeBinding
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.WelcomeDialogEntity
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class WelcomeDialog : BaseDialogFragment() {
|
||||
|
||||
companion object {
|
||||
const val TAG = "welcome_dialog"
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(welcomeEntity: WelcomeDialogEntity?) = WelcomeDialog().apply { mWelcomeEntity = welcomeEntity }
|
||||
fun getInstance(welcomeEntity: WelcomeDialogEntity?) = WelcomeDialog().apply {
|
||||
arguments = Bundle()
|
||||
arguments?.putParcelable(TAG, welcomeEntity)
|
||||
LogUtils.uploadWelcomeDialog("show", welcomeEntity?.id, welcomeEntity?.text)
|
||||
}
|
||||
}
|
||||
|
||||
private var mWelcomeEntity: WelcomeDialogEntity? = null
|
||||
@ -34,12 +42,18 @@ class WelcomeDialog : BaseDialogFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mWelcomeEntity = arguments?.getParcelable(TAG)
|
||||
mTimeHelper = TimeElapsedHelper(this)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
binding = DataBindingUtil.inflate(inflater, R.layout.dialog_welcome, container, false)
|
||||
binding.ivOpeningCover.setOnClickListener {
|
||||
|
||||
HaloApp.put(Constants.WELCOME_DIALOG_ID, mWelcomeEntity?.id)
|
||||
HaloApp.put(Constants.WELCOME_DIALOG_LINK_TITLE, mWelcomeEntity?.text)
|
||||
LogUtils.uploadWelcomeDialog("click", mWelcomeEntity?.id, mWelcomeEntity?.text)
|
||||
|
||||
when (mWelcomeEntity?.type) {
|
||||
EntranceUtils.HOST_ARTICLE -> {
|
||||
DirectUtils.directToArticle(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
@ -51,10 +65,10 @@ class WelcomeDialog : BaseDialogFragment() {
|
||||
DirectUtils.directToSubject(requireContext(), mWelcomeEntity?.link!!, null, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_QUESTION -> {
|
||||
DirectUtils.directToQuestionDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
|
||||
DirectUtils.directToQuestionDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_ANSWER -> {
|
||||
DirectUtils.directToAnswerDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
|
||||
DirectUtils.directToAnswerDetail(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
}
|
||||
EntranceUtils.HOST_WEB -> {
|
||||
DirectUtils.directToWebView(requireContext(), mWelcomeEntity?.link!!, EntranceUtils.ENTRANCE_WELCOME)
|
||||
@ -67,7 +81,7 @@ class WelcomeDialog : BaseDialogFragment() {
|
||||
}
|
||||
// else -> DialogUtils.showLowVersionDialog(context)
|
||||
else -> DirectUtils.directToLinkPage(requireContext(), mWelcomeEntity
|
||||
?: WelcomeDialogEntity(), EntranceUtils.ENTRANCE_WELCOME, "首页弹窗")
|
||||
?: WelcomeDialogEntity(), EntranceUtils.ENTRANCE_WELCOME, "")
|
||||
}
|
||||
|
||||
mDismissByClickImage = true
|
||||
@ -111,15 +125,9 @@ class WelcomeDialog : BaseDialogFragment() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
val type = if (mDismissByClickImage) {
|
||||
"点击图片"
|
||||
} else {
|
||||
"点击关闭"
|
||||
}
|
||||
val type = if (mDismissByClickImage) "点击图片" else "点击关闭"
|
||||
|
||||
DataUtils.trackTimeEvent(context, "启动弹窗",
|
||||
mTimeHelper?.elapsedTime!!,
|
||||
type, "No parameter.")
|
||||
MtaHelper.onEventWithTime("启动弹窗", mTimeHelper?.elapsedTime!!, type, "No parameter.")
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(context?.applicationContext).edit {
|
||||
putString(SP_LAST_OPENING_ID, mWelcomeEntity?.id)
|
||||
|
||||
@ -75,6 +75,12 @@ public class DWebView extends WebView {
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JavascriptInterface
|
||||
public String call(String methodName) {
|
||||
return call(methodName, "");
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JavascriptInterface
|
||||
public String call(String methodName, String argStr) {
|
||||
@ -93,7 +99,7 @@ public class DWebView extends WebView {
|
||||
PrintDebugInfo(error);
|
||||
return ret.toString();
|
||||
}
|
||||
Object arg=null;
|
||||
Object arg = null;
|
||||
Method method = null;
|
||||
String callback = null;
|
||||
|
||||
@ -102,7 +108,7 @@ public class DWebView extends WebView {
|
||||
if (args.has("_dscbstub")) {
|
||||
callback = args.getString("_dscbstub");
|
||||
}
|
||||
if(args.has("data")) {
|
||||
if (args.has("data")) {
|
||||
arg = args.get("data");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
@ -123,7 +129,10 @@ public class DWebView extends WebView {
|
||||
try {
|
||||
method = cls.getMethod(methodName, new Class[]{Object.class});
|
||||
} catch (Exception ex) {
|
||||
|
||||
try {
|
||||
method = cls.getMethod(methodName, new Class[]{});
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +196,12 @@ public class DWebView extends WebView {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
retData = method.invoke(jsb, arg);
|
||||
Class<?>[] methodParameterTypes = method.getParameterTypes();
|
||||
if (methodParameterTypes.length == 0) {
|
||||
retData = method.invoke(jsb);
|
||||
} else {
|
||||
retData = method.invoke(jsb, arg);
|
||||
}
|
||||
ret.put("code", 0);
|
||||
ret.put("data", retData);
|
||||
return ret.toString();
|
||||
@ -307,7 +321,10 @@ public class DWebView extends WebView {
|
||||
try {
|
||||
method = cls.getMethod(nameStr[1], new Class[]{Object.class});
|
||||
} catch (Exception ex) {
|
||||
|
||||
try {
|
||||
method = cls.getMethod(nameStr[1], new Class[]{});
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method != null) {
|
||||
@ -336,7 +353,7 @@ public class DWebView extends WebView {
|
||||
|| javascriptCloseWindowListener.onClose()) {
|
||||
Context context = getContext();
|
||||
if (context instanceof Activity) {
|
||||
((Activity)context).onBackPressed();
|
||||
((Activity) context).onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,7 +376,7 @@ public class DWebView extends WebView {
|
||||
|
||||
@Keep
|
||||
@JavascriptInterface
|
||||
public void returnValue(final Object obj){
|
||||
public void returnValue(final Object obj) {
|
||||
runOnMainThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -390,7 +407,17 @@ public class DWebView extends WebView {
|
||||
|
||||
private void _evaluateJavascript(String script) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
DWebView.super.evaluateJavascript(script, null);
|
||||
try {
|
||||
DWebView.super.evaluateJavascript(script, null);
|
||||
} catch (Exception e) {
|
||||
// 部分机型把自己伪装成 Android 4.4 然后没 evaluateJavascript 方法!
|
||||
e.printStackTrace();
|
||||
try {
|
||||
super.loadUrl("javascript:" + script);
|
||||
} catch (Exception ignored){
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.loadUrl("javascript:" + script);
|
||||
}
|
||||
@ -422,9 +449,9 @@ public class DWebView extends WebView {
|
||||
runOnMainThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (url != null && url.startsWith("javascript:")){
|
||||
if (url != null && url.startsWith("javascript:")) {
|
||||
DWebView.super.loadUrl(url);
|
||||
}else{
|
||||
} else {
|
||||
callInfoList = new ArrayList<>();
|
||||
DWebView.super.loadUrl(url);
|
||||
}
|
||||
@ -444,9 +471,9 @@ public class DWebView extends WebView {
|
||||
runOnMainThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (url != null && url.startsWith("javascript:")){
|
||||
if (url != null && url.startsWith("javascript:")) {
|
||||
DWebView.super.loadUrl(url, additionalHttpHeaders);
|
||||
}else{
|
||||
} else {
|
||||
callInfoList = new ArrayList<>();
|
||||
DWebView.super.loadUrl(url, additionalHttpHeaders);
|
||||
}
|
||||
@ -996,7 +1023,4 @@ public class DWebView extends WebView {
|
||||
mainHandler.post(runnable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.gh.common.view.vertical_recycler
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
|
||||
class SnappingLinearLayoutManager(val context: Context) : LinearLayoutManager(context) {
|
||||
override fun smoothScrollToPosition(recyclerView: RecyclerView?, state: RecyclerView.State?, position: Int) {
|
||||
tryWithDefaultCatch {
|
||||
val smoothScroller = object : LinearSmoothScroller(context) {
|
||||
override fun getVerticalSnapPreference(): Int = SNAP_TO_START
|
||||
override fun computeScrollVectorForPosition(targetPosition: Int): PointF =
|
||||
this@SnappingLinearLayoutManager.computeScrollVectorForPosition(targetPosition)
|
||||
?: PointF(0F, 0F)
|
||||
}
|
||||
smoothScroller.targetPosition = position
|
||||
startSmoothScroll(smoothScroller)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
|
||||
tryWithDefaultCatch { super.onLayoutChildren(recycler, state) }
|
||||
}
|
||||
}
|
||||
15
app/src/main/java/com/gh/common/xapk/IXapkUnzipListener.kt
Normal file
15
app/src/main/java/com/gh/common/xapk/IXapkUnzipListener.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.gh.common.xapk
|
||||
|
||||
import com.lightgame.download.DownloadEntity
|
||||
|
||||
interface IXapkUnzipListener {
|
||||
fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long)
|
||||
|
||||
fun onNext(downloadEntity: DownloadEntity, unzipPath: String)
|
||||
|
||||
fun onCancel(downloadEntity: DownloadEntity)
|
||||
|
||||
fun onFailure(downloadEntity: DownloadEntity, exception: Exception)
|
||||
|
||||
fun onSuccess(downloadEntity: DownloadEntity)
|
||||
}
|
||||
175
app/src/main/java/com/gh/common/xapk/XapkInstaller.kt
Normal file
175
app/src/main/java/com/gh/common/xapk/XapkInstaller.kt
Normal file
@ -0,0 +1,175 @@
|
||||
package com.gh.common.xapk
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.util.*
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DataChanger
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.Util_System_Phone_State
|
||||
import com.lightgame.utils.Utils
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 目前已知的Xapk内容是:只有一个apk包和一个或做多个obb数据包(多余文件不解压,如果存在多个apk包,则以下安装无效)
|
||||
*
|
||||
* 每次安装都会重新跑一遍解压安装流程
|
||||
* 目前检验是否已解压的根据是存在相同文件名且大小一致(暂时想不到校验MD5值的方法)
|
||||
*
|
||||
* obb文件直接解压至根目录即可,无需操作文件
|
||||
* apk文件这解压的gh-download文件夹中
|
||||
*/
|
||||
object XapkInstaller : IXapkUnzipListener {
|
||||
private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path"
|
||||
|
||||
// private const val XAPK_DATA_PATH_TAG = "xapk_data_path"
|
||||
const val XAPK_EXTENSION_NAME = "xapk"
|
||||
|
||||
// 通过解压过程存放于 DownloadEntity meta
|
||||
const val XAPK_UNZIP_PERCENT = "unzip_percent"
|
||||
const val XAPK_UNZIP_STATUS = "unzip_status"
|
||||
|
||||
const val XAPK_DATA_EXTENSION_NAME = "obb"
|
||||
const val PACKAGE_EXTENSION_NAME = "apk"
|
||||
|
||||
private var mContext = HaloApp.getInstance().application.applicationContext
|
||||
|
||||
// 是否需要开启特定线程处理
|
||||
private val mXapkUnzipThreadMap = Collections.synchronizedMap(HashMap<String, XapkUnzipThread>())
|
||||
|
||||
// 按并行解压
|
||||
@JvmStatic
|
||||
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean = false) {
|
||||
this.mContext = context
|
||||
|
||||
val filePath = downloadEntity.path
|
||||
if (XAPK_EXTENSION_NAME == filePath.getExtension()) {
|
||||
unzipXapkFile(downloadEntity)
|
||||
if (showUnzipToast) {
|
||||
Utils.toast(mContext, "解压过程请勿退出光环助手!")
|
||||
}
|
||||
} else {
|
||||
throwExceptionInDebug("如果是Apk包请使用PackageInstaller进行安装")
|
||||
PackageInstaller.install(mContext, downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun unzipXapkFile(downloadEntity: DownloadEntity) {
|
||||
if (mXapkUnzipThreadMap[downloadEntity.path] == null) {
|
||||
val xapkUnzipThread = XapkUnzipThread(downloadEntity, this)
|
||||
xapkUnzipThread.start()
|
||||
mXapkUnzipThreadMap[downloadEntity.path] = xapkUnzipThread
|
||||
} else {
|
||||
debugOnly {
|
||||
Utils.log("unzip", "重复解压,该文件解压已在队列中")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long) {
|
||||
AppExecutor.uiExecutor.execute {
|
||||
val df = DecimalFormat("#.0")
|
||||
var percent = 0.0
|
||||
tryCatchInRelease {
|
||||
percent = df.format((unzipProgress / unzipSize.toFloat()) * 100).toDouble()
|
||||
}
|
||||
downloadEntity.meta[XAPK_UNZIP_PERCENT] = percent.toString()
|
||||
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
|
||||
DataChanger.notifyDataChanged(downloadEntity)
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("unzip", "onProgress->" + (unzipProgress / unzipSize.toFloat()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNext(downloadEntity: DownloadEntity, unzipPath: String) {
|
||||
if (PACKAGE_EXTENSION_NAME == unzipPath.getExtension()) {
|
||||
downloadEntity.meta[XAPK_PACKAGE_PATH_TAG] = unzipPath
|
||||
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("unzip", "onNext->$unzipPath")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消解压回调
|
||||
*
|
||||
* 取消后的表现与下载完成一致
|
||||
*/
|
||||
override fun onCancel(downloadEntity: DownloadEntity) {
|
||||
mXapkUnzipThreadMap.remove(downloadEntity.path)
|
||||
|
||||
AppExecutor.uiExecutor.execute {
|
||||
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
|
||||
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
|
||||
DataChanger.notifyDataChanged(downloadEntity)
|
||||
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(downloadEntity: DownloadEntity, exception: Exception) {
|
||||
mXapkUnzipThreadMap.remove(downloadEntity.path)
|
||||
|
||||
AppExecutor.uiExecutor.execute {
|
||||
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
DataChanger.notifyDataChanged(downloadEntity)
|
||||
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
|
||||
MtaHelper.onEvent("解压失败"
|
||||
, "安卓版本", Build.VERSION.RELEASE
|
||||
, "IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
|
||||
, "光环版本", BuildConfig.VERSION_NAME
|
||||
, "厂商", Build.MANUFACTURER
|
||||
, "机型", Build.MODEL
|
||||
, "游戏", downloadEntity.name
|
||||
, "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
|
||||
|
||||
debugOnly {
|
||||
Utils.log("unzip", "onFailure->$exception")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(downloadEntity: DownloadEntity) {
|
||||
mXapkUnzipThreadMap.remove(downloadEntity.path)
|
||||
|
||||
AppExecutor.uiExecutor.execute {
|
||||
val pkgPath = checkNotNull(downloadEntity.meta[XAPK_PACKAGE_PATH_TAG])
|
||||
PackageInstaller.install(mContext, pkgPath)
|
||||
|
||||
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
|
||||
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
|
||||
DataChanger.notifyDataChanged(downloadEntity)
|
||||
DownloadManager.getInstance(mContext).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
|
||||
debugOnly {
|
||||
Utils.log("unzip", "onSuccess->${downloadEntity.path}")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun cancelUnzipTask(downloadEntity: DownloadEntity) {
|
||||
val xapkUnzipThread = mXapkUnzipThreadMap[downloadEntity.path]
|
||||
if (xapkUnzipThread != null) {
|
||||
xapkUnzipThread.canceled = true
|
||||
} else {
|
||||
onCancel(downloadEntity) // 刷新页面
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class XapkUnzipStatus(status: String) {
|
||||
UNZIPPING("unzipping"),
|
||||
SUCCESS("success"),
|
||||
CANCEL("cancel"),
|
||||
FAILURE("failure");
|
||||
}
|
||||
211
app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt
Normal file
211
app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt
Normal file
@ -0,0 +1,211 @@
|
||||
package com.gh.common.xapk
|
||||
|
||||
import android.os.Environment
|
||||
import com.gh.common.util.getExtension
|
||||
import com.gh.common.util.throwException
|
||||
import com.gh.common.util.throwExceptionInDebug
|
||||
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 net.lingala.zip4j.progress.ProgressMonitor
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
|
||||
class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
|
||||
private var mUnzipListener: IXapkUnzipListener) : Thread() {
|
||||
|
||||
private val mDefaultBufferSize = 1024 * 1024
|
||||
|
||||
var canceled = false
|
||||
|
||||
override fun run() {
|
||||
super.run()
|
||||
try {
|
||||
val path = mDownloadEntity.path
|
||||
var unzipSize = 0L
|
||||
try {
|
||||
unzipSize = getUnzipSize(path)
|
||||
} catch (e: Exception) {
|
||||
planB()
|
||||
return
|
||||
}
|
||||
|
||||
val msg = FileUtils.isCanDownload(HaloApp.getInstance().application, unzipSize)
|
||||
if (!msg.isNullOrEmpty()) {
|
||||
// 空间不足应该不用刷新页面,保持不变就好
|
||||
Utils.toast(HaloApp.getInstance().application, "设备存储空间不足,请清理后重试!")
|
||||
mUnzipListener.onCancel(mDownloadEntity)
|
||||
return
|
||||
}
|
||||
var unzipProgress = 0L
|
||||
val absolutePath = Environment.getExternalStorageDirectory().absolutePath
|
||||
val xapkFile = File(path)
|
||||
|
||||
ZipFile(xapkFile).use { zip ->
|
||||
for (zipEntry in zip.entries().asSequence()) {
|
||||
val outputFile = if (zipEntry.name.getExtension() == XapkInstaller.XAPK_DATA_EXTENSION_NAME) {
|
||||
File(absolutePath + File.separator + zipEntry.name)
|
||||
} else if (zipEntry.name.getExtension() == XapkInstaller.PACKAGE_EXTENSION_NAME) {
|
||||
// apk文件名称 = xapk文件名+本身的文件名称
|
||||
val fileName = xapkFile.nameWithoutExtension + "_" + zipEntry.name
|
||||
File(FileUtils.getDownloadPath(HaloApp.getInstance().application, fileName))
|
||||
} else continue // 暂时只需要解压xpk/obb文件
|
||||
|
||||
if (zipEntry.isDirectory) {
|
||||
if (!outputFile.exists()) {
|
||||
throwException("unzip create file path failure", !outputFile.mkdirs())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (!outputFile.parentFile.exists()) {
|
||||
throwException("unzip create file path failure", !outputFile.parentFile.mkdirs())
|
||||
}
|
||||
|
||||
// 如果存在同名且大小一致,可以认为该文件已经解压缩(在不解压缩的情况下如果如果获取压缩文件的MD5????)
|
||||
if (!outputFile.exists()) {
|
||||
throwException("unzip create file failure", !outputFile.createNewFile())
|
||||
} else if (outputFile.length() != zipEntry.size) {
|
||||
throwException("unzip delete existing file failure", !outputFile.delete())
|
||||
throwException("unzip create file failure", !outputFile.createNewFile())
|
||||
} else {
|
||||
unzipProgress += zipEntry.size
|
||||
mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipSize, unzipProgress)
|
||||
mUnzipListener.onNext(mDownloadEntity, outputFile.path)
|
||||
continue
|
||||
}
|
||||
|
||||
// unzip
|
||||
zip.getInputStream(zipEntry).use { input ->
|
||||
outputFile.outputStream().use { output ->
|
||||
val buffer = ByteArray(mDefaultBufferSize)
|
||||
var bytes = input.read(buffer)
|
||||
while (bytes >= 0) {
|
||||
output.write(buffer, 0, bytes)
|
||||
unzipProgress += bytes
|
||||
bytes = input.read(buffer)
|
||||
if (canceled) {
|
||||
mUnzipListener.onCancel(mDownloadEntity)
|
||||
return
|
||||
} else {
|
||||
mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipSize, unzipProgress)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mUnzipListener.onNext(mDownloadEntity, outputFile.path)
|
||||
}
|
||||
}
|
||||
mUnzipListener.onSuccess(mDownloadEntity)
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) throw e
|
||||
mUnzipListener.onFailure(mDownloadEntity, e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 部分未知情况(有可能是项目配置问题,有可能时Zip包破损)原生的ZipFile无法打开压缩包,则启动以下备用方案
|
||||
* 具体复现机型:小米 9(Android 9)
|
||||
* 具体复现的压缩包:太空竞速2 具体可以咨询陈思雨
|
||||
*
|
||||
* 实现方式请参考:https://github.com/srikanth-lingala/zip4j
|
||||
* 注意使用该库的ZipInputStream依然无法解压,提示头文件丢失
|
||||
*
|
||||
* 后续如果有需要可以直接使用该方法进行解压
|
||||
*/
|
||||
private fun planB() {
|
||||
val zipPath = mDownloadEntity.path
|
||||
|
||||
val absolutePath = Environment.getExternalStorageDirectory().absolutePath
|
||||
|
||||
val zipFile = net.lingala.zip4j.ZipFile(zipPath)
|
||||
val progressMonitor = zipFile.progressMonitor
|
||||
zipFile.isRunInThread = true
|
||||
|
||||
val fileHeaders = zipFile.fileHeaders
|
||||
var unzipSize = 0L
|
||||
for (fileHeader in fileHeaders) {
|
||||
unzipSize += fileHeader.uncompressedSize;
|
||||
}
|
||||
|
||||
var unzipProgress = 0L
|
||||
var completedSize = 0L
|
||||
|
||||
for (fileHeader in fileHeaders) {
|
||||
if (canceled) {
|
||||
mUnzipListener.onCancel(mDownloadEntity)
|
||||
return
|
||||
}
|
||||
|
||||
// 暂时只需要解压xpk/obb文件
|
||||
val extension = fileHeader.fileName.getExtension()
|
||||
if (extension != XapkInstaller.XAPK_DATA_EXTENSION_NAME && extension != XapkInstaller.PACKAGE_EXTENSION_NAME) continue
|
||||
|
||||
|
||||
var unzipPath = ""
|
||||
if (extension == XapkInstaller.XAPK_DATA_EXTENSION_NAME) {
|
||||
unzipPath = absolutePath + File.separator + fileHeader.fileName
|
||||
|
||||
if (hasUnzipFile(unzipPath, fileHeader.uncompressedSize)) {
|
||||
mUnzipListener.onNext(mDownloadEntity, unzipPath)
|
||||
continue
|
||||
}
|
||||
|
||||
zipFile.extractFile(fileHeader.fileName, absolutePath)
|
||||
}
|
||||
|
||||
if (extension == XapkInstaller.PACKAGE_EXTENSION_NAME) {
|
||||
val downloadDir = FileUtils.getDownloadDir(HaloApp.getInstance().application)
|
||||
val unzipFileName = File(zipPath).nameWithoutExtension + "_" + fileHeader.fileName
|
||||
unzipPath = downloadDir + File.separator + unzipFileName
|
||||
|
||||
if (hasUnzipFile(unzipPath, fileHeader.uncompressedSize)) {
|
||||
mUnzipListener.onNext(mDownloadEntity, unzipPath)
|
||||
continue
|
||||
}
|
||||
|
||||
zipFile.extractFile(fileHeader.fileName, downloadDir, unzipFileName)
|
||||
}
|
||||
|
||||
throwExceptionInDebug("check unzipPath", unzipPath.isEmpty())
|
||||
|
||||
// 回调太频繁了,变态吗? 4K回调一次,还不能改,FUCK
|
||||
var filterCounter = 0
|
||||
val filterInterval = 1024 * 10
|
||||
while (progressMonitor.state != ProgressMonitor.State.READY) {
|
||||
filterCounter++
|
||||
if (filterCounter % filterInterval == 0) {
|
||||
unzipProgress = completedSize + progressMonitor.workCompleted
|
||||
mUnzipListener.onProgress(mDownloadEntity, unzipPath, unzipSize, unzipProgress)
|
||||
|
||||
if (canceled) {
|
||||
progressMonitor.isCancelAllTasks = true
|
||||
mUnzipListener.onCancel(mDownloadEntity)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
completedSize += fileHeader.uncompressedSize
|
||||
mUnzipListener.onNext(mDownloadEntity, unzipPath)
|
||||
}
|
||||
|
||||
mUnzipListener.onSuccess(mDownloadEntity)
|
||||
}
|
||||
|
||||
private fun hasUnzipFile(unzipPath: String, uncompressedSize: Long): Boolean {
|
||||
val unzipFile = File(unzipPath)
|
||||
if (unzipFile.exists() || unzipFile.length() == uncompressedSize) return true
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getUnzipSize(path: String): Long {
|
||||
var totalSize = 0L
|
||||
for (entry in ZipFile(File(path)).entries()) {
|
||||
totalSize += entry.size
|
||||
}
|
||||
return totalSize
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,21 @@
|
||||
package com.gh.download
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import com.gh.common.exposure.meta.MetaUtil.getMeta
|
||||
import com.gh.common.loghub.LoghubUtils
|
||||
import com.gh.common.util.DeviceUtils
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
object DownloadDataHelper {
|
||||
private const val DOWNLOAD_SPEED_TIME = "download_speed_time"
|
||||
private const val DOWNLOAD_SPEED_SIZE = "download_speed_size"
|
||||
|
||||
const val DOWNLOAD_RESUME_WAY = "download_resume_way"
|
||||
const val DOWNLOAD_RESUME_MANUAL = "manual"
|
||||
const val DOWNLOAD_RESUME_AUTO = "auto"
|
||||
@ -14,9 +24,16 @@ object DownloadDataHelper {
|
||||
const val DOWNLOAD_CANCEL_MANUAL = "manual"
|
||||
const val DOWNLOAD_CANCEL_AUTO = "auto"
|
||||
|
||||
const val DOWNLOAD_FIRST_START = "download_first_start"
|
||||
|
||||
private val mDownloadSpeedMap = HashMap<String, MutableList<Long>>()
|
||||
|
||||
private val mDownloadHeartbeatList = mutableListOf<JSONObject>()
|
||||
private val mDownloadHeartbeatSheet = HashMap<String, JSONObject>()
|
||||
|
||||
@JvmStatic
|
||||
fun getDownloadStatusAlias(downloadEntity: DownloadEntity): String {
|
||||
val status = downloadEntity.status
|
||||
fun getDownloadStatusAlias(downloadEntity: DownloadEntity, downloadStatus: DownloadStatus? = null): String {
|
||||
val status = downloadStatus ?: downloadEntity.status
|
||||
return if (status == DownloadStatus.add) {
|
||||
"开始下载"
|
||||
} else if (status == DownloadStatus.pause) {
|
||||
@ -53,4 +70,236 @@ object DownloadDataHelper {
|
||||
"未知状态"
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun uploadDownloadEvent(downloadEntity: DownloadEntity) {
|
||||
if (downloadEntity.status != DownloadStatus.downloading) {
|
||||
uploadDownloadStatusEvent(downloadEntity)
|
||||
}
|
||||
|
||||
if (downloadEntity.status == DownloadStatus.downloading) {
|
||||
val startupTime = downloadEntity.meta[DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY]
|
||||
if (startupTime != null) {
|
||||
uploadDownloadStartupTimeEvent(downloadEntity, startupTime.toInt())
|
||||
downloadEntity.meta.remove(DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY)
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadEntity.status == DownloadStatus.downloading || downloadEntity.status == DownloadStatus.done) {
|
||||
val time = downloadEntity.meta[DOWNLOAD_SPEED_TIME]
|
||||
val size = downloadEntity.meta[DOWNLOAD_SPEED_SIZE]
|
||||
if (downloadEntity.speed == 0L || time == null || size == null) {
|
||||
downloadEntity.meta[DOWNLOAD_SPEED_TIME] = System.currentTimeMillis().toString()
|
||||
downloadEntity.meta[DOWNLOAD_SPEED_SIZE] = downloadEntity.progress.toString()
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).updateDownloadEntity(downloadEntity)
|
||||
} else {
|
||||
val offset = System.currentTimeMillis() - time.toLong()
|
||||
if (offset > 5000) {
|
||||
//记录并重置
|
||||
val downloadedSize = downloadEntity.progress - size.toLong()
|
||||
val averageSpeed = downloadedSize / offset
|
||||
val speedList = mDownloadSpeedMap[downloadEntity.url]
|
||||
if (speedList == null) {
|
||||
mDownloadSpeedMap[downloadEntity.url] = arrayListOf(averageSpeed)
|
||||
} else {
|
||||
speedList.add(averageSpeed)
|
||||
if (speedList.size >= 6 || downloadEntity.status == DownloadStatus.done) {
|
||||
uploadDownloadAverageSpeed(downloadEntity, speedList)
|
||||
if (downloadEntity.status == DownloadStatus.done) {
|
||||
mDownloadSpeedMap.remove(downloadEntity.url)
|
||||
} else {
|
||||
speedList.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
downloadEntity.meta[DOWNLOAD_SPEED_TIME] = System.currentTimeMillis().toString()
|
||||
downloadEntity.meta[DOWNLOAD_SPEED_SIZE] = downloadEntity.progress.toString()
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadDownloadStartupTimeEvent(downloadEntity: DownloadEntity, startupTime: Int) {
|
||||
val jsonObject = JSONObject()
|
||||
|
||||
try {
|
||||
jsonObject.put("event", "下载线程启动")
|
||||
val startupStatus = downloadEntity.meta[DownloadEntity.DOWNLOAD_STARTUP_STATUS_KEY]
|
||||
if (startupStatus != null) {
|
||||
jsonObject.put("msg", getDownloadStatusAlias(downloadEntity, DownloadStatus.valueOf(startupStatus)))
|
||||
}
|
||||
|
||||
jsonObject.put("meta", getMetaJson())
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
|
||||
// payload
|
||||
val payloadObject = JSONObject()
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
payloadObject.put("package", downloadEntity.packageName)
|
||||
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
|
||||
payloadObject.put("launch_ms", startupTime)
|
||||
jsonObject.put("payload", payloadObject)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->$jsonObject")
|
||||
}
|
||||
LoghubUtils.log(jsonObject, "download_debug", false)
|
||||
}
|
||||
|
||||
private fun uploadDownloadStatusEvent(downloadEntity: DownloadEntity) {
|
||||
val jsonObject = JSONObject()
|
||||
|
||||
try {
|
||||
jsonObject.put("event", getDownloadStatusAlias(downloadEntity))
|
||||
jsonObject.put("msg", downloadEntity.error)
|
||||
jsonObject.put("status", downloadEntity.status.status)
|
||||
|
||||
jsonObject.put("meta", getMetaJson())
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
|
||||
// payload
|
||||
val payloadObject = JSONObject()
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
payloadObject.put("package", downloadEntity.packageName)
|
||||
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
|
||||
payloadObject.put("total_size", downloadEntity.size / 1024 / 1024)
|
||||
payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
|
||||
if (downloadEntity.status == DownloadStatus.resume) {
|
||||
if (downloadEntity.meta[DOWNLOAD_FIRST_START] == "YES") {
|
||||
payloadObject.put("is_first_start", true)
|
||||
} else {
|
||||
payloadObject.put("is_first_start", false)
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadEntity.status == DownloadStatus.resume || downloadEntity.status == DownloadStatus.add) {
|
||||
downloadEntity.meta[DOWNLOAD_FIRST_START] = "NO"
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
jsonObject.put("payload", payloadObject)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->$jsonObject")
|
||||
}
|
||||
LoghubUtils.log(jsonObject, "download_debug", false)
|
||||
}
|
||||
|
||||
|
||||
private fun uploadDownloadAverageSpeed(downloadEntity: DownloadEntity, averageSpeedList: List<Long>) {
|
||||
val jsonObject = JSONObject()
|
||||
|
||||
try {
|
||||
jsonObject.put("event", "下载进度")
|
||||
jsonObject.put("msg", "")
|
||||
|
||||
jsonObject.put("meta", getMetaJson())
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
|
||||
// payload
|
||||
val payloadObject = JSONObject()
|
||||
payloadObject.put("game_id", downloadEntity.gameId)
|
||||
payloadObject.put("gameName", downloadEntity.name)
|
||||
payloadObject.put("platform", downloadEntity.platform)
|
||||
payloadObject.put("package", downloadEntity.packageName)
|
||||
payloadObject.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
|
||||
payloadObject.put("speed_progress", JSONArray(averageSpeedList))
|
||||
payloadObject.put("is_finished", downloadEntity.status == DownloadStatus.done)
|
||||
jsonObject.put("payload", payloadObject)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->$jsonObject")
|
||||
}
|
||||
LoghubUtils.log(jsonObject, "download_debug", false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 分片检测下载进度,每隔15秒内记录一次,60秒上传一次
|
||||
*
|
||||
* 请见:https://gitlab.ghzs.com/stats/stats-issues/-/issues/188#note_66919
|
||||
*/
|
||||
fun uploadDownloadHeartbeat(upload: Boolean) {
|
||||
val allDownloadEntity = DownloadManager.getInstance(HaloApp.getInstance().application).allDownloadEntity
|
||||
for (downloadEntity in allDownloadEntity) {
|
||||
if (downloadEntity.status == DownloadStatus.downloading) {
|
||||
var sheet = mDownloadHeartbeatSheet[downloadEntity.url]
|
||||
if (sheet == null) {
|
||||
sheet = JSONObject()
|
||||
val host = downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown"
|
||||
sheet.put("host", host)
|
||||
sheet.put("game_id", downloadEntity.gameId)
|
||||
sheet.put("platform", downloadEntity.platform)
|
||||
sheet.put("package", downloadEntity.packageName)
|
||||
sheet.put("filename", downloadEntity.path.substring(downloadEntity.path.lastIndexOf("/") + 1))
|
||||
sheet.put("total_size", downloadEntity.size / 1024 / 1024)
|
||||
sheet.put("current_progress_size", downloadEntity.progress / 1024)
|
||||
mDownloadHeartbeatSheet[downloadEntity.url] = sheet
|
||||
} else {
|
||||
val progressSize = sheet.getLong("current_progress_size")
|
||||
sheet.put("total_size", downloadEntity.size / 1024 / 1024) // 初始化记录的 total_size 有可能为0
|
||||
sheet.put("progress_size", downloadEntity.progress / 1024 - progressSize)
|
||||
sheet.put("current_progress_size", downloadEntity.progress / 1024)
|
||||
mDownloadHeartbeatList.add(JSONObject(sheet.toString()))
|
||||
}
|
||||
} else {
|
||||
mDownloadHeartbeatSheet.remove(downloadEntity.url)
|
||||
}
|
||||
}
|
||||
|
||||
if (upload && mDownloadHeartbeatList.isNotEmpty()) {
|
||||
val jsonObject = JSONObject()
|
||||
try {
|
||||
jsonObject.put("event", "progress")
|
||||
jsonObject.put("meta", getMetaJson())
|
||||
jsonObject.put("timestamp", System.currentTimeMillis() / 1000)
|
||||
|
||||
val payloads = JSONArray()
|
||||
for (heartbeatData in mDownloadHeartbeatList) {
|
||||
heartbeatData.remove("current_progress_size")
|
||||
payloads.put(heartbeatData)
|
||||
}
|
||||
jsonObject.put("payloads", payloads)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("LogUtils->$jsonObject")
|
||||
}
|
||||
mDownloadHeartbeatList.clear()
|
||||
LoghubUtils.log(jsonObject, "download_debug", false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMetaJson(): JSONObject {
|
||||
val context = HaloApp.getInstance().application
|
||||
val meta = getMeta()
|
||||
// meta
|
||||
val metaObject = JSONObject()
|
||||
metaObject.put("android_id", meta.android_id)
|
||||
metaObject.put("android_sdk", meta.android_sdk)
|
||||
metaObject.put("android_version", meta.android_version)
|
||||
metaObject.put("appVersion", meta.appVersion)
|
||||
metaObject.put("channel", meta.channel)
|
||||
metaObject.put("gid", meta.gid)
|
||||
metaObject.put("imei", meta.imei)
|
||||
metaObject.put("mac", meta.mac)
|
||||
metaObject.put("manufacturer", meta.manufacturer)
|
||||
metaObject.put("model", meta.model)
|
||||
metaObject.put("network", DeviceUtils.getNetwork(context))
|
||||
metaObject.put("os", meta.os)
|
||||
metaObject.put("MNC", DeviceUtils.getTelephonySubscriberId(context) ?: "")
|
||||
metaObject.put("userId", meta.userId)
|
||||
return metaObject
|
||||
}
|
||||
}
|
||||
@ -11,10 +11,9 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
@ -22,10 +21,11 @@ import com.gh.common.util.AppDebugConfig;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DeviceUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.GdtHelper;
|
||||
import com.gh.common.util.HomePluggableHelper;
|
||||
import com.gh.common.util.MD5Utils;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.SPUtils;
|
||||
import com.gh.gamecenter.entity.ApkEntity;
|
||||
@ -186,7 +186,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
}
|
||||
};
|
||||
|
||||
List<DownloadEntity> list = getAll();
|
||||
List<DownloadEntity> list = getAllDownloadEntity();
|
||||
for (DownloadEntity downloadEntity : list) {
|
||||
statusMap.put(downloadEntity.getUrl(), downloadEntity.getStatus());
|
||||
if (!DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
@ -243,8 +243,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
DownloadEntity downloadEntity = new DownloadEntity();
|
||||
downloadEntity.setUrl(apkEntity.getUrl());
|
||||
downloadEntity.setName(gameEntity.getName());
|
||||
downloadEntity.setPath(FileUtils.getDownloadPath(context,
|
||||
MD5Utils.getContentMD5(gameEntity.getName() + "_" + System.currentTimeMillis()) + ".apk"));
|
||||
downloadEntity.setPath(PackageInstaller.getDownloadPath(gameEntity.getName(), apkEntity.getFormat()));
|
||||
downloadEntity.setETag(apkEntity.getEtag());
|
||||
downloadEntity.setIcon(gameEntity.getIcon());
|
||||
downloadEntity.setPlatform(apkEntity.getPlatform());
|
||||
@ -253,6 +252,8 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
downloadEntity.setEntrance(entrance);
|
||||
downloadEntity.setLocation(location);
|
||||
downloadEntity.setVersionName(apkEntity.getVersion());
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.RAW_GAME_ICON, gameEntity.getRawIcon());
|
||||
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_SUBSCRIPT, gameEntity.getIconSubscript());
|
||||
int installed = 0;
|
||||
for (ApkEntity apk : gameEntity.getApk()) {
|
||||
if (PackagesManager.INSTANCE.isInstalled(apk.getPackageName())) {
|
||||
@ -475,7 +476,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
public void initGameMap() {
|
||||
gameMap.clear();
|
||||
List<DownloadEntity> list = getAll();
|
||||
List<DownloadEntity> list = getAllDownloadEntity();
|
||||
if (list != null && list.size() != 0) {
|
||||
String name;
|
||||
for (DownloadEntity downloadEntity : list) {
|
||||
@ -492,11 +493,9 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
/**
|
||||
* 获取所有下载列表中的任务
|
||||
*
|
||||
* @return null表示没有下载任务
|
||||
*/
|
||||
@NonNull
|
||||
public List<DownloadEntity> getAll() {
|
||||
public List<DownloadEntity> getAllDownloadEntity() {
|
||||
if (CommonDebug.IS_DEBUG) {
|
||||
CommonDebug.logMethodName(this);
|
||||
}
|
||||
@ -504,6 +503,31 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
return all != null ? all : new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有下载列表中的任务排除静默更新
|
||||
*/
|
||||
public List<DownloadEntity> getAllDownloadEntityExcludeSilentUpdate() {
|
||||
if (CommonDebug.IS_DEBUG) {
|
||||
CommonDebug.logMethodName(this);
|
||||
}
|
||||
List<DownloadEntity> all = mDownloadDao.getAll();
|
||||
return filterSilentDownloadTask(all);
|
||||
}
|
||||
|
||||
private ArrayList<DownloadEntity> filterSilentDownloadTask(List<DownloadEntity> downloadEntityList) {
|
||||
ArrayList<DownloadEntity> filteredDownloadEntityList = new ArrayList<>();
|
||||
|
||||
if (downloadEntityList == null) return filteredDownloadEntityList;
|
||||
|
||||
for (DownloadEntity downloadEntity : downloadEntityList) {
|
||||
if (!Constants.SILENT_UPDATE.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE))) {
|
||||
filteredDownloadEntityList.add(downloadEntity);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredDownloadEntityList;
|
||||
}
|
||||
|
||||
public ArrayMap<String, DownloadEntity> getEntryMap(String name) {
|
||||
return gameMap.get(name);
|
||||
}
|
||||
@ -621,7 +645,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
*/
|
||||
public void initDownloadService() {
|
||||
final List<String> urlList = new ArrayList<>(DataChanger.INSTANCE.getDownloadingTasks().keySet());
|
||||
for (DownloadEntity downloadEntity : getAll()) {
|
||||
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
|
||||
if (!urlList.contains(downloadEntity.getUrl()) &&
|
||||
(downloadEntity.getStatus().equals(DownloadStatus.downloading)
|
||||
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
|
||||
@ -645,13 +669,11 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
DataChanger.INSTANCE.deleteObserver(dataWatcher);
|
||||
}
|
||||
|
||||
private void startDownloadService() {
|
||||
public void startDownloadService() {
|
||||
Intent serviceIntent = new Intent(mContext, DownloadService.class);
|
||||
// 当满足系统版本大于 8.0 并且进程处于 CREATED 状态 (ON_STOP后的状态) 的时候才以前台服务开启
|
||||
// "not allowed to start service, app is in background" 的错误概率比 "startForegroundService() did not then call Service.startForeground() " 低
|
||||
// 所以还是老老实实地以 startService 为主吧
|
||||
// 当满足系统版本大于 8.0 并且应用在后台运行时以前台服务开启
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
|
||||
&& !PackageUtils.isAppOnForeground(mContext)) {
|
||||
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
|
||||
mContext.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
@ -671,10 +693,16 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
downloadEntity.getMeta().put(DownloadEntity.NETWORK_STATUS_KEY, network);
|
||||
}
|
||||
|
||||
if (status == DownloadStatus.add || status == DownloadStatus.subscribe) {
|
||||
if (downloadEntity.getMeta().get(DownloadDataHelper.DOWNLOAD_FIRST_START) == null) {
|
||||
downloadEntity.getMeta().put(DownloadDataHelper.DOWNLOAD_FIRST_START, "YES");
|
||||
}
|
||||
}
|
||||
|
||||
Intent serviceIntent = getIntent(downloadEntity, status);
|
||||
// 当满足系统版本大于 8.0 、应用在后台运行时以前台服务开启
|
||||
// 当满足系统版本大于 8.0 并且应用在后台运行时以前台服务开启
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
|
||||
&& !PackageUtils.isAppOnForeground(mContext)) {
|
||||
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
|
||||
mContext.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
@ -685,7 +713,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
public void checkRetryDownload() {
|
||||
if (!NetworkUtils.isWifiConnected(mContext)) return;
|
||||
|
||||
for (DownloadEntity downloadEntity : DownloadManager.getInstance(mContext).getAll()) {
|
||||
for (DownloadEntity downloadEntity : DownloadManager.getInstance(mContext).getAllDownloadEntityExcludeSilentUpdate()) {
|
||||
if (DownloadStatus.neterror.equals(downloadEntity.getStatus()) ||
|
||||
DownloadStatus.timeout.equals(downloadEntity.getStatus()) ||
|
||||
DownloadStatus.subscribe.equals(downloadEntity.getStatus())) {
|
||||
@ -709,7 +737,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
boolean showRedPoint = false;
|
||||
int downloadingSize = 0;
|
||||
|
||||
for (DownloadEntity downloadEntity : getAll()) {
|
||||
for (DownloadEntity downloadEntity : getAllDownloadEntityExcludeSilentUpdate()) {
|
||||
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
|
||||
if (TextUtils.isEmpty(mark)) showRedPoint = true;
|
||||
@ -767,7 +795,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
}
|
||||
|
||||
public boolean isContainsUnreadDownloadedTask() {
|
||||
for (DownloadEntity downloadEntity : getAll()) {
|
||||
for (DownloadEntity downloadEntity : getAllDownloadEntityExcludeSilentUpdate()) {
|
||||
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
|
||||
if (TextUtils.isEmpty(mark)) {
|
||||
@ -785,7 +813,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
List<DownloadEntity> all = getAll();
|
||||
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentUpdate();
|
||||
for (DownloadEntity downloadEntity : all) {
|
||||
DownloadStatus status = downloadEntity.getStatus();
|
||||
if (status == DownloadStatus.done) {
|
||||
@ -825,7 +853,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
List<DownloadEntity> all = getAll();
|
||||
List<DownloadEntity> all = getAllDownloadEntityExcludeSilentUpdate();
|
||||
for (DownloadEntity downloadEntity : all) {
|
||||
if (downloadEntity.getStatus() != DownloadStatus.done) {
|
||||
if (isRead) {
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.download
|
||||
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object DownloadWorkManager {
|
||||
@ -22,12 +23,13 @@ object DownloadWorkManager {
|
||||
.addTag(TAG_DOWNLOAD)
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance().enqueue(workerRequest)
|
||||
// TODO 某些特殊场景下会出现 WorkManagerImpl.getInstance() 为空的情况,下版本更新 WorkManager
|
||||
tryWithDefaultCatch { WorkManager.getInstance().enqueue(workerRequest) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun cancelWorker() {
|
||||
WorkManager.getInstance().cancelAllWorkByTag(TAG_DOWNLOAD)
|
||||
tryWithDefaultCatch { WorkManager.getInstance().cancelAllWorkByTag(TAG_DOWNLOAD) }
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user