Compare commits
271 Commits
v3.7.2-bug
...
v3.7.4-bug
| Author | SHA1 | Date | |
|---|---|---|---|
| 82a859e820 | |||
| c7db58f6ea | |||
| 79ff887375 | |||
| 4f68f30576 | |||
| 0683a579c0 | |||
| f1194d434b | |||
| 59e80970ae | |||
| 92a0d77885 | |||
| 1bc0b0e085 | |||
| a5129c809b | |||
| 3e8e5572d2 | |||
| 862b66f8e7 | |||
| 15fad5635b | |||
| bddde8c851 | |||
| b589c38eea | |||
| 5c3cdf227e | |||
| 838b775a3e | |||
| 7af2b7c2d7 | |||
| f78570ce80 | |||
| 071376267a | |||
| 51c3d25f3a | |||
| cc6c31027a | |||
| f3b91b63ec | |||
| 48b8c0d23e | |||
| c56826b29d | |||
| 28ec3ef5dc | |||
| c3b8538ac3 | |||
| f04b1c4300 | |||
| 1d7c8b894f | |||
| afd1232cea | |||
| 2b141e79cd | |||
| f6e452237a | |||
| 508dff3bae | |||
| 1259199e2c | |||
| 85fc2dda02 | |||
| d57a6879fb | |||
| c0f32124ad | |||
| b3a53f51b0 | |||
| 66175c7f20 | |||
| dc698ca2cc | |||
| 6d8c703f33 | |||
| f32e6b60d1 | |||
| f45d1ded17 | |||
| da9eac4ecd | |||
| b58d52709f | |||
| 3cde5cc39d | |||
| 50214e7461 | |||
| dc0994d084 | |||
| f79a45e533 | |||
| b704e47322 | |||
| dab9f850ba | |||
| e7073bf010 | |||
| c1ab9617ad | |||
| c6d9026333 | |||
| 42dae5c993 | |||
| a3af3dcf9b | |||
| ba15462981 | |||
| c29066eb46 | |||
| 0464a859d2 | |||
| 962ff89833 | |||
| 74a40ebe97 | |||
| 686b454abe | |||
| 6d54ddea60 | |||
| d005403f65 | |||
| 8e907f5221 | |||
| 96bb953d9d | |||
| 78b581b376 | |||
| ef7edb4a9e | |||
| 4bf5ae40e2 | |||
| 22ebdc0e87 | |||
| 01bd1628cf | |||
| 7de88bc8ad | |||
| 1a01e2dd4d | |||
| 9e20c7082a | |||
| 74cb2f253b | |||
| cf41d2e4a7 | |||
| f232adaa98 | |||
| 713af4bf12 | |||
| f0f1906ffc | |||
| 3da6444ede | |||
| f149c56617 | |||
| 9915a18656 | |||
| 2173e5a91c | |||
| 4a6866d8fd | |||
| ddc324bcf1 | |||
| daba7e0d12 | |||
| 6203b80c4e | |||
| 416cbe7e82 | |||
| e28ce4d099 | |||
| d1f5ec6c2e | |||
| 166f44bb1d | |||
| c8a0420b21 | |||
| a3d7d9cb81 | |||
| b6d49c88db | |||
| 8572f8eaf4 | |||
| c533cd021f | |||
| 3eb1af7e23 | |||
| 97188a7d9c | |||
| e29ffa3d13 | |||
| 5b772a0537 | |||
| 82a8888676 | |||
| bf8630756a | |||
| 35fc381162 | |||
| f72342ac72 | |||
| 5a6e528c65 | |||
| 4eb52c91a4 | |||
| 77bc1594aa | |||
| 23267ec0ee | |||
| 1b1bd3264a | |||
| b954c1f664 | |||
| 707beb9672 | |||
| b2f5a19bde | |||
| e24d7f1045 | |||
| 142a64d261 | |||
| 2ef98fd050 | |||
| 2f3c387c16 | |||
| 83b97a9de9 | |||
| 97becbea2e | |||
| 8361609c70 | |||
| eb7d871e70 | |||
| d06ab34db1 | |||
| d59f604c7e | |||
| a8d9bb9180 | |||
| db90717617 | |||
| f916c7b8a5 | |||
| 4e410e3ea3 | |||
| 5a5fb7a5cc | |||
| 233a2172f1 | |||
| 6376973a61 | |||
| 5dd6d73603 | |||
| 5918b35793 | |||
| 10c3536b2b | |||
| fffef74480 | |||
| c5c2938089 | |||
| 32fe28f536 | |||
| fc4a751b2b | |||
| e364b7d3b0 | |||
| bc28e08b3f | |||
| 69b8155dcd | |||
| 16254bb578 | |||
| acc4a5b2aa | |||
| fddce1ebe3 | |||
| 7151cba40e | |||
| 6cff45eada | |||
| a05b4f7b65 | |||
| e5797a41b7 | |||
| 9f0191ce0a | |||
| 68a5c472c0 | |||
| 6c7e6d95ce | |||
| ec84bbb4f3 | |||
| 780a8649e3 | |||
| 9aaaf2204a | |||
| c7f608b9cb | |||
| 591885095b | |||
| 3bcdd37837 | |||
| 959c5e4cf5 | |||
| 7ecc8446ea | |||
| d3809bb699 | |||
| d5113a52fc | |||
| e2dd868705 | |||
| 41ae5b9b6b | |||
| b0470b3a41 | |||
| d371ae9dc5 | |||
| 00124a657d | |||
| 620cec08eb | |||
| b1205356c8 | |||
| e96d6829a4 | |||
| 0652da2300 | |||
| ebe3852132 | |||
| 1ae73277a9 | |||
| 97ec50f8a9 | |||
| 1997a8b296 | |||
| baae0e5bca | |||
| 4136bfab42 | |||
| 3d64d3c90e | |||
| 7d2835bb83 | |||
| 9ffaa97d70 | |||
| 363751a970 | |||
| c7218d9c0d | |||
| e9387e29c6 | |||
| 33b4d60882 | |||
| 86537b8f1e | |||
| c2e64e2a71 | |||
| 79af4945e3 | |||
| f83a50d4c5 | |||
| 1868488390 | |||
| 4dc71d2d76 | |||
| dca5565f45 | |||
| aa6294bfd4 | |||
| 77a6d3f295 | |||
| 10fd6d9aef | |||
| 37e6120768 | |||
| b9defd4a58 | |||
| 7f7938fdfa | |||
| 7c2f411a48 | |||
| 51c152ca5e | |||
| dc46ee4431 | |||
| da3ba76547 | |||
| 36a31f28f0 | |||
| 450a732f2e | |||
| b8c5dcf4b4 | |||
| 8ae5eacffe | |||
| bb9f7a33fb | |||
| 06f603e975 | |||
| 20c74a1727 | |||
| 5dd3ba43c9 | |||
| cd749fc1c9 | |||
| 6b7610bac8 | |||
| 041f48bdb5 | |||
| a1adfb336b | |||
| 35ff5af974 | |||
| 638f324cd2 | |||
| 62390f88e5 | |||
| 9428604613 | |||
| 610fc444af | |||
| e5d7b68a85 | |||
| 9e91a53e94 | |||
| fa553238bb | |||
| 0a579427f4 | |||
| 921bc29f73 | |||
| 2864fa0d91 | |||
| 9771fb7f25 | |||
| ec5bf05d42 | |||
| 7257f88993 | |||
| 79a5402e83 | |||
| abc899e822 | |||
| 4e96f00ae9 | |||
| 48106a8577 | |||
| dcdba2a9ad | |||
| 544c7a065f | |||
| cd3ed911d2 | |||
| e95b2a905c | |||
| e36209306e | |||
| af607bc64a | |||
| 450d81a4e3 | |||
| 75c69adc87 | |||
| 97b808fa81 | |||
| 512ae70b94 | |||
| 322a31fcac | |||
| 20b6c383e1 | |||
| e7ff3ab327 | |||
| 60b55bddab | |||
| 1898e594dd | |||
| 09f0704ad2 | |||
| a6cd047b24 | |||
| 37429a4993 | |||
| 47f2b1e62f | |||
| 4e5fe8c32d | |||
| 2fdf5421ad | |||
| 412e6aa0c5 | |||
| 1fdafeec4e | |||
| ac819893d4 | |||
| 118936845e | |||
| 4b1ab3453f | |||
| 53690ff46d | |||
| e9578bdeec | |||
| 3c4cc4ff7f | |||
| 150d640977 | |||
| a3599af9d1 | |||
| 1ac1196b20 | |||
| 6c5e863a5b | |||
| 15376a5e13 | |||
| eaf5b24044 | |||
| f05c6540f1 | |||
| 25dd3ca4df | |||
| 6281b4f510 | |||
| 2cbc0b0e17 | |||
| f18a0ef72c | |||
| 98fb4fc412 | |||
| 73c995c31f | |||
| 60dcafe0c1 |
@ -247,7 +247,7 @@ dependencies {
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
implementation 'com.contrarywind:Android-PickerView:4.1.3'
|
||||
implementation 'com.contrarywind:Android-PickerView:4.1.8'
|
||||
|
||||
implementation "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}"
|
||||
implementation "net.cachapa.expandablelayout:expandablelayout:${expandableLayout}"
|
||||
@ -263,8 +263,9 @@ dependencies {
|
||||
implementation ("com.shuyu:gsyVideoPlayer-java:$gsyVideo",{
|
||||
exclude module: "gsyvideoplayer-androidvideocache"
|
||||
})
|
||||
implementation "com.shuyu:gsyVideoPlayer-armv7a:$gsyVideo"
|
||||
implementation "com.shuyu:gsyVideoPlayer-x86:$gsyVideo"
|
||||
implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo"
|
||||
// implementation "com.shuyu:gsyVideoPlayer-armv7a:$gsyVideo"
|
||||
// implementation "com.shuyu:gsyVideoPlayer-x86:$gsyVideo"
|
||||
|
||||
implementation "com.github.wendux:DSBridge-Android:$dsBridge"
|
||||
|
||||
@ -291,6 +292,9 @@ dependencies {
|
||||
exclude group: 'com.squareup.okhttp3'
|
||||
})
|
||||
|
||||
debugImplementation "com.github.markzhai:blockcanary-android:$blockcanary"
|
||||
releaseImplementation "com.github.markzhai:blockcanary-no-op:$blockcanary"
|
||||
|
||||
implementation project(':libraries:LGLibrary')
|
||||
implementation project(':libraries:MTA')
|
||||
implementation project(':libraries:QQShare')
|
||||
|
||||
@ -41,6 +41,8 @@
|
||||
com.shuyu.gsyvideoplayer.armv7a,
|
||||
com.shuyu.gsyvideoplayer.x86,
|
||||
com.shuyu.gsy.base,
|
||||
com.google.android.exoplayer2,
|
||||
tv.danmaku.ijk.media.exo2,
|
||||
shuyu.com.androidvideocache,
|
||||
pl.droidsonroids.gif" />
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<link rel="stylesheet" type="text/css" href="normalize.css">
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<link rel="stylesheet" type="text/css" href="video-js.min.css">
|
||||
|
||||
1
app/src/main/assets/lottie/community_vote.json
Normal file
1
app/src/main/assets/lottie/community_vote.json
Normal file
File diff suppressed because one or more lines are too long
1
app/src/main/assets/lottie/double_click_guide.json
Normal file
1
app/src/main/assets/lottie/double_click_guide.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.6.4","fr":25,"ip":0,"op":35,"w":1080,"h":214,"nm":"点赞","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"椭圆形 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.588],"y":[0]},"t":17,"s":[15]},{"t":20,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[468.04,73.68,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.659,0.659,0.333],"y":[0,0,0]},"t":10,"s":[50,50,100]},{"t":19,"s":[150,150,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":1510,"st":10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"椭圆形 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.588],"y":[0]},"t":27,"s":[15]},{"t":30,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[468.04,73.68,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.659,0.659,0.333],"y":[0,0,0]},"t":20,"s":[50,50,100]},{"t":28,"s":[140,140,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":20,"op":1520,"st":20,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"路径备份 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.602],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.663],"y":[0]},"t":24,"s":[100]},{"t":29,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[531.02,129.675,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.514,0.514,0.333],"y":[0,0,0]},"t":5,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.533,0.533,0.333],"y":[0,0,0]},"t":10,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.586,0.586,0.333],"y":[0,0,0]},"t":15,"s":[95,95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.499,0.499,0.333],"y":[0,0,0]},"t":19,"s":[90,90,100]},{"t":24,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.33,-8.3],[3.89,0.27],[-4.4,-1.68],[-4.33,-0.67],[-4.08,9.32],[3.33,5.44],[3.39,4.6],[0.87,-3.7],[3.6,-0.86],[1.03,-0.21],[2.34,-0.53],[0.96,1.15],[4.22,5.48],[-1.18,-4.56]],"o":[[1.11,1.71],[-3.89,-0.27],[6.42,2.5],[4.33,0.66],[1.63,-5.32],[-3.34,-5.45],[-1.68,-2.1],[-0.71,3.14],[-3.43,0.95],[-0.57,0.08],[-3.86,1.12],[-3.23,-3.94],[-1.89,-2.28],[2.42,4.64]],"v":[[-5.387,9.698],[-10.717,8.498],[-12.327,15.628],[5.813,21.748],[23.313,11.778],[20.273,-1.202],[11.563,-13.962],[5.393,-12.362],[1.083,-13.722],[-2.087,-9.742],[-5.707,-11.752],[-8.777,-7.572],[-18.297,-20.542],[-23.827,-17.832]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":"路径备份 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1500,"st":0,"bm":0}],"markers":[]}
|
||||
1
app/src/main/assets/lottie/like.json
Normal file
1
app/src/main/assets/lottie/like.json
Normal file
File diff suppressed because one or more lines are too long
@ -617,3 +617,10 @@ RE.sendElementNameToNative = function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// android function to open link
|
||||
function customLinkgo(self) {
|
||||
var datas = self.dataset.datas
|
||||
// console.log(datas)
|
||||
window.OnLinkClickListener.onClick(datas)
|
||||
}
|
||||
|
||||
@ -133,9 +133,9 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
shareSummary,
|
||||
shareType);
|
||||
if (shareType == ShareUtils.ShareType.game || shareType == ShareUtils.ShareType.plugin) {
|
||||
MtaHelper.onEvent("内容分享", shareTitle + shareSummary);
|
||||
MtaHelper.onEvent("内容分享", "内容分享", shareTitle + shareSummary);
|
||||
} else {
|
||||
MtaHelper.onEvent("内容分享", shareTitle);
|
||||
MtaHelper.onEvent("内容分享", "内容分享", shareTitle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,12 +178,23 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (isFinishing()) {
|
||||
onFinish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
/**
|
||||
* 可凭借此回调确定当前 activity 已经执行了 finish() 处于 isFinishing 状态
|
||||
* 可在后续进行
|
||||
*/
|
||||
protected void onFinish() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
|
||||
@ -201,7 +201,7 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
}
|
||||
R.id.editor_link_game -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-游戏")
|
||||
startActivityForResult(GameActivity.getIntent(this, "插入游戏"), INSERT_GAME_CODE)
|
||||
startActivityForResult(GameActivity.getIntent(this, GameActivity.INSERT_GAME_TITLE), INSERT_GAME_CODE)
|
||||
}
|
||||
R.id.editor_link_video -> {
|
||||
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-视频")
|
||||
|
||||
@ -52,7 +52,7 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
protected boolean isEverPause;
|
||||
|
||||
@NonNull
|
||||
protected String mEntrance;
|
||||
protected String mEntrance = "";
|
||||
|
||||
protected final Handler mBaseHandler = new BaseFragment.BaseHandler(this);
|
||||
|
||||
|
||||
@ -2,14 +2,27 @@ package com.gh.common
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
import com.gh.common.AppExecutor.ioExecutor
|
||||
import com.gh.common.AppExecutor.lightWeightIoExecutor
|
||||
import com.gh.common.AppExecutor.uiExecutor
|
||||
import java.util.concurrent.*
|
||||
|
||||
/**
|
||||
* APP 线程池管理类
|
||||
*
|
||||
* [ioExecutor] 是一个最大线程数固定的线程池,较为繁重的 IO 任务可以交给它
|
||||
* [uiExecutor] 是主线程的包裹,需要切换至主线程执行可以用它
|
||||
* [lightWeightIoExecutor] 是一个单线程的线程池,轻量级且需要保证同一线程的 IO 任务可以交给它
|
||||
*
|
||||
*/
|
||||
object AppExecutor {
|
||||
@JvmStatic
|
||||
var ioExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
@JvmStatic
|
||||
var uiExecutor = MainThreadExecutor()
|
||||
@JvmStatic
|
||||
var lightWeightIoExecutor = Executors.newSingleThreadExecutor()
|
||||
@JvmStatic
|
||||
var ioExecutor = Executors.newCachedThreadPool()
|
||||
|
||||
class MainThreadExecutor : Executor {
|
||||
private val mainThreadHandler = Handler(Looper.getMainLooper())
|
||||
@ -24,8 +37,12 @@ object AppExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
fun runOnIoThread(f: () -> Unit) {
|
||||
AppExecutor.ioExecutor.execute(f)
|
||||
fun runOnIoThread(isLightWeightTask: Boolean = false, f: () -> Unit) {
|
||||
if (isLightWeightTask) {
|
||||
AppExecutor.lightWeightIoExecutor.execute(f)
|
||||
} else {
|
||||
AppExecutor.ioExecutor.execute(f)
|
||||
}
|
||||
}
|
||||
|
||||
fun runOnUiThread(f: () -> Unit) {
|
||||
|
||||
@ -15,7 +15,6 @@ import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
object DefaultWebViewUrlHandler {
|
||||
@ -36,7 +35,7 @@ object DefaultWebViewUrlHandler {
|
||||
when (host) {
|
||||
"article" -> context.startActivity(NewsDetailActivity.getIntentById(context, id, entrance))
|
||||
|
||||
"game" -> GameDetailActivity.startGameDetailActivity(context, id, entrance)
|
||||
"game" -> GameDetailActivity.startGameDetailActivity(context, id, "libao" == uri.getQueryParameter("to"), entrance)
|
||||
|
||||
"column" -> SubjectActivity.startSubjectActivity(context, id, uri.getQueryParameter("name"), false, entrance)
|
||||
|
||||
@ -116,13 +115,17 @@ object DefaultWebViewUrlHandler {
|
||||
val categoryId = uri.getQueryParameter("category_id") ?: ""
|
||||
val link = uri.getQueryParameter("link") ?: ""
|
||||
val linkEntity = VideoLinkEntity(title, categoryId, link)
|
||||
if (!CheckLoginUtils.isLogin()) {
|
||||
HaloApp.put(EntranceUtils.HOST_UPLOAD_VIDEO, linkEntity)
|
||||
}
|
||||
CheckLoginUtils.checkLogin(context, EntranceUtils.ENTRANCE_BROWSER) {
|
||||
// if (!CheckLoginUtils.isLogin()) {
|
||||
// HaloApp.put(EntranceUtils.HOST_UPLOAD_VIDEO, linkEntity)
|
||||
// }
|
||||
CheckLoginUtils.checkLogin(context, null, true, EntranceUtils.ENTRANCE_BROWSER) {
|
||||
DirectUtils.directToVideoManager(context, linkEntity, EntranceUtils.ENTRANCE_BROWSER, "")
|
||||
}
|
||||
}
|
||||
EntranceUtils.HOST_USERHOME -> {
|
||||
val position = uri.getQueryParameter("position")
|
||||
DirectUtils.directToHomeActivity(context, id, if(position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
|
||||
}
|
||||
else -> DialogUtils.showLowVersionDialog(context)
|
||||
}
|
||||
return true
|
||||
|
||||
@ -9,7 +9,7 @@ import com.halo.assistant.HaloApp
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* 统计用户在当前 Fragment 的停留时间,在 onViewDestroy 或 onDestroy 里获取 elapsedTime 即可,单位为秒
|
||||
* 统计用户在当前 Fragment/Activity 的停留时间,在 onViewDestroy 或 onDestroy 里获取 elapsedTime 即可,单位为秒
|
||||
*/
|
||||
class TimeElapsedHelper(val fragment: Fragment?, val activity: Activity?) {
|
||||
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package com.gh.common.avoidcallback;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
public class ActivityResultInfo {
|
||||
private int resultCode;
|
||||
private Intent data;
|
||||
|
||||
public ActivityResultInfo(int resultCode, Intent data) {
|
||||
this.resultCode = resultCode;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
public int getResultCode() {
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
public void setResultCode(int resultCode) {
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
public Intent getData() {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(Intent data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.gh.common.avoidcallback
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.SparseArray
|
||||
import androidx.fragment.app.Fragment
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
|
||||
class AvoidOnResultFragment : Fragment() {
|
||||
private val mSubjects = SparseArray<PublishSubject<ActivityResultInfo>>()
|
||||
private val mCallbacks = SparseArray<Callback>()
|
||||
|
||||
private var requestCode = 1000
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
retainInstance = true
|
||||
}
|
||||
|
||||
fun startForResult(intent: Intent): Observable<ActivityResultInfo> {
|
||||
val subject = PublishSubject.create<ActivityResultInfo>()
|
||||
return subject.doOnSubscribe {
|
||||
mSubjects.put(requestCode, subject)
|
||||
startActivityForResult(intent, requestCode)
|
||||
requestCode++
|
||||
}
|
||||
}
|
||||
|
||||
fun startForResult(intent: Intent, callback: Callback) {
|
||||
mCallbacks.put(requestCode, callback)
|
||||
startActivityForResult(intent, requestCode)
|
||||
requestCode++
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
val subject = mSubjects.get(requestCode)
|
||||
if (subject != null) {
|
||||
subject.onNext(ActivityResultInfo(resultCode, data))
|
||||
subject.onComplete()
|
||||
}
|
||||
mSubjects.remove(requestCode)
|
||||
val callback = mCallbacks.get(requestCode)
|
||||
callback?.onActivityResult(resultCode, data)
|
||||
mCallbacks.remove(requestCode)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.gh.common.avoidcallback
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import io.reactivex.Observable
|
||||
|
||||
|
||||
class AvoidOnResultManager {
|
||||
val TAG = "AvoidOnResultManager"
|
||||
private var mAvoidOnResultFragment: AvoidOnResultFragment
|
||||
|
||||
private constructor(activity: AppCompatActivity) {
|
||||
mAvoidOnResultFragment = getAvoidOnResultFragment(activity)
|
||||
}
|
||||
|
||||
private constructor(fragment: Fragment) : this(fragment.activity as AppCompatActivity)
|
||||
|
||||
companion object {
|
||||
fun getInstance(activity: AppCompatActivity): AvoidOnResultManager {
|
||||
return AvoidOnResultManager(activity)
|
||||
}
|
||||
|
||||
fun getInstance(fragment: Fragment): AvoidOnResultManager {
|
||||
return AvoidOnResultManager(fragment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAvoidOnResultFragment(activity: AppCompatActivity): AvoidOnResultFragment {
|
||||
var avoidOnResultFragment = findAvoidOnResultFragment(activity)
|
||||
if (avoidOnResultFragment == null) {
|
||||
avoidOnResultFragment = AvoidOnResultFragment()
|
||||
val fragmentManager = activity.supportFragmentManager
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(avoidOnResultFragment, TAG)
|
||||
.commitAllowingStateLoss()
|
||||
fragmentManager.executePendingTransactions()
|
||||
}
|
||||
return avoidOnResultFragment
|
||||
}
|
||||
|
||||
private fun findAvoidOnResultFragment(activity: AppCompatActivity): AvoidOnResultFragment? {
|
||||
return activity.supportFragmentManager.findFragmentByTag(TAG) as? AvoidOnResultFragment
|
||||
}
|
||||
|
||||
fun startForResult(intent: Intent, callback: Callback) {
|
||||
mAvoidOnResultFragment.startForResult(intent, callback)
|
||||
}
|
||||
|
||||
fun startForResult(clazz: Class<*>, callback: Callback) {
|
||||
val intent = Intent(mAvoidOnResultFragment.activity, clazz)
|
||||
mAvoidOnResultFragment.startForResult(intent, callback)
|
||||
}
|
||||
|
||||
fun startForResult(intent: Intent): Observable<ActivityResultInfo> {
|
||||
return mAvoidOnResultFragment.startForResult(intent)
|
||||
}
|
||||
|
||||
fun startForResult(clazz: Class<*>): Observable<ActivityResultInfo> {
|
||||
val intent = Intent(mAvoidOnResultFragment.activity, clazz)
|
||||
return mAvoidOnResultFragment.startForResult(intent)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.gh.common.avoidcallback
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
interface Callback {
|
||||
fun onActivityResult(resultCode: Int, data: Intent?)
|
||||
}
|
||||
@ -44,12 +44,24 @@ public class Constants {
|
||||
public static final String SP_SHOWED_NOTIFICATION_NEW_VERSION = "show_notification_new_version";
|
||||
// 今天是否已经触发了 “通知管理” 引导弹窗
|
||||
public static final String SP_IS_SHOWED_NOTIFICATION_TODAY = "show_is_notification_today";
|
||||
// 标记安装的游戏为已玩过弹窗,最多取消2次 (https://gitlab.ghzs.com/pm/halo-app-issues/issues/722 调整为版本相关) (不是常量了也放这里好像有点奇怪)
|
||||
// v4.0.0已废弃,标记安装的游戏为已玩过弹窗,最多取消2次 (https://gitlab.ghzs.com/pm/halo-app-issues/issues/722 调整为版本相关) (不是常量了也放这里好像有点奇怪)
|
||||
public static final String SP_MARK_INSTALLED_GAME = "mark_installed_game" + PackageUtils.getVersionName();
|
||||
// 标记安装的游戏为已玩过弹窗(个人主页最多弹一次)
|
||||
public static final String SP_MARK_INSTALLED_GAME_USER_HOME = "mark_installed_game_user_home" + PackageUtils.getVersionName();
|
||||
// 标记安装的游戏为已玩过弹窗(我的游戏最多弹一次)
|
||||
public static final String SP_MARK_INSTALLED_GAME_MY_GAME = "mark_installed_game_my_game" + PackageUtils.getVersionName();
|
||||
//视频详情滑动引导
|
||||
public static final String SP_SHOW_SLIDE_GUIDE = "show_slide_guide";
|
||||
//视频详情点击引导
|
||||
public static final String SP_SHOW_CLICK_GUIDE = "show_click_guide";
|
||||
//视频详情双击点赞引导
|
||||
public static final String SP_SHOW_DOUBLE_CLICK_GUIDE = "show_double_click_guide";
|
||||
//顶部视频声音状态,重启恢复
|
||||
public static final String SP_TOP_VIDEO_VOICE = "top_video_voice";
|
||||
//我的光环提醒设置已读
|
||||
public static final String SP_ADDONS_FUNCS_HAVE_READ = "addons_funcs_have_read";
|
||||
//视频非wifi提醒只提醒一次,重启恢复
|
||||
public static final String SP_NON_WIFI_TIPS = "non_wifi_tips";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
@ -84,7 +96,9 @@ public class Constants {
|
||||
public static final int COMMENT_CD = 60 * 1000;
|
||||
//我的光环功能分组 cd间隔
|
||||
public static final int ADDONS_CD = 10 * 60 * 1000;
|
||||
|
||||
//已收录包名更新 cd间隔
|
||||
public static final int PACKAGES_CD = 60 * 1000;
|
||||
|
||||
public static final String[] REPORT_LIST = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它"};
|
||||
|
||||
public static final String ENTRANCE_UNKNOWN = "(unknown)";
|
||||
|
||||
@ -38,7 +38,7 @@ class GameOffServiceDialogFragment : BaseTrackableDialogFragment() {
|
||||
topMargin = DisplayUtils.dip2px(12f)
|
||||
}
|
||||
siteTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
|
||||
siteTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme))
|
||||
siteTv.setTextColor(ContextCompat.getColor(requireContext(), R.color.theme_font))
|
||||
siteTv.text = site.text
|
||||
siteTv.paintFlags = siteTv.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
siteTv.setOnClickListener {
|
||||
|
||||
@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.SPUtils
|
||||
import com.gh.common.util.tryWithDefaultCatch
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
@ -128,7 +129,7 @@ object ImManager {
|
||||
@JvmStatic
|
||||
fun sendFeedbackMessage(message: String) {
|
||||
val fromToMessage = IMMessage.createTxtMessage(message)
|
||||
HaloApp.getInstance().mainExecutor.execute {
|
||||
runOnIoThread {
|
||||
tryWithDefaultCatch {
|
||||
IMChat.getInstance().sendMessage(fromToMessage, object : ChatListener {
|
||||
override fun onProgress(p0: Int) {}
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.gamecenter.LoginActivity;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by khy on 28/06/17.
|
||||
*/
|
||||
@ -32,6 +36,28 @@ public class CheckLoginUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkLogin(final Context context, Bundle nextToBundle, boolean isTriggerNextStep, String entrance, OnLoginListener listener) {
|
||||
if (!isLogin()) {
|
||||
if (listener != null) Utils.toast(context, "需要登录");
|
||||
LogUtils.login("dialog", null, entrance);
|
||||
LogUtils.login("activity", null, entrance);
|
||||
|
||||
// 有可能App未启动
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
bundle.putString(EntranceUtils.KEY_TO, LoginActivity.class.getName());
|
||||
EntranceUtils.jumpActivity(context, nextToBundle, bundle, (resultCode, data) -> {
|
||||
if (isTriggerNextStep && listener != null && isLogin()) {
|
||||
listener.onLogin();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.onLogin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isLogin() {
|
||||
return !TextUtils.isEmpty(UserManager.getInstance().getToken());
|
||||
}
|
||||
|
||||
@ -72,11 +72,6 @@ object CommentHelper {
|
||||
videoId: String? = null,
|
||||
listener: OnCommentCallBackListener? = null) {
|
||||
val dialogOptions = ArrayList<String>()
|
||||
|
||||
if (commentEntity.me == null || !commentEntity.me?.isCommentOwner!!) {
|
||||
dialogOptions.add("回复")
|
||||
}
|
||||
|
||||
dialogOptions.add("复制")
|
||||
dialogOptions.add("投诉")
|
||||
|
||||
@ -97,18 +92,6 @@ object CommentHelper {
|
||||
when (it) {
|
||||
"管理" -> showControlDialog(context, answerId, articleId, communityId, commentEntity, commentEntity.me!!)
|
||||
|
||||
"回复" -> {
|
||||
context.ifLogin("回答详情-评论-回复") {
|
||||
if (listener != null) {
|
||||
listener.onCommentCallback(commentEntity)
|
||||
} else if (!TextUtils.isEmpty(commentEntity.id)) {
|
||||
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, commentEntity.id))
|
||||
} else {
|
||||
Utils.toast(context, "缺少关键属性")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"复制" -> copyText(commentEntity.content, context)
|
||||
|
||||
"投诉" -> {
|
||||
|
||||
@ -13,9 +13,7 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.gh.gamecenter.CommentDetailActivity;
|
||||
import com.gh.gamecenter.MessageDetailActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.OnCommentCallBackListener;
|
||||
import com.gh.gamecenter.adapter.viewholder.CommentViewHolder;
|
||||
import com.gh.gamecenter.entity.CommentEntity;
|
||||
import com.gh.gamecenter.entity.MeEntity;
|
||||
@ -85,8 +83,6 @@ public class CommentUtils {
|
||||
public static void showReportDialog(final CommentEntity commentEntity,
|
||||
final Context context,
|
||||
final boolean showConversation,
|
||||
final OnCommentCallBackListener listener,
|
||||
final String newsId,
|
||||
final String patch) {
|
||||
final Dialog dialog = new Dialog(context);
|
||||
|
||||
@ -96,11 +92,6 @@ public class CommentUtils {
|
||||
container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12));
|
||||
|
||||
List<String> dialogType = new ArrayList<>();
|
||||
|
||||
if (commentEntity.getMe() == null || !commentEntity.getMe().isCommentOwner()) {
|
||||
dialogType.add("回复");
|
||||
}
|
||||
|
||||
dialogType.add("复制");
|
||||
dialogType.add("投诉");
|
||||
|
||||
@ -126,17 +117,6 @@ public class CommentUtils {
|
||||
public void onClick(View v) {
|
||||
dialog.cancel();
|
||||
switch (reportTv.getText().toString()) {
|
||||
case "回复":
|
||||
CheckLoginUtils.checkLogin(context, patch + "-回复", () -> {
|
||||
if (listener != null) {
|
||||
listener.onCommentCallback(commentEntity);
|
||||
} else if (!TextUtils.isEmpty(newsId)) {
|
||||
context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, newsId));
|
||||
} else {
|
||||
Utils.toast(context, "缺少关键属性");
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "复制":
|
||||
copyText(commentEntity.getContent(), context);
|
||||
break;
|
||||
@ -218,13 +198,13 @@ public class CommentUtils {
|
||||
public static void postVote(final Context context, final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv, final ImageView commentLikeIv,
|
||||
final OnVoteListener listener) {
|
||||
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
|
||||
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
|
||||
Utils.toast(context, "已经点过赞啦!");
|
||||
return;
|
||||
}
|
||||
commentEntity.setVote(commentEntity.getVote() + 1);
|
||||
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
|
||||
commentLikeIv.setImageResource(R.drawable.vote_icon_select);
|
||||
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
|
||||
commentLikeIv.setImageResource(R.drawable.comment_vote_select);
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
|
||||
@ -242,7 +222,7 @@ public class CommentUtils {
|
||||
|
||||
commentEntity.setVote(commentEntity.getVote() - 1);
|
||||
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
|
||||
commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
|
||||
commentLikeIv.setImageResource(R.drawable.comment_vote_unselect);
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
if (commentEntity.getVote() == 0) {
|
||||
commentLikeCountTv.setVisibility(View.GONE);
|
||||
@ -284,13 +264,13 @@ public class CommentUtils {
|
||||
entrance = "社区文章详情-评论-点赞";
|
||||
}
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) {
|
||||
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
|
||||
Utils.toast(context, "已经点过赞啦!");
|
||||
return;
|
||||
}
|
||||
commentEntity.setVote(commentEntity.getVote() + 1);
|
||||
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme));
|
||||
commentLikeIv.setImageResource(R.drawable.vote_icon_select);
|
||||
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
|
||||
commentLikeIv.setImageResource(R.drawable.comment_vote_select);
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
|
||||
@ -307,7 +287,7 @@ public class CommentUtils {
|
||||
public void postFailed(Throwable e) {
|
||||
commentEntity.setVote(commentEntity.getVote() - 1);
|
||||
commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint));
|
||||
commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
|
||||
commentLikeIv.setImageResource(R.drawable.comment_vote_unselect);
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
if (commentEntity.getVote() == 0) {
|
||||
commentLikeCountTv.setVisibility(View.GONE);
|
||||
@ -340,14 +320,22 @@ public class CommentUtils {
|
||||
public static void setCommentUserView(Context mContext, CommentViewHolder holder, CommentEntity entity) {
|
||||
MeEntity userDataEntity = entity.getMe();
|
||||
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.hint));
|
||||
holder.commentLikeIv.setImageResource(R.drawable.vote_icon_unselect);
|
||||
holder.commentLikeIv.setImageResource(R.drawable.comment_vote_unselect);
|
||||
|
||||
if (userDataEntity == null || !userDataEntity.isCommentOwner()) {
|
||||
holder.replyLine.setVisibility(View.VISIBLE);
|
||||
holder.commentReply.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.replyLine.setVisibility(View.GONE);
|
||||
holder.commentReply.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (entity.getVote() == 0) {
|
||||
holder.commentLikeCountTv.setVisibility(View.GONE);
|
||||
} else { // 检查是否已点赞
|
||||
if (userDataEntity != null && (userDataEntity.isCommentVoted())) {
|
||||
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
holder.commentLikeIv.setImageResource(R.drawable.vote_icon_select);
|
||||
holder.commentLikeCountTv.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
holder.commentLikeIv.setImageResource(R.drawable.comment_vote_select);
|
||||
}
|
||||
holder.commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
holder.commentLikeCountTv.setText(NumberUtils.transSimpleCount(entity.getVote()));
|
||||
@ -367,10 +355,11 @@ public class CommentUtils {
|
||||
UserInfoEntity userInfo = UserManager.getInstance().getUserInfoEntity();
|
||||
if (userDataEntity != null && userDataEntity.isCommentOwner() && userInfo != null) {
|
||||
if (entity.getMe() != null && entity.getMe().isContentOwner()) {
|
||||
holder.commentUserNameTv.setText(userInfo.getName() + "(作者)");
|
||||
holder.commentAuthorTv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.commentUserNameTv.setText(userInfo.getName());
|
||||
holder.commentAuthorTv.setVisibility(View.GONE);
|
||||
}
|
||||
holder.commentUserNameTv.setText(userInfo.getName());
|
||||
if (userInfo.getAuth() != null) {
|
||||
ImageUtils.display(holder.commentUserBadgeIv, userInfo.getAuth().getIcon());
|
||||
} else {
|
||||
@ -379,10 +368,11 @@ public class CommentUtils {
|
||||
ImageUtils.displayIcon(holder.commentUserIconDv, userInfo.getIcon());
|
||||
} else {
|
||||
if (entity.getMe() != null && entity.getMe().isContentOwner()) {
|
||||
holder.commentUserNameTv.setText(entity.getUser().getName() + "(作者)");
|
||||
holder.commentAuthorTv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.commentUserNameTv.setText(entity.getUser().getName());
|
||||
holder.commentAuthorTv.setVisibility(View.GONE);
|
||||
}
|
||||
holder.commentUserNameTv.setText(entity.getUser().getName());
|
||||
if (entity.getUser().getAuth() != null) {
|
||||
ImageUtils.display(holder.commentUserBadgeIv, entity.getUser().getAuth().getIcon());
|
||||
} else {
|
||||
|
||||
@ -238,18 +238,12 @@ public class DataUtils {
|
||||
}
|
||||
|
||||
public static void onError(Context context, Throwable throwable) {
|
||||
// MTA主动上传错误
|
||||
//bugly 作为默认处理异常的类库,已经上报了,此处不重复上报
|
||||
try {
|
||||
StatService.reportException(context, throwable);
|
||||
CrashReport.postCatchedException(throwable);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
// //bugly 作为默认处理异常的类库,已经上报了,此处不重复上报
|
||||
// try {
|
||||
// CrashReport.postCatchedException(throwable);
|
||||
// } catch (Exception e) {
|
||||
// }
|
||||
|
||||
//talkingdata
|
||||
try {
|
||||
TCAgent.onError(context, throwable);
|
||||
|
||||
@ -8,6 +8,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.CountDownTimer;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@ -200,7 +201,7 @@ public class DialogUtils {
|
||||
String mb = size.toUpperCase().replaceAll("MB", "").trim();
|
||||
Float i = Float.valueOf(mb);
|
||||
if (NetworkUtils.isWifiOr4GConnected(context) && i <= 50) {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> Utils.toast(context, "当前使用移动网络下载,请注意流量消耗"),500);
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> Utils.toast(context, "当前使用移动网络下载,请注意流量消耗"), 500);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -241,7 +242,7 @@ public class DialogUtils {
|
||||
Context finalContext = context;
|
||||
allowOnce.setOnClickListener(v -> {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> {
|
||||
Utils.toast(HaloApp.getInstance().getApplication(), "已使用移动网络下载,请注意流量消耗");
|
||||
Utils.toast(finalContext, "已使用移动网络下载,请注意流量消耗");
|
||||
}, 500);
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
@ -261,7 +262,7 @@ public class DialogUtils {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> {
|
||||
// 显示了弹窗以后,即便下面这个 toast 放在 listener.onConfirm 后调用也是显示 listener.onConfirm 里的 toast
|
||||
// 喷了,延时包治疑难杂症
|
||||
Utils.toast(HaloApp.getInstance().getApplication(), "已使用移动网络下载,请注意流量消耗");
|
||||
Utils.toast(finalContext, "已使用移动网络下载,请注意流量消耗");
|
||||
}, 500);
|
||||
listener.onConfirm();
|
||||
dialog.dismiss();
|
||||
@ -646,9 +647,9 @@ public class DialogUtils {
|
||||
Button negativeBtn = alertDialog.getButton(android.app.AlertDialog.BUTTON_NEGATIVE);
|
||||
|
||||
positiveBtn.setTextSize(13);
|
||||
positiveBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
|
||||
positiveBtn.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
|
||||
negativeBtn.setTextSize(13);
|
||||
negativeBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
|
||||
negativeBtn.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
|
||||
if (mesage != null) {
|
||||
mesage.setGravity(Gravity.CENTER);
|
||||
mesage.setTextSize(24);
|
||||
@ -878,19 +879,24 @@ public class DialogUtils {
|
||||
// 区分此 dialog 是点击 dialog 外部取消的还是点击返回取消的
|
||||
AtomicBoolean isCanceledByClickOutsideOfDialog = new AtomicBoolean(true);
|
||||
|
||||
final Dialog dialog = new Dialog(activityContext, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
|
||||
final Dialog dialog = new Dialog(activityContext, R.style.GhAlertDialog);
|
||||
View contentView = LayoutInflater.from(activityContext).inflate(R.layout.dialog_privacy_policy, null);
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(contentView);
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.getDecorView().setPadding(0, 0, 0, 0);
|
||||
window.setBackgroundDrawableResource(android.R.color.transparent);
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.horizontalMargin = 0;
|
||||
params.width = context.getResources().getDisplayMetrics().widthPixels;
|
||||
params.height = context.getResources().getDisplayMetrics().heightPixels;
|
||||
params.width = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(40);
|
||||
int height = context.getResources().getDisplayMetrics().heightPixels - DisplayUtils.dip2px(120);
|
||||
int maxHeight = DisplayUtils.dip2px(546);
|
||||
if (height > maxHeight) {
|
||||
params.height = maxHeight;
|
||||
} else {
|
||||
params.height = height;
|
||||
}
|
||||
window.setAttributes(params);
|
||||
}
|
||||
|
||||
@ -898,6 +904,7 @@ public class DialogUtils {
|
||||
TextView bottomContent = contentView.findViewById(R.id.bottom_content);
|
||||
TextView topContent = contentView.findViewById(R.id.top_content);
|
||||
TextView allowButton = contentView.findViewById(R.id.allow_button);
|
||||
TextView disallowButton = contentView.findViewById(R.id.disallow_button);
|
||||
TextView linkContent = contentView.findViewById(R.id.link_content);
|
||||
RecyclerView permissions = contentView.findViewById(R.id.permissions_content);
|
||||
|
||||
@ -938,7 +945,7 @@ public class DialogUtils {
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(ContextCompat.getColor(activityContext, R.color.text_1383EB));
|
||||
ds.setColor(ContextCompat.getColor(activityContext, R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@ -954,7 +961,7 @@ public class DialogUtils {
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(ContextCompat.getColor(activityContext, R.color.text_1383EB));
|
||||
ds.setColor(ContextCompat.getColor(activityContext, R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@ -968,17 +975,19 @@ public class DialogUtils {
|
||||
title.setText(entity.getTitle());
|
||||
linkContent.setText(skipText);
|
||||
linkContent.setMovementMethod(new LinkMovementMethod());
|
||||
allowButton.setText("我知道了");
|
||||
topContent.setText(entity.getTopContent());
|
||||
bottomContent.setText(entity.getBottomContent());
|
||||
|
||||
allowButton.setOnClickListener(view -> {
|
||||
dialog.dismiss();
|
||||
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击我知道了");
|
||||
callback.onCallback();
|
||||
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "点击同意");
|
||||
});
|
||||
|
||||
dialog.setOnDismissListener(d -> {
|
||||
callback.onCallback();
|
||||
disallowButton.setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
showPrivacyPolicyDisallowDialog(activityContext, entity, callback);
|
||||
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "不同意并退出App");
|
||||
});
|
||||
|
||||
dialog.setOnCancelListener(cd -> {
|
||||
@ -997,6 +1006,38 @@ public class DialogUtils {
|
||||
|
||||
MtaHelper.onEvent("隐私政策弹窗", "隐私政策弹窗", "出现弹窗");
|
||||
|
||||
try {
|
||||
dialog.setCancelable(false);
|
||||
dialog.show();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void showPrivacyPolicyDisallowDialog(Context context,
|
||||
@NonNull PrivacyPolicyEntity entity,
|
||||
EmptyCallback callback) {
|
||||
final Context activityContext = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(activityContext, R.style.DialogWindowTransparent);
|
||||
|
||||
View contentView = LayoutInflater.from(activityContext).inflate(R.layout.dialog_disallow_privacy_policy, null);
|
||||
View backButton = contentView.findViewById(R.id.back_button);
|
||||
View reviewButton = contentView.findViewById(R.id.review_button);
|
||||
|
||||
backButton.setOnClickListener(v -> {
|
||||
MtaHelper.onEvent("隐私政策弹窗", "退出提示弹窗", "退出应用");
|
||||
dialog.dismiss();
|
||||
AppManager.getInstance().appExit(activityContext);
|
||||
});
|
||||
reviewButton.setOnClickListener(v -> {
|
||||
MtaHelper.onEvent("隐私政策弹窗", "退出提示弹窗", "再次查看");
|
||||
dialog.dismiss();
|
||||
showPrivacyPolicyDialog(activityContext, entity, callback);
|
||||
});
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setCancelable(false);
|
||||
dialog.setContentView(contentView);
|
||||
try {
|
||||
dialog.show();
|
||||
} catch (Exception ignored) {
|
||||
@ -1150,6 +1191,39 @@ public class DialogUtils {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static void showDownloadMutexDialog(Context context) {
|
||||
context = checkDialogContext(context);
|
||||
|
||||
final Dialog dialog = new Dialog(context, R.style.GhAlertDialog);
|
||||
|
||||
View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_downlaod_mutex, null);
|
||||
TextView positive = contentView.findViewById(R.id.dialog_positive);
|
||||
|
||||
CountDownTimer timer = new CountDownTimer(6000, 1000) {
|
||||
public void onTick(long millisUntilFinished) {
|
||||
positive.setText(("我知道了(" + millisUntilFinished / 1000 + ")"));
|
||||
}
|
||||
|
||||
public void onFinish() {
|
||||
dialog.dismiss();
|
||||
}
|
||||
};
|
||||
timer.start();
|
||||
|
||||
positive.setOnClickListener(v -> {
|
||||
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
|
||||
|
||||
@ -149,7 +149,14 @@ object DirectUtils {
|
||||
|
||||
"community_special_column" -> context.startActivity(AskColumnDetailActivity.getIntentByColumnId(context, linkEntity.link, linkEntity.community!!, entrance, path))
|
||||
|
||||
"web", "inurl", "web链接" -> directToWebView(context, url = linkEntity.link!!, entrance = BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
"web", "inurl", "web链接" -> {
|
||||
when {
|
||||
linkEntity.link!!.contains("v.douyin") && PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme") -> {
|
||||
directDouyin(context, "1402577827140941")
|
||||
}
|
||||
else -> directToWebView(context, url = linkEntity.link!!, entrance = BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
}
|
||||
}
|
||||
|
||||
"qq", "QQ" -> directToQqConversation(context, linkEntity.link)
|
||||
|
||||
@ -234,6 +241,21 @@ object DirectUtils {
|
||||
context.startActivity(UserHomeActivity.getIntent(context, userId ?: "", entrance, path))
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至个人主页
|
||||
* @param position 定位到某个tab 0游戏评论 1问答 2视频
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToHomeActivity(context: Context, userId: String?, position: Int, entrance: String? = null, path: String? = null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_USER_ID, userId)
|
||||
bundle.putString(KEY_TO, UserHomeActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
|
||||
bundle.putString(KEY_PATH, path)
|
||||
bundle.putInt(KEY_POSITION, position)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 回到首页
|
||||
*/
|
||||
@ -246,11 +268,15 @@ object DirectUtils {
|
||||
* 跳转到游戏详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null) {
|
||||
fun directToGameDetail(context: Context, id: String, entrance: String? = null, autoDownload: Boolean? = null, scrollToLibao: Boolean = false) {
|
||||
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)
|
||||
}
|
||||
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
@ -567,4 +593,13 @@ object DirectUtils {
|
||||
// context.startActivity(GameVideoActivity.getIntent(context, gameId, entrance, path))
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun directDouyin(context: Context, userId: String) {
|
||||
if (PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme")) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("snssdk1128://user/profile/$userId"))
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,7 @@ import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
@ -237,6 +238,18 @@ public class DisplayUtils {
|
||||
return (resourceId > 0 && hasSoftKeys(context)) ? resources.getDimensionPixelSize(resourceId) : 0;
|
||||
}
|
||||
|
||||
//判断导航栏是否显示
|
||||
public static boolean isNavigationBarShow(Activity activity) {
|
||||
ViewGroup vp = (ViewGroup) activity.getWindow().getDecorView();
|
||||
for (int i = 0; i < vp.getChildCount(); i++) {
|
||||
View child = vp.getChildAt(i);
|
||||
if (child.getId() != -1 && "navigationBarBackground".equals(activity.getResources().getResourceEntryName(child.getId())) && child.getMeasuredHeight() != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasSoftKeys(Context context) {
|
||||
if (!(context instanceof Activity)) return false;
|
||||
|
||||
|
||||
232
app/src/main/java/com/gh/common/util/DownloadObserver.kt
Normal file
232
app/src/main/java/com/gh/common/util/DownloadObserver.kt
Normal file
@ -0,0 +1,232 @@
|
||||
package com.gh.common.util
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import com.gh.base.BaseActivity
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.SuggestionActivity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBShowDialog
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.suggest.SuggestType
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.halo.assistant.fragment.SettingsFragment
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import com.lightgame.download.FileUtils
|
||||
import com.lightgame.utils.AppManager
|
||||
import com.lightgame.utils.Util_System_Phone_State
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
object DownloadObserver {
|
||||
|
||||
private val mApplication = HaloApp.getInstance().application
|
||||
|
||||
@JvmStatic
|
||||
fun initObserver() {
|
||||
val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
if (downloadEntity.status != DownloadStatus.downloading) {
|
||||
LogUtils.uploadDownloadEvent(downloadEntity)
|
||||
}
|
||||
|
||||
if (DownloadStatus.hijack == downloadEntity.status) {
|
||||
// 链接被劫持
|
||||
processHijack(downloadEntity)
|
||||
val nameAndPlatform = (downloadEntity.name + ":"
|
||||
+ PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
MtaHelper.onEvent( "下载劫持",
|
||||
"游戏名字", nameAndPlatform,
|
||||
"网络状态", DeviceUtils.getNetwork(mApplication))
|
||||
return
|
||||
} else if (DownloadStatus.notfound == downloadEntity.status) {
|
||||
// 404 Not Found
|
||||
// 删除任务
|
||||
downloadEntity.status = DownloadStatus.cancel
|
||||
DownloadManager.getInstance(mApplication).cancel(downloadEntity.url)
|
||||
Utils.toast(mApplication, "该链接已失效!请联系管理员。")
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
|
||||
"游戏", downloadEntity.name,
|
||||
"平台", downloadEntity.platform)
|
||||
|
||||
DialogUtils.showAlertDialog(AppManager.getInstance().currentActivity(), "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
|
||||
SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
|
||||
SuggestType.gameQuestion, "notfound",
|
||||
StringUtils.buildString(downloadEntity.name, ",问题反馈:下载链接失效"),
|
||||
SimpleGameEntity(downloadEntity.gameId, downloadEntity.name, ""))
|
||||
}, null)
|
||||
return
|
||||
} else if (DownloadStatus.neterror == downloadEntity.status || DownloadStatus.timeout == downloadEntity.status) {
|
||||
|
||||
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
|
||||
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
|
||||
"游戏", downloadEntity.name,
|
||||
"平台", downloadEntity.platform)
|
||||
}
|
||||
if (DownloadStatus.done == downloadEntity.status) {
|
||||
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
|
||||
MtaHelper.onEvent("软件更新", "下载完成")
|
||||
mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path, true))
|
||||
DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据
|
||||
} else {
|
||||
statDoneEvent(downloadEntity)
|
||||
|
||||
val platform = PlatformUtils.getInstance(mApplication)
|
||||
.getPlatformName(downloadEntity.platform)
|
||||
if (platform != null) {
|
||||
when {
|
||||
downloadEntity.isPluggable -> // 弹出插件化提示框
|
||||
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
|
||||
downloadEntity.isPlugin -> Utils.toast(mApplication, downloadEntity.name + " - " + platform + " - 下载完成")
|
||||
else -> Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
|
||||
}
|
||||
} else {
|
||||
Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
|
||||
}
|
||||
if (!downloadEntity.isPluggable) {
|
||||
// 是否是自动安装
|
||||
if (PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(SettingsFragment.AUTO_INSTALL_SP_KEY, true)) {
|
||||
if (FileUtils.isEmptyFile(downloadEntity.path)) {
|
||||
Utils.toast(mApplication, R.string.install_failure_hint)
|
||||
DownloadManager.getInstance(mApplication).cancel(downloadEntity.url)
|
||||
} else {
|
||||
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path))
|
||||
} else {
|
||||
// 弹出卸载提示框
|
||||
EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计下载完成
|
||||
uploadData(downloadEntity.gameId, downloadEntity.platform)
|
||||
}
|
||||
|
||||
// 下载过程分析统计
|
||||
val pm = mApplication.packageManager
|
||||
val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, PackageManager.GET_ACTIVITIES)
|
||||
if (packageInfo == null) {
|
||||
MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析",
|
||||
"游戏名字", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("解析包错误_新",
|
||||
"游戏", downloadEntity.name + ":" + PlatformUtils.getInstance(mApplication).getPlatformName(downloadEntity.platform))
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadEntity.status == DownloadStatus.done) {
|
||||
EventBus.getDefault().post(EBDownloadStatus("done", "", "", "", "", ""))
|
||||
}
|
||||
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加观察者
|
||||
DownloadManager.getInstance(mApplication).addObserver(dataWatcher)
|
||||
|
||||
}
|
||||
|
||||
// 统计下载完成事件
|
||||
private fun statDoneEvent(downloadEntity: DownloadEntity) {
|
||||
var type: ExposureUtils.DownloadType
|
||||
val platform = PlatformUtils.getInstance(HaloApp.getInstance().application).getPlatformName(downloadEntity.platform)
|
||||
|
||||
val kv1 = HashMap<String, Any>()
|
||||
kv1["版本"] = platform
|
||||
kv1["状态"] = "下载完成"
|
||||
kv1["用户机型"] = Build.MODEL
|
||||
kv1["设备IMEI"] = Util_System_Phone_State.getDeviceId(HaloApp.getInstance().application)
|
||||
kv1["网络状态"] = DeviceUtils.getNetwork(HaloApp.getInstance().application)
|
||||
kv1["光环助手版本"] = BuildConfig.VERSION_NAME
|
||||
if (downloadEntity.isUpdate) {
|
||||
type = ExposureUtils.DownloadType.UPDATE
|
||||
if (downloadEntity.isPlugin) {
|
||||
type = ExposureUtils.DownloadType.PLUGIN_UPDATE
|
||||
}
|
||||
DataUtils.onEvent(mApplication, "游戏更新", downloadEntity.name, kv1)
|
||||
} else {
|
||||
type = ExposureUtils.DownloadType.DOWNLOAD
|
||||
}
|
||||
|
||||
val kv2 = HashMap<String, Any>()
|
||||
kv2["版本"] = downloadEntity.platform
|
||||
kv2["状态"] = "下载完成"
|
||||
kv2["位置"] = downloadEntity.entrance ?: "null"
|
||||
kv2["游戏分平台"] = downloadEntity.name + "-" + platform
|
||||
kv2["光环助手版本"] = BuildConfig.VERSION_NAME
|
||||
DataUtils.onEvent(mApplication, "游戏下载位置", downloadEntity.name, kv2)
|
||||
|
||||
if (downloadEntity.isPluggable) {
|
||||
val kv3 = HashMap<String, Any>()
|
||||
kv3["下载"] = "下载完成"
|
||||
kv3["版本"] = downloadEntity.platform
|
||||
kv3["位置"] = downloadEntity.entrance ?: "null"
|
||||
type = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD
|
||||
DataUtils.onEvent(mApplication, "插件化", downloadEntity.name, kv3)
|
||||
|
||||
MtaHelper.onEvent(
|
||||
"插件化_新",
|
||||
"位置", downloadEntity.entrance,
|
||||
"游戏", downloadEntity.name + "-" + downloadEntity.platform,
|
||||
"操作", "下载完成",
|
||||
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().application))
|
||||
}
|
||||
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
GameEntity(downloadEntity.gameId, downloadEntity.name),
|
||||
downloadEntity.platform,
|
||||
downloadEntity.exposureTrace,
|
||||
type)
|
||||
|
||||
DataCollectionUtils.uploadDownload(mApplication, downloadEntity, "完成")
|
||||
}
|
||||
|
||||
private fun processHijack(downloadEntity: DownloadEntity) {
|
||||
// 删除任务
|
||||
downloadEntity.status = DownloadStatus.cancel
|
||||
DownloadManager.getInstance(mApplication).cancel(downloadEntity.url)
|
||||
// 弹出提示框
|
||||
EventBus.getDefault().post(EBShowDialog(BaseActivity.DOWNLOAD_HIJACK))
|
||||
// 记录链接被劫持
|
||||
DataCollectionUtils.uploadHijack(mApplication, downloadEntity)
|
||||
// 上传劫持log
|
||||
DataLogUtils.uploadHijack(mApplication, downloadEntity)
|
||||
}
|
||||
|
||||
// 统计下载
|
||||
private fun uploadData(id: String, platform: String?) {
|
||||
val params = HashMap<String, String>()
|
||||
params["game"] = id
|
||||
params["platform"] = platform ?: ""
|
||||
val body = RequestBody.create(MediaType.parse("application/json"),
|
||||
JSONObject(params).toString())
|
||||
RetrofitManager.getInstance(mApplication).api.postDownload(body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(Response())
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,11 +4,15 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.gamecenter.MainActivity;
|
||||
import com.gh.gamecenter.NormalActivity;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
/**
|
||||
* @author CsHeng
|
||||
* @Date 2017/4/25
|
||||
@ -18,6 +22,7 @@ import com.gh.gamecenter.normal.NormalFragment;
|
||||
public class EntranceUtils {
|
||||
|
||||
public static final String KEY_TO = "to";
|
||||
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_ID = "id";
|
||||
@ -30,6 +35,7 @@ public class EntranceUtils {
|
||||
public static final String HOST_VIDEO_STREAMING_HOME = "video_streaming_home";//视频流-首页
|
||||
public static final String HOST_VIDEO_STREAMING_DESC = "video_streaming_desc";//视频流-游戏介绍进入
|
||||
public static final String HOST_VIDEO_COLLECTION = "video_collection";//视频合集
|
||||
public static final String HOST_USERHOME = "userhome";//个人主页
|
||||
public static final String HOST_VIDEO = "video";
|
||||
public static final String HOST_COMMUNITY_ARTICLE = "community_article";
|
||||
public static final String HOST_COMMUNITY_COLUMN = "community_column";
|
||||
@ -107,6 +113,7 @@ public class EntranceUtils {
|
||||
public static final String KEY_CATEGORY_INIT_TITLE = "category_init_title";
|
||||
public static final String KEY_BLOCK_DATA = "blockData";
|
||||
public static final String KEY_ASK_TAG = "askTag";
|
||||
public static final String KEY_SCROLL_TO_LIBAO = "libao";
|
||||
public static final String KEY_ASK_COLUMN_TAG = "askColumnTag";
|
||||
public static final String KEY_COMMUNITY_ID = "community_id";
|
||||
public static final String KEY_COMMUNITY_NAME = "community_name";
|
||||
@ -164,4 +171,33 @@ public class EntranceUtils {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void jumpActivity(Context context, Bundle nextToBundle, Bundle bundle, Callback callback) {
|
||||
|
||||
//TODO 把其他类似的跳转启动逻辑也处理掉
|
||||
if (RunningUtils.isRunning(context)
|
||||
&& MainActivity.class.getName().equals(RunningUtils.getBaseActivity(context))) {
|
||||
// 应用正在运行,前台或后台
|
||||
String to = bundle.getString(KEY_TO);
|
||||
Class<?> clazz = ClassUtils.forName(to);
|
||||
if (clazz == null) clazz = MainActivity.class;
|
||||
if (NormalFragment.class.isAssignableFrom(clazz)) { // 兼容NormalFragment
|
||||
NormalActivity.startFragmentNewTask(context, (Class<? extends NormalFragment>) clazz, bundle);
|
||||
} else {
|
||||
Intent intent1 = new Intent(context, clazz);
|
||||
//TODO:添加FLAG_ACTIVITY_NEW_TASK会导致一跳转页面callback就被调用
|
||||
//intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent1.putExtras(bundle);
|
||||
|
||||
AvoidOnResultManager.Companion.getInstance((AppCompatActivity) context)
|
||||
.startForResult(intent1, callback);
|
||||
}
|
||||
} else {
|
||||
// 应用未在运行
|
||||
if (nextToBundle != null) {
|
||||
bundle.putBundle(KEY_NEXT_TO, nextToBundle);
|
||||
}
|
||||
context.startActivity(SplashScreenActivity.getSplashScreenIntent(context, bundle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,10 @@ object ErrorHelper {
|
||||
customizedHandler: (code: Int) -> Boolean) {
|
||||
val errorEntity = errorString?.toObject<ErrorEntity>()
|
||||
|
||||
if (customizedHandler(errorEntity?.code ?: 0)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (errorEntity == null) {
|
||||
Utils.toast(context, R.string.post_failure_hint)
|
||||
return
|
||||
@ -33,11 +37,7 @@ object ErrorHelper {
|
||||
return
|
||||
}
|
||||
|
||||
if (customizedHandler(errorEntity.code ?: 0)) {
|
||||
return
|
||||
} else {
|
||||
handleError(context, showHighPriorityHint, errorEntity)
|
||||
}
|
||||
handleError(context, showHighPriorityHint, errorEntity)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,10 +115,11 @@ object ErrorHelper {
|
||||
403074 -> Utils.toast(context, "该微信号(${errorEntity.data?.nickname})已绑定")
|
||||
403078 -> Utils.toast(context, "已点赞")
|
||||
403072 -> Utils.toast(context, R.string.comment_failed_userblocked)
|
||||
403082 -> Utils.toast(context, "作者已关闭评论")
|
||||
|
||||
403020 -> if (showHighPriorityHint) {
|
||||
DialogUtils.showAlertDialog(context,
|
||||
"限制提醒",
|
||||
"提醒",
|
||||
"提问过于频繁,请先休息一下哦",
|
||||
"知道了", null, null, null)
|
||||
} else {
|
||||
|
||||
@ -13,6 +13,7 @@ import android.view.View
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
@ -222,6 +223,20 @@ inline fun tryWithDefaultCatch(action: (() -> Unit)) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 只在正式版本进行 try catch 操作
|
||||
*
|
||||
* 对于个别偶发的异常尽量不要做暴力的 try catch 处理
|
||||
*/
|
||||
inline fun tryCatchInRelease(action: (() -> Unit)) {
|
||||
try {
|
||||
action.invoke()
|
||||
} catch (e: Throwable) {
|
||||
if (BuildConfig.DEBUG) throw e
|
||||
else e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String related
|
||||
*/
|
||||
@ -390,7 +405,7 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) {
|
||||
fun TextView.setTextWithHighlightedTextWrappedInsideWrapper(text: CharSequence,
|
||||
wrapper: String = Constants.DEFAULT_TEXT_WRAPPER,
|
||||
@ColorRes
|
||||
highlightColorId: Int = R.color.theme,
|
||||
highlightColorId: Int = R.color.theme_font,
|
||||
copyClickedText: Boolean = false,
|
||||
highlightedTextClickListener: (() -> Unit)? = null) {
|
||||
TextHelper.highlightTextThatIsWrappedInsideWrapper(this, text, wrapper, highlightColorId, object : SimpleCallback<String> {
|
||||
@ -419,7 +434,7 @@ fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before
|
||||
}
|
||||
|
||||
fun Int.toColor(): Int {
|
||||
return HaloApp.getInstance().application.resources.getColor(this)
|
||||
return ContextCompat.getColor(HaloApp.getInstance().application, this)
|
||||
}
|
||||
|
||||
fun Int.toResString(): String {
|
||||
|
||||
@ -57,7 +57,7 @@ public class GameUtils {
|
||||
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_plugin_style);
|
||||
} else if ("打开".equals(status) || "启动".equals(status)) {
|
||||
downloadBtn.setBackgroundResource(R.drawable.detail_download_open_style);
|
||||
downloadBtn.setTextColor(ContextCompat.getColor(context, R.color.theme));
|
||||
downloadBtn.setTextColor(ContextCompat.getColor(context, R.color.theme_font));
|
||||
} else {
|
||||
downloadBtn.setBackgroundResource(R.drawable.game_item_btn_download_style);
|
||||
}
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import com.contrarywind.adapter.WheelAdapter;
|
||||
|
||||
/**
|
||||
* 注意:选择后的数据其实是dates的position,需要在回调时对返回的date数据进行转换
|
||||
*
|
||||
* 例子请见:
|
||||
* {@link com.gh.gamecenter.servers.add.AddKaiFuActivity}
|
||||
*/
|
||||
public class HaloWheelViewAdapter implements WheelAdapter {
|
||||
private int[] dates;
|
||||
|
||||
|
||||
public HaloWheelViewAdapter(int[] dates) {
|
||||
this.dates = dates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int index) {
|
||||
return dates[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemsCount() {
|
||||
return dates.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
try {
|
||||
return (int) o;
|
||||
} catch (Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,4 +32,39 @@ public class HtmlUtils {
|
||||
|
||||
return htmlStr.trim(); //返回文本字符串
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除html代码及文本
|
||||
*/
|
||||
public static String stripHtmlCode(String htmlStr) {
|
||||
if (TextUtils.isEmpty(htmlStr)) return "";
|
||||
|
||||
String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
|
||||
String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
|
||||
String regEx_html = "<[^>]+>[\\s\\S]*?<\\/[^>]+>"; //定义HTML标签的正则表达式
|
||||
String regEx_html_single = "<[^>]+>"; //定义HTML单标签的正则表达式
|
||||
String regEx_blank = "\\s+"; //定义空白字符的正则表达式
|
||||
|
||||
Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_script = p_script.matcher(htmlStr);
|
||||
htmlStr = m_script.replaceAll(""); //过滤script标签
|
||||
|
||||
Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_style = p_style.matcher(htmlStr);
|
||||
htmlStr = m_style.replaceAll(""); //过滤style标签
|
||||
|
||||
Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_html = p_html.matcher(htmlStr);
|
||||
htmlStr = m_html.replaceAll(""); //过滤html标签
|
||||
|
||||
Pattern p_html_single = Pattern.compile(regEx_html_single, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_html_single = p_html_single.matcher(htmlStr);
|
||||
htmlStr = m_html_single.replaceAll(""); //过滤html单标签
|
||||
|
||||
Pattern p_blank = Pattern.compile(regEx_blank, Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_blank = p_blank.matcher(htmlStr);
|
||||
htmlStr = m_blank.replaceAll(" ");//过滤空白字符
|
||||
|
||||
return htmlStr.trim(); //返回文本字符串
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,7 +236,7 @@ object ImageUtils {
|
||||
fun display(view: SimpleDraweeView?, url: String?) {
|
||||
url?.let {
|
||||
// 图片是以 gif 结尾的就
|
||||
if (it.endsWith(".gif")) {
|
||||
if (it.endsWith(".gif") && view?.getTag(R.id.tag_show_gif) != false) {
|
||||
if (view?.tag == url) return@let
|
||||
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
|
||||
@ -166,12 +166,12 @@ public class LibaoUtils {
|
||||
case "coming":
|
||||
libaoBtn.setText(R.string.libao_coming);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme));
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "used_up":
|
||||
libaoBtn.setText(R.string.libao_used_up);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme));
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "finish":
|
||||
libaoBtn.setText(R.string.libao_finish);
|
||||
@ -181,12 +181,12 @@ public class LibaoUtils {
|
||||
case "linged":
|
||||
libaoBtn.setText(R.string.libao_linged);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme));
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "taoed":
|
||||
libaoBtn.setText(R.string.libao_taoed);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme));
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "copy":
|
||||
libaoBtn.setText(R.string.libao_copy);
|
||||
@ -195,7 +195,7 @@ public class LibaoUtils {
|
||||
case "repeatLing":
|
||||
libaoBtn.setText(R.string.libao_repeat_ling);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme));
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "repeatLinged":
|
||||
libaoBtn.setText(R.string.libao_repeat_ling);
|
||||
@ -204,7 +204,7 @@ public class LibaoUtils {
|
||||
case "repeatTao":
|
||||
libaoBtn.setText(R.string.libao_repeat_tao);
|
||||
libaoBtn.setBackgroundResource(R.drawable.button_normal_border);
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme));
|
||||
libaoBtn.setTextColor(context.getResources().getColor(R.color.theme_font));
|
||||
break;
|
||||
case "repeatTaoed":
|
||||
libaoBtn.setText(R.string.libao_repeat_tao);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@ -264,8 +265,9 @@ public class PackageUtils {
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
|
||||
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
} else {
|
||||
if (isInAppUpdate) {
|
||||
// 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现
|
||||
// 应用内更新不加 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");
|
||||
|
||||
@ -4,10 +4,9 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.Handler;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.collection.ArrayMap;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.entity.PlatformEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
@ -30,6 +29,8 @@ import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
@ -153,7 +154,7 @@ public class PlatformUtils {
|
||||
}
|
||||
}
|
||||
if (urls.size() != 0) {
|
||||
HaloApp.getInstance().getMainExecutor().execute(new Runnable() {
|
||||
AppExecutor.getIoExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int success = 0;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
@ -9,6 +10,7 @@ import com.gh.gamecenter.retrofit.JSONObjectResponse;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.walkud.rom.checker.RomIdentifier;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -25,10 +27,23 @@ import retrofit2.HttpException;
|
||||
*/
|
||||
public class PostCommentUtils {
|
||||
|
||||
public static void addCommentData(final Context context, final String newsId, final String content,
|
||||
public static void addCommentData(final Context context, final String newsId, final JSONObject content,
|
||||
final CommentEntity commentEntity,
|
||||
final PostCommentListener listener) {
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content);
|
||||
|
||||
try {
|
||||
JSONObject device = new JSONObject();
|
||||
device.put("os", "Android");
|
||||
device.put("model", Build.MODEL);
|
||||
device.put("manufacturer", Build.MANUFACTURER);
|
||||
device.put("android_version", android.os.Build.VERSION.RELEASE);
|
||||
device.put("rom", RomIdentifier.getRom().name() + " " + RomIdentifier.getRom().getVersionName());
|
||||
content.put("device", device);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), content.toString());
|
||||
Observable<ResponseBody> observable;
|
||||
if (commentEntity != null) {
|
||||
observable = RetrofitManager.getInstance(context).getApi().postReplyComment(commentEntity.getId(), body);
|
||||
|
||||
@ -18,6 +18,7 @@ import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupWindow;
|
||||
@ -202,8 +203,13 @@ public class ShareUtils {
|
||||
popupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);
|
||||
//解决PopupWindow无法覆盖状态栏
|
||||
popupWindow.setClippingEnabled(false);
|
||||
|
||||
int bottomLocation = -DisplayUtils.retrieveNavigationHeight(activity);
|
||||
if (!DisplayUtils.isNavigationBarShow(activity)) {
|
||||
bottomLocation = 0;
|
||||
}
|
||||
try {
|
||||
popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
|
||||
popupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -268,8 +274,15 @@ public class ShareUtils {
|
||||
popupWindow = new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT
|
||||
, LinearLayout.LayoutParams.MATCH_PARENT, true);
|
||||
popupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);
|
||||
//解决PopupWindow无法覆盖状态栏
|
||||
popupWindow.setClippingEnabled(false);
|
||||
int bottomLocation = -DisplayUtils.retrieveNavigationHeight(activity);
|
||||
if (!DisplayUtils.isNavigationBarShow(activity)) {
|
||||
bottomLocation = 0;
|
||||
}
|
||||
try {
|
||||
popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
|
||||
// popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0);
|
||||
popupWindow.showAtLocation(view, Gravity.NO_GRAVITY, 0, bottomLocation);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Parcelable
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.gh.common.annotation.Synchronize
|
||||
import com.gh.common.util.SyncDataBetweenPageHelper.resultHandle
|
||||
import com.gh.common.util.SyncDataBetweenPageHelper.startActivityForResult
|
||||
@ -12,7 +13,7 @@ import com.gh.gamecenter.gamedetail.rating.RatingAdapter
|
||||
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
|
||||
/**
|
||||
* 页面之间实现数据同步
|
||||
* 页面之间实现数据同步(前提:页面之前拥有同一个数据实体)
|
||||
* 需要同步的数据,在相应的字段加上[Synchronize]注解,关键方法[resultHandle]
|
||||
* 如无特殊情况,尽量使用下面方法进行页面联动
|
||||
* 注意: [startActivityForResult] intent的数据实体key必须是Class的SimpleName
|
||||
@ -38,6 +39,12 @@ object SyncDataBetweenPageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
fun startActivityForResult(fragment: Fragment, intent: Intent, requestCode: Int, dataPosition: Int) {
|
||||
intent.putExtra(DATA_POSITION_TAG, dataPosition)
|
||||
intent.putExtra(REQUEST_CODE_TAG, requestCode)
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
|
||||
fun <T : Parcelable> setResultAndFinish(context: Context, syncData: T?, resultCode: Int = Activity.RESULT_OK): Boolean {
|
||||
if (context is Activity) {
|
||||
val requestCode = context.intent.getIntExtra(REQUEST_CODE_TAG, DEFAULT_NUMBER)
|
||||
|
||||
@ -91,8 +91,8 @@ object TextHelper {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun highlightTextThatIsWrappedInsideWrapperByDefault(textView: TextView, text: String) {
|
||||
textView.text = getHighlightedSpannableStringThatIsWrappedInsideWrapper(textView.context, text, "###", R.color.theme, object : SimpleCallback<String> {
|
||||
fun highlightTextThatIsWrappedInsideWrapperByDefault(textView: TextView, text: String?) {
|
||||
textView.text = getHighlightedSpannableStringThatIsWrappedInsideWrapper(textView.context, text ?: "", "###", R.color.theme_font, object : SimpleCallback<String> {
|
||||
override fun onCallback(arg: String) {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
@ -122,7 +122,7 @@ object TextHelper {
|
||||
text: CharSequence,
|
||||
wrapper: String = "###",
|
||||
@ColorRes
|
||||
highlightColorId: Int = R.color.theme,
|
||||
highlightColorId: Int = R.color.theme_font,
|
||||
highlightedTextClickListener: SimpleCallback<String>? = object : SimpleCallback<String> {
|
||||
override fun onCallback(arg: String) {
|
||||
val application = HaloApp.getInstance().application
|
||||
@ -193,7 +193,7 @@ object TextHelper {
|
||||
splits.forEachIndexed { index, s ->
|
||||
if (index != 0) {
|
||||
val item = "<tag>$s"
|
||||
val pattern = Pattern.compile("<tag>(\\S+)</tag>([\\S,\n]+)")
|
||||
val pattern = Pattern.compile("<tag>(\\S+)</tag>([\\S\\s\n]+)")
|
||||
val matcher = pattern.matcher(item)
|
||||
if (matcher.find()) {
|
||||
val label = matcher.group(1)
|
||||
|
||||
@ -30,6 +30,7 @@ public class TimestampUtils {
|
||||
intervalMap.put(".*games.*", 15);
|
||||
intervalMap.put(".*articles.*", 20);
|
||||
intervalMap.put(".*halo_addons.*", 10);
|
||||
intervalMap.put(".*packages.*", 1);
|
||||
}
|
||||
|
||||
private static void initCDMap() {
|
||||
@ -39,6 +40,7 @@ public class TimestampUtils {
|
||||
cdMap.put(".*games.*", Constants.GAME_CD);
|
||||
cdMap.put(".*articles.*", Constants.NEWS_CD);
|
||||
cdMap.put(".*halo_addons.*", Constants.ADDONS_CD);
|
||||
cdMap.put(".*packages.*", Constants.PACKAGES_CD);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -12,6 +12,7 @@ import android.view.animation.Animation;
|
||||
import android.view.animation.CycleInterpolator;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
|
||||
@ -49,7 +50,8 @@ public class ClearEditTextNormal extends androidx.appcompat.widget.AppCompatEdit
|
||||
mClearDrawable = getResources().getDrawable(R.drawable.icon_close);
|
||||
}
|
||||
|
||||
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
|
||||
// mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
|
||||
mClearDrawable.setBounds(0, 0, DisplayUtils.dip2px(16), DisplayUtils.dip2px(16));
|
||||
//默认设置隐藏图标
|
||||
setClearIconVisible(false);
|
||||
//设置焦点改变的监听
|
||||
|
||||
@ -92,7 +92,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
super.onDraw(canvas);
|
||||
if (TextUtils.isEmpty(mText)) return;
|
||||
|
||||
mPaint.setColor(mDefaultColor == 0 ? ContextCompat.getColor(getContext(), R.color.theme) : mDefaultColor); // 初始化颜色
|
||||
mPaint.setColor(mDefaultColor == 0 ? ContextCompat.getColor(getContext(), R.color.theme_font) : mDefaultColor); // 初始化颜色
|
||||
mPaint.setTextSize(mTextSize);
|
||||
mFakeTextPaint.setTextSize(mTextSize);
|
||||
mFakeTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
@ -116,7 +116,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
if (DOWNLOAD_IMAGE_STYLE == mDownloadStyle) {
|
||||
color = Color.BLACK;
|
||||
} else if (DOWNLOAD_SLIDE_STYLE == mDownloadStyle) {
|
||||
color = getResources().getColor(R.color.theme);
|
||||
color = getResources().getColor(R.color.theme_font);
|
||||
}
|
||||
mPaint.setColor(color); // 反向颜色
|
||||
}
|
||||
@ -200,7 +200,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
switch (mDownloadStyle) {
|
||||
case DOWNLOAD_RECT_STYLE:
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_rect_style));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme);
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
|
||||
break;
|
||||
case DOWNLOAD_IMAGE_STYLE:
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_image_style));
|
||||
@ -208,7 +208,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
break;
|
||||
default:
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.detail_download_open_style));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme);
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
|
||||
break;
|
||||
}
|
||||
setProgress(0);
|
||||
@ -217,7 +217,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
switch (mDownloadStyle) {
|
||||
case DOWNLOAD_RECT_STYLE:
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_rect_style));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme);
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
|
||||
break;
|
||||
case DOWNLOAD_IMAGE_STYLE:
|
||||
case DOWNLOAD_SLIDE_STYLE:
|
||||
@ -226,7 +226,7 @@ public class DownloadProgressBar extends ProgressBar {
|
||||
break;
|
||||
default:
|
||||
setProgressDrawable(getResources().getDrawable(R.drawable.detail_downloading_normal_style));
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme);
|
||||
mDefaultColor = ContextCompat.getColor(getContext(), R.color.theme_font);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
|
||||
@ -16,6 +20,7 @@ class EllipsizeTextView : AppCompatTextView {
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
@SuppressLint("DrawAllocation")
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
if (lineCount > maxLines) {
|
||||
@ -30,7 +35,7 @@ class EllipsizeTextView : AppCompatTextView {
|
||||
val cutWidth = paint.measureText(text.subSequence(secondLastLineEnd, lastLineEnd - i).toString() + "...")
|
||||
if (cutWidth <= layout.width) {
|
||||
charSequence = text.subSequence(0, lastLineEnd - i)
|
||||
text = "$charSequence..."
|
||||
text = SpannableStringBuilder().append(charSequence).append("...")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
592
app/src/main/java/com/gh/common/view/ExpandAndCloseTextView.java
Normal file
592
app/src/main/java/com/gh/common/view/ExpandAndCloseTextView.java
Normal file
@ -0,0 +1,592 @@
|
||||
package com.gh.common.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.AlignmentSpan;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 参考: https://github.com/MrTrying/ExpandableText-Example
|
||||
* <p>
|
||||
* todo 辣鸡代码,有时间移除并在 {@link ExpandTextView} 实现该功能
|
||||
*/
|
||||
public class ExpandAndCloseTextView extends AppCompatTextView {
|
||||
|
||||
public static final String ELLIPSIS_STRING = new String(new char[]{'\u2026'});
|
||||
private static final int DEFAULT_MAX_LINE = 3;
|
||||
private static final String DEFAULT_OPEN_SUFFIX = " 展开";
|
||||
private static final String DEFAULT_CLOSE_SUFFIX = " 收起";
|
||||
volatile boolean animating = false;
|
||||
boolean isClosed = false;
|
||||
private int mMaxLines = DEFAULT_MAX_LINE;
|
||||
/**
|
||||
* TextView可展示宽度,包含paddingLeft和paddingRight
|
||||
*/
|
||||
private int initWidth = 0;
|
||||
/**
|
||||
* 原始文本
|
||||
*/
|
||||
private CharSequence originalText;
|
||||
|
||||
private SpannableStringBuilder mOpenSpannableStr, mCloseSpannableStr;
|
||||
|
||||
private boolean hasAnimation = false;
|
||||
private Animation mOpenAnim, mCloseAnim;
|
||||
private int mOpenHeight, mCLoseHeight;
|
||||
private boolean mExpandable;
|
||||
private boolean mCloseInNewLine;
|
||||
@Nullable
|
||||
private SpannableString mOpenSuffixSpan, mCloseSuffixSpan;
|
||||
private String mOpenSuffixStr = DEFAULT_OPEN_SUFFIX;
|
||||
private String mCloseSuffixStr = DEFAULT_CLOSE_SUFFIX;
|
||||
private int mOpenSuffixColor, mCloseSuffixColor;
|
||||
|
||||
private View.OnClickListener mOnClickListener;
|
||||
|
||||
private CharSequenceToSpannableHandler mCharSequenceToSpannableHandler;
|
||||
|
||||
public ExpandAndCloseTextView(Context context) {
|
||||
super(context);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public ExpandAndCloseTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public ExpandAndCloseTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
private void initialize() {
|
||||
mOpenSuffixColor = mCloseSuffixColor = getResources().getColor( R.color.theme_font);
|
||||
setMovementMethod(CustomLinkMovementMethod.getInstance());
|
||||
setIncludeFontPadding(false);
|
||||
updateOpenSuffixSpan();
|
||||
updateCloseSuffixSpan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setOriginalText(CharSequence originalText) {
|
||||
this.originalText = originalText;
|
||||
mExpandable = false;
|
||||
mCloseSpannableStr = new SpannableStringBuilder();
|
||||
final int maxLines = mMaxLines;
|
||||
SpannableStringBuilder tempText = charSequenceToSpannable(originalText);
|
||||
mOpenSpannableStr = charSequenceToSpannable(originalText);
|
||||
|
||||
if (maxLines != -1) {
|
||||
Layout layout = createStaticLayout(tempText);
|
||||
mExpandable = layout.getLineCount() > maxLines;
|
||||
if (mExpandable) {
|
||||
//拼接展开内容
|
||||
if (mCloseInNewLine) {
|
||||
mOpenSpannableStr.append("\n");
|
||||
}
|
||||
if (mCloseSuffixSpan != null) {
|
||||
mOpenSpannableStr = new SpannableStringBuilder(autoSplitText(mOpenSpannableStr.toString()));
|
||||
mOpenSpannableStr.append(mCloseSuffixSpan);
|
||||
}
|
||||
//计算原文截取位置
|
||||
int endPos = layout.getLineEnd(maxLines - 1);
|
||||
if (originalText.length() <= endPos) {
|
||||
mCloseSpannableStr = charSequenceToSpannable(originalText);
|
||||
} else {
|
||||
mCloseSpannableStr = charSequenceToSpannable(originalText.subSequence(0, endPos));
|
||||
}
|
||||
SpannableStringBuilder tempText2 = charSequenceToSpannable(mCloseSpannableStr).append(ELLIPSIS_STRING);
|
||||
if (mOpenSuffixSpan != null) {
|
||||
tempText2.append(mOpenSuffixSpan);
|
||||
}
|
||||
//循环判断,收起内容添加展开后缀后的内容
|
||||
Layout tempLayout = createStaticLayout(tempText2);
|
||||
while (tempLayout.getLineCount() > maxLines) {
|
||||
int lastSpace = mCloseSpannableStr.length() - 1;
|
||||
if (lastSpace == -1) {
|
||||
break;
|
||||
}
|
||||
if (originalText.length() <= lastSpace) {
|
||||
mCloseSpannableStr = charSequenceToSpannable(originalText);
|
||||
} else {
|
||||
mCloseSpannableStr = charSequenceToSpannable(originalText.subSequence(0, lastSpace));
|
||||
}
|
||||
tempText2 = charSequenceToSpannable(mCloseSpannableStr).append(ELLIPSIS_STRING);
|
||||
if (mOpenSuffixSpan != null) {
|
||||
tempText2.append(mOpenSuffixSpan);
|
||||
}
|
||||
tempLayout = createStaticLayout(tempText2);
|
||||
|
||||
}
|
||||
int lastSpace = mCloseSpannableStr.length() - mOpenSuffixSpan.length();
|
||||
if (lastSpace >= 0 && originalText.length() > lastSpace) {
|
||||
CharSequence redundantChar = originalText.subSequence(lastSpace, lastSpace + mOpenSuffixSpan.length());
|
||||
int offset = hasEnCharCount(redundantChar) - hasEnCharCount(mOpenSuffixSpan) + 1;
|
||||
lastSpace = offset <= 0 ? lastSpace : lastSpace - offset;
|
||||
mCloseSpannableStr = charSequenceToSpannable(originalText.subSequence(0, lastSpace));
|
||||
}
|
||||
//计算收起的文本高度
|
||||
mCLoseHeight = tempLayout.getHeight() + getPaddingTop() + getPaddingBottom();
|
||||
|
||||
mCloseSpannableStr.append(ELLIPSIS_STRING);
|
||||
|
||||
mCloseSpannableStr = new SpannableStringBuilder(autoSplitText(mCloseSpannableStr.toString()));
|
||||
if (mOpenSuffixSpan != null) {
|
||||
mCloseSpannableStr.append(mOpenSuffixSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
isClosed = mExpandable;
|
||||
if (mExpandable) {
|
||||
setText(mCloseSpannableStr);
|
||||
//设置监听
|
||||
super.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// switchOpenClose();
|
||||
// if (mOnClickListener != null) {
|
||||
// mOnClickListener.onClick(v);
|
||||
// }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setText(mOpenSpannableStr);
|
||||
}
|
||||
}
|
||||
|
||||
private int hasEnCharCount(CharSequence str) {
|
||||
int count = 0;
|
||||
if (!TextUtils.isEmpty(str)) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
if (c >= ' ' && c <= '~') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void switchOpenClose() {
|
||||
if (mExpandable) {
|
||||
isClosed = !isClosed;
|
||||
if (isClosed) {
|
||||
close();
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否有动画
|
||||
*
|
||||
* @param hasAnimation
|
||||
*/
|
||||
public void setHasAnimation(boolean hasAnimation) {
|
||||
this.hasAnimation = hasAnimation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开
|
||||
*/
|
||||
private void open() {
|
||||
if (hasAnimation) {
|
||||
Layout layout = createStaticLayout(mOpenSpannableStr);
|
||||
mOpenHeight = layout.getHeight() + getPaddingTop() + getPaddingBottom();
|
||||
executeOpenAnim();
|
||||
} else {
|
||||
ExpandAndCloseTextView.super.setMaxLines(Integer.MAX_VALUE);
|
||||
setText(mOpenSpannableStr);
|
||||
if (mOpenCloseCallback != null) {
|
||||
mOpenCloseCallback.onOpen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收起
|
||||
*/
|
||||
private void close() {
|
||||
if (hasAnimation) {
|
||||
executeCloseAnim();
|
||||
} else {
|
||||
ExpandAndCloseTextView.super.setMaxLines(mMaxLines);
|
||||
setText(mCloseSpannableStr);
|
||||
if (mOpenCloseCallback != null) {
|
||||
mOpenCloseCallback.onClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行展开动画
|
||||
*/
|
||||
private void executeOpenAnim() {
|
||||
//创建展开动画
|
||||
if (mOpenAnim == null) {
|
||||
mOpenAnim = new ExpandCollapseAnimation(this, mCLoseHeight, mOpenHeight);
|
||||
mOpenAnim.setFillAfter(true);
|
||||
mOpenAnim.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
ExpandAndCloseTextView.super.setMaxLines(Integer.MAX_VALUE);
|
||||
setText(mOpenSpannableStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
// 动画结束后textview设置展开的状态
|
||||
getLayoutParams().height = mOpenHeight;
|
||||
requestLayout();
|
||||
animating = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (animating) {
|
||||
return;
|
||||
}
|
||||
animating = true;
|
||||
clearAnimation();
|
||||
// 执行动画
|
||||
startAnimation(mOpenAnim);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行收起动画
|
||||
*/
|
||||
private void executeCloseAnim() {
|
||||
//创建收起动画
|
||||
if (mCloseAnim == null) {
|
||||
mCloseAnim = new ExpandCollapseAnimation(this, mOpenHeight, mCLoseHeight);
|
||||
mCloseAnim.setFillAfter(true);
|
||||
mCloseAnim.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
animating = false;
|
||||
ExpandAndCloseTextView.super.setMaxLines(mMaxLines);
|
||||
setText(mCloseSpannableStr);
|
||||
getLayoutParams().height = mCLoseHeight;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (animating) {
|
||||
return;
|
||||
}
|
||||
animating = true;
|
||||
clearAnimation();
|
||||
// 执行动画
|
||||
startAnimation(mCloseAnim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spannable
|
||||
* @return
|
||||
*/
|
||||
private Layout createStaticLayout(SpannableStringBuilder spannable) {
|
||||
int contentWidth = initWidth - getPaddingLeft() - getPaddingRight();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
StaticLayout.Builder builder = StaticLayout.Builder.obtain(spannable, 0, spannable.length(), getPaint(), contentWidth);
|
||||
builder.setAlignment(Layout.Alignment.ALIGN_NORMAL);
|
||||
builder.setIncludePad(getIncludeFontPadding());
|
||||
builder.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier());
|
||||
return builder.build();
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
return new StaticLayout(spannable, getPaint(), contentWidth, Layout.Alignment.ALIGN_NORMAL,
|
||||
getLineSpacingMultiplier(), getLineSpacingExtra(), getIncludeFontPadding());
|
||||
} else {
|
||||
return new StaticLayout(spannable, getPaint(), contentWidth, Layout.Alignment.ALIGN_NORMAL,
|
||||
getFloatField("mSpacingMult", 1f), getFloatField("mSpacingAdd", 0f), getIncludeFontPadding());
|
||||
}
|
||||
}
|
||||
|
||||
private float getFloatField(String fieldName, float defaultValue) {
|
||||
float value = defaultValue;
|
||||
if (TextUtils.isEmpty(fieldName)) {
|
||||
return value;
|
||||
}
|
||||
try {
|
||||
// 获取该类的所有属性值域
|
||||
Field[] fields = this.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (TextUtils.equals(fieldName, field.getName())) {
|
||||
value = field.getFloat(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param charSequence
|
||||
* @return
|
||||
*/
|
||||
private SpannableStringBuilder charSequenceToSpannable(@NonNull CharSequence charSequence) {
|
||||
SpannableStringBuilder spannableStringBuilder = null;
|
||||
if (mCharSequenceToSpannableHandler != null) {
|
||||
spannableStringBuilder = mCharSequenceToSpannableHandler.charSequenceToSpannable(charSequence);
|
||||
}
|
||||
if (spannableStringBuilder == null) {
|
||||
spannableStringBuilder = new SpannableStringBuilder(charSequence);
|
||||
}
|
||||
return spannableStringBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化TextView的可展示宽度
|
||||
*
|
||||
* @param width
|
||||
*/
|
||||
public void initWidth(int width) {
|
||||
initWidth = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxLines(int maxLines) {
|
||||
this.mMaxLines = maxLines;
|
||||
super.setMaxLines(maxLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置展开后缀text
|
||||
*
|
||||
* @param openSuffix
|
||||
*/
|
||||
public void setOpenSuffix(String openSuffix) {
|
||||
mOpenSuffixStr = openSuffix;
|
||||
updateOpenSuffixSpan();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置展开后缀文本颜色
|
||||
*
|
||||
* @param openSuffixColor
|
||||
*/
|
||||
public void setOpenSuffixColor(@ColorInt int openSuffixColor) {
|
||||
mOpenSuffixColor = openSuffixColor;
|
||||
updateOpenSuffixSpan();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置收起后缀text
|
||||
*
|
||||
* @param closeSuffix
|
||||
*/
|
||||
public void setCloseSuffix(String closeSuffix) {
|
||||
mCloseSuffixStr = closeSuffix;
|
||||
updateCloseSuffixSpan();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置收起后缀文本颜色
|
||||
*
|
||||
* @param closeSuffixColor
|
||||
*/
|
||||
public void setCloseSuffixColor(@ColorInt int closeSuffixColor) {
|
||||
mCloseSuffixColor = closeSuffixColor;
|
||||
updateCloseSuffixSpan();
|
||||
}
|
||||
|
||||
/**
|
||||
* 收起后缀是否另起一行
|
||||
*
|
||||
* @param closeInNewLine
|
||||
*/
|
||||
public void setCloseInNewLine(boolean closeInNewLine) {
|
||||
mCloseInNewLine = closeInNewLine;
|
||||
updateCloseSuffixSpan();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新展开后缀Spannable
|
||||
*/
|
||||
private void updateOpenSuffixSpan() {
|
||||
if (TextUtils.isEmpty(mOpenSuffixStr)) {
|
||||
mOpenSuffixSpan = null;
|
||||
return;
|
||||
}
|
||||
mOpenSuffixSpan = new SpannableString(mOpenSuffixStr);
|
||||
mOpenSuffixSpan.setSpan(new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
switchOpenClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(mOpenSuffixColor);
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
}, 0, mOpenSuffixStr.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新收起后缀Spannable
|
||||
*/
|
||||
private void updateCloseSuffixSpan() {
|
||||
if (TextUtils.isEmpty(mCloseSuffixStr)) {
|
||||
mCloseSuffixSpan = null;
|
||||
return;
|
||||
}
|
||||
mCloseSuffixSpan = new SpannableString(mCloseSuffixStr);
|
||||
if (mCloseInNewLine) {
|
||||
AlignmentSpan alignmentSpan = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE);
|
||||
mCloseSuffixSpan.setSpan(alignmentSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
mCloseSuffixSpan.setSpan(new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
switchOpenClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(mCloseSuffixColor);
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
}, 1, mCloseSuffixStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
private String autoSplitText(final String rawText) {
|
||||
final Paint tvPaint = getPaint(); //paint,包含字体等信息
|
||||
final float tvWidth = initWidth - getPaddingLeft() - getPaddingRight(); //控件可用宽度
|
||||
|
||||
//将原始文本按行拆分
|
||||
String[] rawTextLines = rawText.replaceAll("\r", "").split("\n");
|
||||
StringBuilder sbNewText = new StringBuilder();
|
||||
for (String rawTextLine : rawTextLines) {
|
||||
if (tvPaint.measureText(rawTextLine) <= tvWidth) {
|
||||
//如果整行宽度在控件可用宽度之内,就不处理了
|
||||
sbNewText.append(rawTextLine);
|
||||
} else {
|
||||
//如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行
|
||||
float lineWidth = 0;
|
||||
for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {
|
||||
char ch = rawTextLine.charAt(cnt);
|
||||
lineWidth += tvPaint.measureText(String.valueOf(ch));
|
||||
if (lineWidth <= tvWidth) {
|
||||
sbNewText.append(ch);
|
||||
} else {
|
||||
sbNewText.append("\n");
|
||||
lineWidth = 0;
|
||||
--cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
sbNewText.append("\n");
|
||||
}
|
||||
|
||||
//把结尾多余的\n去掉
|
||||
if (!rawText.endsWith("\n")) {
|
||||
sbNewText.deleteCharAt(sbNewText.length() - 1);
|
||||
}
|
||||
|
||||
return sbNewText.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClickListener(View.OnClickListener onClickListener) {
|
||||
mOnClickListener = onClickListener;
|
||||
}
|
||||
|
||||
public OpenAndCloseCallback mOpenCloseCallback;
|
||||
|
||||
public void setOpenAndCloseCallback(OpenAndCloseCallback callback) {
|
||||
this.mOpenCloseCallback = callback;
|
||||
}
|
||||
|
||||
public interface OpenAndCloseCallback {
|
||||
void onOpen();
|
||||
|
||||
void onClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文本内容处理
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setCharSequenceToSpannableHandler(CharSequenceToSpannableHandler handler) {
|
||||
mCharSequenceToSpannableHandler = handler;
|
||||
}
|
||||
|
||||
public interface CharSequenceToSpannableHandler {
|
||||
@NonNull
|
||||
SpannableStringBuilder charSequenceToSpannable(CharSequence charSequence);
|
||||
}
|
||||
|
||||
class ExpandCollapseAnimation extends Animation {
|
||||
private final View mTargetView;//动画执行view
|
||||
private final int mStartHeight;//动画执行的开始高度
|
||||
private final int mEndHeight;//动画结束后的高度
|
||||
|
||||
ExpandCollapseAnimation(View target, int startHeight, int endHeight) {
|
||||
mTargetView = target;
|
||||
mStartHeight = startHeight;
|
||||
mEndHeight = endHeight;
|
||||
setDuration(400);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
mTargetView.setScrollY(0);
|
||||
//计算出每次应该显示的高度,改变执行view的高度,实现动画
|
||||
mTargetView.getLayoutParams().height = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
|
||||
mTargetView.requestLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import androidx.core.content.ContextCompat;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
public class ExpendTextView extends AppCompatTextView {
|
||||
public class ExpandTextView extends AppCompatTextView {
|
||||
|
||||
private CharSequence mSnapshotText;
|
||||
|
||||
@ -31,11 +31,11 @@ public class ExpendTextView extends AppCompatTextView {
|
||||
|
||||
private ExpandCallback mExpandCallback;
|
||||
|
||||
public ExpendTextView(Context context) {
|
||||
public ExpandTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ExpendTextView(Context context, AttributeSet attrs) {
|
||||
public ExpandTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
mMaxLines = getMaxLines();
|
||||
@ -100,7 +100,7 @@ public class ExpendTextView extends AppCompatTextView {
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(ContextCompat.getColor(getContext(), R.color.theme));
|
||||
ds.setColor(ContextCompat.getColor(getContext(), R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ class HighlightableTextView @JvmOverloads constructor(context: Context, attrs: A
|
||||
}
|
||||
|
||||
override fun setText(text: CharSequence?, type: BufferType?) {
|
||||
super.setText(TextHelper.getHighlightedSpannableStringThatIsWrappedInsideWrapper(context, text.toString(), "###", R.color.theme, object : SimpleCallback<String> {
|
||||
super.setText(TextHelper.getHighlightedSpannableStringThatIsWrappedInsideWrapper(context, text.toString(), "###", R.color.theme_font, object : SimpleCallback<String> {
|
||||
override fun onCallback(arg: String) {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
114
app/src/main/java/com/gh/common/view/LikeView.kt
Normal file
114
app/src/main/java/com/gh/common/view/LikeView.kt
Normal file
@ -0,0 +1,114 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.animation.*
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.gh.gamecenter.R
|
||||
import java.util.*
|
||||
|
||||
class LikeView : RelativeLayout {
|
||||
|
||||
private val num = floatArrayOf(-35f, -25f, -15f, 0f, 15f, 25f, 35f)
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
fun runLikeAnimation(event: MotionEvent) {
|
||||
val iv = ImageView(context)
|
||||
val lp = LayoutParams(168, 150)
|
||||
val widthPixels = context.resources.displayMetrics.widthPixels
|
||||
val leftMargin = if (event.rawX.toInt() + 84 > widthPixels) {
|
||||
widthPixels - 168
|
||||
} else {
|
||||
event.rawX.toInt() - 84
|
||||
}
|
||||
lp.leftMargin = leftMargin
|
||||
lp.topMargin = event.rawY.toInt() - 220
|
||||
iv.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_double_click_like))
|
||||
iv.layoutParams = lp
|
||||
|
||||
addView(iv)
|
||||
|
||||
val animatorSet = AnimatorSet()
|
||||
animatorSet.play(
|
||||
scaleAni(iv, "scaleX", 1f, 2f, 50, 0))
|
||||
.with(scaleAni(iv, "scaleY", 1f, 2f, 50, 0))
|
||||
//缩放动画,X轴2倍缩小至0.9倍
|
||||
.with(scaleAni(iv, "scaleX", 2f, 0.9f, 100, 50))
|
||||
//缩放动画,Y轴2倍缩放至0.9倍
|
||||
.with(scaleAni(iv, "scaleY", 2f, 0.9f, 100, 50))
|
||||
//旋转动画,随机旋转角
|
||||
.with(rotation(iv, 0, 0, num[Random().nextInt(6)]))
|
||||
//渐变透明动画,透明度从0-1
|
||||
.with(alphaAni(iv, 0F, 1F, 100, 0))
|
||||
//缩放动画,X轴0.9倍缩小至
|
||||
.with(scaleAni(iv, "scaleX", 0.9f, 1F, 50, 150))
|
||||
//缩放动画,Y轴0.9倍缩放至
|
||||
.with(scaleAni(iv, "scaleY", 0.9f, 1F, 50, 150))
|
||||
//位移动画,Y轴从0上移至600
|
||||
.with(translationY(iv, 0F, -800F, 1200, 400))
|
||||
//透明动画,从1-0
|
||||
.with(alphaAni(iv, 1F, 0F, 500, 400))
|
||||
//缩放动画,X轴1至3倍
|
||||
.with(scaleAni(iv, "scaleX", 1F, 3f, 800, 400))
|
||||
//缩放动画,Y轴1至3倍
|
||||
.with(scaleAni(iv, "scaleY", 1F, 3f, 800, 400))
|
||||
|
||||
|
||||
animatorSet.start()
|
||||
animatorSet.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
super.onAnimationEnd(animation)
|
||||
removeViewInLayout(iv)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
private fun scaleAni(view: View, propertyName: String, from: Float, to: Float, time: Long, delayTime: Long): ObjectAnimator {
|
||||
val ani: ObjectAnimator = ObjectAnimator.ofFloat(view, propertyName, from, to)
|
||||
ani.interpolator = LinearInterpolator()
|
||||
ani.startDelay = delayTime
|
||||
ani.duration = time
|
||||
return ani
|
||||
}
|
||||
|
||||
private fun translationX(view: View, from: Float, to: Float, time: Long, delayTime: Long): ObjectAnimator {
|
||||
val ani: ObjectAnimator = ObjectAnimator.ofFloat(view, "translationX", from, to)
|
||||
ani.interpolator = LinearInterpolator()
|
||||
ani.startDelay = delayTime
|
||||
ani.duration = time
|
||||
return ani
|
||||
}
|
||||
|
||||
private fun translationY(view: View, from: Float, to: Float, time: Long, delayTime: Long): ObjectAnimator {
|
||||
val ani: ObjectAnimator = ObjectAnimator.ofFloat(view, "translationY", from, to)
|
||||
ani.interpolator = LinearInterpolator()
|
||||
ani.startDelay = delayTime
|
||||
ani.duration = time
|
||||
return ani
|
||||
}
|
||||
|
||||
private fun alphaAni(view: View, from: Float, to: Float, time: Long, delayTime: Long): ObjectAnimator {
|
||||
val ani = ObjectAnimator.ofFloat(view, "alpha", from, to)
|
||||
ani.interpolator = LinearInterpolator()
|
||||
ani.startDelay = delayTime
|
||||
ani.duration = time
|
||||
return ani
|
||||
}
|
||||
|
||||
private fun rotation(view: View, time: Long, delayTime: Long, vararg values: Float): ObjectAnimator {
|
||||
val ani = ObjectAnimator.ofFloat(view, "rotation", *values)
|
||||
ani.duration = time
|
||||
ani.startDelay = delayTime
|
||||
ani.interpolator = TimeInterpolator { input -> input }
|
||||
return ani
|
||||
}
|
||||
}
|
||||
161
app/src/main/java/com/gh/common/view/NestedScrollRichEditor.java
Normal file
161
app/src/main/java/com/gh/common/view/NestedScrollRichEditor.java
Normal file
@ -0,0 +1,161 @@
|
||||
package com.gh.common.view;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.core.view.MotionEventCompat;
|
||||
import androidx.core.view.NestedScrollingChild;
|
||||
import androidx.core.view.NestedScrollingChildHelper;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
public class NestedScrollRichEditor extends RichEditor implements NestedScrollingChild {
|
||||
|
||||
public static final String TAG = NestedScrollRichEditor.class.getSimpleName();
|
||||
|
||||
private int mLastMotionY;
|
||||
|
||||
private final int[] mScrollOffset = new int[2];
|
||||
private final int[] mScrollConsumed = new int[2];
|
||||
|
||||
private int mNestedYOffset;
|
||||
private boolean mChange;
|
||||
|
||||
private NestedScrollingChildHelper mChildHelper;
|
||||
|
||||
public NestedScrollRichEditor(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public NestedScrollRichEditor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public NestedScrollRichEditor(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mChildHelper = new NestedScrollingChildHelper(this);
|
||||
setNestedScrollingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
boolean result = false;
|
||||
|
||||
MotionEvent trackedEvent = MotionEvent.obtain(event);
|
||||
|
||||
final int action = MotionEventCompat.getActionMasked(event);
|
||||
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
mNestedYOffset = 0;
|
||||
}
|
||||
|
||||
int y = (int) event.getY();
|
||||
|
||||
event.offsetLocation(0, mNestedYOffset);
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mLastMotionY = y;
|
||||
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
|
||||
result = super.onTouchEvent(event);
|
||||
mChange = false;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int deltaY = mLastMotionY - y;
|
||||
|
||||
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
|
||||
deltaY -= mScrollConsumed[1];
|
||||
trackedEvent.offsetLocation(0, mScrollOffset[1]);
|
||||
mNestedYOffset += mScrollOffset[1];
|
||||
}
|
||||
|
||||
int oldY = getScrollY();
|
||||
mLastMotionY = y - mScrollOffset[1];
|
||||
int newScrollY = Math.max(0, oldY + deltaY);
|
||||
deltaY -= newScrollY - oldY;
|
||||
if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
|
||||
mLastMotionY -= mScrollOffset[1];
|
||||
trackedEvent.offsetLocation(0, mScrollOffset[1]);
|
||||
mNestedYOffset += mScrollOffset[1];
|
||||
}
|
||||
if(mScrollConsumed[1]==0 && mScrollOffset[1]==0) {
|
||||
if(mChange){
|
||||
mChange =false;
|
||||
trackedEvent.setAction(MotionEvent.ACTION_DOWN);
|
||||
super.onTouchEvent(trackedEvent);
|
||||
}else {
|
||||
result = super.onTouchEvent(trackedEvent);
|
||||
}
|
||||
trackedEvent.recycle();
|
||||
}else{
|
||||
if(Math.abs(mLastMotionY - y) >= 10) {
|
||||
if (!mChange) {
|
||||
mChange = true;
|
||||
super.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
stopNestedScroll();
|
||||
result = super.onTouchEvent(event);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NestedScrollingChild
|
||||
@Override
|
||||
public void setNestedScrollingEnabled(boolean enabled) {
|
||||
mChildHelper.setNestedScrollingEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNestedScrollingEnabled() {
|
||||
return mChildHelper.isNestedScrollingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startNestedScroll(int axes) {
|
||||
return mChildHelper.startNestedScroll(axes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopNestedScroll() {
|
||||
mChildHelper.stopNestedScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNestedScrollingParent() {
|
||||
return mChildHelper.hasNestedScrollingParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
|
||||
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
|
||||
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
|
||||
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
|
||||
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
|
||||
}
|
||||
|
||||
}
|
||||
@ -26,18 +26,27 @@ class RoundStrokeBackgroundColorSpan(private val strokeColor: Int,
|
||||
|
||||
override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
|
||||
val originalColor = paint.color
|
||||
val originalTextSize = paint.textSize
|
||||
|
||||
paint.color = this.strokeColor
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = strokeWidth.toFloat()
|
||||
|
||||
val fontMetrics = paint.fontMetrics
|
||||
|
||||
// 当目标字体大小与原字体大小不一样时,需要先用目标字体大小测量字体宽度
|
||||
if (textSize != 0) {
|
||||
paint.textSize = textSize.toFloat()
|
||||
}
|
||||
val fontMetrics = paint.fontMetrics
|
||||
val textWidth = paint.measureText(text, start, end).toInt()
|
||||
|
||||
// 用原字体大小画椭圆
|
||||
paint.textSize = originalTextSize
|
||||
canvas.drawRoundRect(RectF(
|
||||
x + halfStrokeWidth,
|
||||
top.toFloat() + halfStrokeWidth,
|
||||
x + halfStrokeWidth + paint.measureText(text, start, end).toInt(),
|
||||
top + fontMetrics.bottom - fontMetrics.top + strokeWidth * 2 - halfStrokeWidth),
|
||||
x + textWidth + halfStrokeWidth,
|
||||
top + fontMetrics.bottom - fontMetrics.top),
|
||||
DisplayUtils.dip2px(HaloApp.getInstance().application, 3f).toFloat(),
|
||||
DisplayUtils.dip2px(HaloApp.getInstance().application, 3f).toFloat(),
|
||||
paint)
|
||||
@ -45,6 +54,11 @@ class RoundStrokeBackgroundColorSpan(private val strokeColor: Int,
|
||||
paint.color = this.textColor
|
||||
paint.style = Paint.Style.FILL
|
||||
paint.strokeWidth = 0f
|
||||
|
||||
// 用目标字体大小画字
|
||||
if (textSize != 0) {
|
||||
paint.textSize = textSize.toFloat()
|
||||
}
|
||||
canvas.drawText(text, start, end, x + halfStrokeWidth, y.toFloat() - strokeWidth, paint)
|
||||
|
||||
paint.color = originalColor
|
||||
|
||||
@ -2,15 +2,31 @@ package com.gh.common.view
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import androidx.annotation.Dimension
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
/**
|
||||
* 简单的 recyclerView Item 装饰类
|
||||
*
|
||||
* @param onlyDecorateTheFirstItem 只装饰第一个 item
|
||||
* @param notDecorateTheFirstItem 不装饰第一个 item
|
||||
* @param notDecorateTheLastItem 不装饰最后一个 item
|
||||
* @param notDecorateTheFirstTwoItems 不装饰前两个 item
|
||||
*
|
||||
* left, top ,right, bottom 分别是四边
|
||||
*/
|
||||
class SpacingItemDecoration(
|
||||
var onlyDecorateTheFirstItem: Boolean = false,
|
||||
var notDecorateTheFirstItem: Boolean = false,
|
||||
var notDecorateTheLastItem: Boolean = false,
|
||||
var notDecorateTheFirstTwoItems: Boolean = false,
|
||||
@Dimension(unit = Dimension.PX)
|
||||
var left: Int = 0,
|
||||
@Dimension(unit = Dimension.PX)
|
||||
var top: Int = 0,
|
||||
@Dimension(unit = Dimension.PX)
|
||||
var right: Int = 0,
|
||||
@Dimension(unit = Dimension.PX)
|
||||
var bottom: Int = 0)
|
||||
: RecyclerView.ItemDecoration() {
|
||||
|
||||
@ -18,7 +34,10 @@ class SpacingItemDecoration(
|
||||
if (onlyDecorateTheFirstItem) {
|
||||
if (parent.getChildAdapterPosition(view) == 0) outRect.set(left, top, right, bottom)
|
||||
} else {
|
||||
if (parent.getChildAdapterPosition(view) == 0 && notDecorateTheFirstItem) {
|
||||
if (parent.getChildAdapterPosition(view) == 0
|
||||
&& (notDecorateTheFirstItem || notDecorateTheFirstTwoItems)) {
|
||||
outRect.set(0, 0, 0, 0)
|
||||
} else if(parent.getChildAdapterPosition(view) == 1 && notDecorateTheFirstTwoItems) {
|
||||
outRect.set(0, 0, 0, 0)
|
||||
} else if (parent.getChildAdapterPosition(view) == parent.adapter!!.itemCount - 1 && notDecorateTheLastItem) {
|
||||
outRect.set(0, 0, 0, 0)
|
||||
|
||||
@ -16,6 +16,7 @@ public class PagerLayoutManager extends LinearLayoutManager {
|
||||
private static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
|
||||
private static final int VERTICAL = OrientationHelper.VERTICAL;
|
||||
private int mOrientation;
|
||||
private int mLastPosition = -1;
|
||||
/**
|
||||
* 位移,用来判断移动方向
|
||||
*/
|
||||
@ -115,9 +116,11 @@ public class PagerLayoutManager extends LinearLayoutManager {
|
||||
positionIdle = getPosition(viewIdle);
|
||||
}
|
||||
int childCount = getChildCount();
|
||||
if (mOnViewPagerListener != null && childCount == 1) {
|
||||
// if (mOnViewPagerListener != null && childCount == 1) {
|
||||
if (mOnViewPagerListener != null && positionIdle != mLastPosition) {
|
||||
mOnViewPagerListener.onPageSelected(positionIdle,
|
||||
positionIdle == childCount - 1);
|
||||
mLastPosition = positionIdle;
|
||||
}
|
||||
break;
|
||||
case RecyclerView.SCROLL_STATE_DRAGGING:
|
||||
|
||||
@ -243,6 +243,17 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
}
|
||||
}
|
||||
|
||||
// 插件版本下载互斥弹窗
|
||||
List<String> mutexPackage = gameEntity.getMutexPackage();
|
||||
if (mutexPackage != null && mutexPackage.size() > 0) {
|
||||
for (String pkg : mutexPackage) {
|
||||
if (PackagesManager.isInstalled(pkg)) {
|
||||
DialogUtils.showDownloadMutexDialog(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DownloadEntity downloadEntity = new DownloadEntity();
|
||||
downloadEntity.setUrl(apkEntity.getUrl());
|
||||
downloadEntity.setName(gameEntity.getName());
|
||||
@ -637,9 +648,10 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
private void startDownloadService() {
|
||||
Intent serviceIntent = new Intent(mContext, DownloadService.class);
|
||||
// 当满足系统版本大于 8.0 、应用在后台运行时以前台服务开启
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& !HaloApp.getInstance().isRunningForeground) {
|
||||
// 当满足系统版本大于 8.0 就以前台服务开启 DownloadService
|
||||
// (因为即便在 SplashActivity 里初始化,也有可能报 not allowed to start service, app is in background 的错误)
|
||||
// DownloadService 会调用 stopForeground 方法,理论上会去掉 `光环助手正在运行中` 的通知
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
|
||||
mContext.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
@ -734,7 +746,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
public void markDownloadedTaskAsRead() {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
|
||||
List<DownloadEntity> all = getAll();
|
||||
for (DownloadEntity downloadEntity : all) {
|
||||
DownloadStatus status = downloadEntity.getStatus();
|
||||
@ -747,20 +759,20 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (markHasChanged) {
|
||||
EventBus.getDefault().post(new EBDownloadStatus("download", "", "", "", "", ""));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 标记可用更新为已读 (用于下载管理页入口的 toolbar 红点显示)
|
||||
*/
|
||||
public void markUpdatableTaskAsRead() {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
|
||||
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
for (GameUpdateEntity update : updates) {
|
||||
String mark = update.getId() + update.getPackageName();
|
||||
@ -769,7 +781,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
if (!markHasChanged) markHasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (markHasChanged) {
|
||||
saveUpdateMarkToStorage();
|
||||
EventBus.getDefault().post(new EBDownloadStatus("download", "", "", "", "", ""));
|
||||
|
||||
@ -12,9 +12,9 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
@ -30,7 +30,7 @@ import okhttp3.Response;
|
||||
|
||||
public class CacheManager {
|
||||
private static final AtomicReference<CacheManager> INSTANCE = new AtomicReference<>();
|
||||
private volatile HashMap<String, Call> downCalls;
|
||||
private volatile ConcurrentHashMap<String, Call> downCalls;
|
||||
private OkHttpClient mClient;
|
||||
private File cacheDirectory = StorageUtils.getIndividualCacheDirectory(HaloApp.getInstance().getApplication());
|
||||
private FileNameGenerator generator = new Md5FileNameGenerator();
|
||||
@ -52,11 +52,11 @@ public class CacheManager {
|
||||
}
|
||||
|
||||
private CacheManager() {
|
||||
downCalls = new HashMap<>();
|
||||
downCalls = new ConcurrentHashMap<>();
|
||||
mClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
private synchronized HashMap<String, Call> getDownCalls() {
|
||||
private synchronized ConcurrentHashMap<String, Call> getDownCalls() {
|
||||
return downCalls;
|
||||
}
|
||||
|
||||
@ -226,9 +226,14 @@ public class CacheManager {
|
||||
}
|
||||
|
||||
private List<File> getAllFile() {
|
||||
if (cacheDirectory.exists()) {
|
||||
File[] files = cacheDirectory.listFiles();
|
||||
return Arrays.asList(files);
|
||||
try {
|
||||
if (cacheDirectory.exists() && cacheDirectory.isDirectory()) {
|
||||
File[] files = cacheDirectory.listFiles();
|
||||
return Arrays.asList(files);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
88
app/src/main/java/com/gh/download/cache/ExoCacheManager.kt
vendored
Normal file
88
app/src/main/java/com/gh/download/cache/ExoCacheManager.kt
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
package com.gh.download.cache
|
||||
|
||||
import android.net.Uri
|
||||
import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.NetworkUtils
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.google.android.exoplayer2.upstream.DataSpec
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheUtil
|
||||
import com.google.android.exoplayer2.util.Util
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import tv.danmaku.ijk.media.exo2.ExoSourceManager
|
||||
import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSource
|
||||
import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSourceFactory
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
|
||||
object ExoCacheManager {
|
||||
|
||||
private val threads = ConcurrentHashMap<String, AtomicBoolean>()
|
||||
private const val preLength = 50 * 1024 * 1024L //预加载视频大小
|
||||
|
||||
fun preload(videoUri: String) {
|
||||
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
|
||||
runOnIoThread {
|
||||
threads[videoUri] = AtomicBoolean(false)
|
||||
val contentLength = getContentLength(videoUri)
|
||||
val cacheLength = if (contentLength >= preLength) preLength else contentLength
|
||||
val dataSpec = DataSpec(Uri.parse(videoUri), 0, cacheLength, null)
|
||||
val simpleCache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
|
||||
val dataSourceFactory = GSYExoHttpDataSourceFactory(Util.getUserAgent(HaloApp.getInstance().application,
|
||||
"ExoCacheManager"), DefaultBandwidthMeter.Builder(HaloApp.getInstance().application).build(),
|
||||
GSYExoHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
|
||||
GSYExoHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false)
|
||||
val cacheDataSource = CacheDataSource(simpleCache, dataSourceFactory.createDataSource())
|
||||
try {
|
||||
CacheUtil.cache(dataSpec, simpleCache, CacheUtil.DEFAULT_CACHE_KEY_FACTORY, cacheDataSource, CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->
|
||||
if (requestLength == bytesCached) {
|
||||
threads.remove(videoUri)
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("$requestLength--$bytesCached--$newBytesCached")
|
||||
}
|
||||
}, threads[videoUri])
|
||||
} catch (e: Exception) {
|
||||
threads.remove(videoUri)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun cancel(videoUri: String) {
|
||||
threads[videoUri]?.set(true)
|
||||
}
|
||||
|
||||
fun cancelAll() {
|
||||
for (entry in threads.entries) {
|
||||
entry.value.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContentLength(downloadUrl: String): Long {
|
||||
var contentLength = -1L
|
||||
val request = Request.Builder()
|
||||
.url(downloadUrl)
|
||||
.build()
|
||||
var response: Response? = null
|
||||
try {
|
||||
response = OkHttpClient.Builder().build().newCall(request).execute()
|
||||
if (response!!.isSuccessful && response.body() != null) {
|
||||
val length = response.body()!!.contentLength()
|
||||
contentLength = if (length == 0L) -1L else length
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
response?.close()
|
||||
}
|
||||
return contentLength
|
||||
}
|
||||
}
|
||||
@ -59,12 +59,24 @@ public class GameDetailActivity extends NormalActivity {
|
||||
* 启动游戏详情页面
|
||||
*/
|
||||
public static void startGameDetailActivity(Context context, String gameId, String entrance) {
|
||||
startGameDetailActivity(context, gameId, false, entrance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scrollToLibao 滚动到动态 tab 的礼包 item
|
||||
*/
|
||||
public static void startGameDetailActivity(Context context, String gameId, Boolean scrollToLibao, String entrance) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_GAMEID, gameId);
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance);
|
||||
if (scrollToLibao) {
|
||||
bundle.putInt(EntranceUtils.KEY_TARGET, GameDetailFragment.INDEX_TRENDES);
|
||||
bundle.putBoolean(EntranceUtils.KEY_SCROLL_TO_LIBAO, true);
|
||||
}
|
||||
context.startActivity(getTargetIntent(context, GameDetailActivity.class, GameDetailFragment.class, bundle));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启动游戏详情页面 with 曝光事件
|
||||
*/
|
||||
|
||||
@ -25,13 +25,12 @@ import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.gh.base.AppUncaughtHandler;
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.base.fragment.BaseFragment_ViewPager;
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
@ -48,6 +47,7 @@ import com.gh.common.util.DeviceTokenUtils;
|
||||
import com.gh.common.util.DeviceUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.DirectUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.DownloadNotificationHelper;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.LogUtils;
|
||||
@ -91,6 +91,7 @@ import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.gamecenter.suggest.SuggestSelectFragment;
|
||||
import com.gh.gamecenter.suggest.SuggestType;
|
||||
import com.google.android.exoplayer2.upstream.cache.Cache;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.halo.assistant.HaloApp;
|
||||
@ -102,6 +103,7 @@ import com.lightgame.download.DownloadStatus;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.lightgame.utils.AppManager;
|
||||
import com.lightgame.utils.Util_System_Phone_State;
|
||||
import com.lightgame.utils.Utils;
|
||||
import com.shuyu.gsyvideoplayer.utils.StorageUtils;
|
||||
import com.tencent.bugly.beta.tinker.TinkerManager;
|
||||
import com.tencent.bugly.crashreport.CrashReport;
|
||||
@ -109,6 +111,7 @@ import com.tencent.bugly.crashreport.CrashReport;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -130,17 +133,22 @@ import java.util.UUID;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import tv.danmaku.ijk.media.exo2.ExoSourceManager;
|
||||
|
||||
import static com.gh.common.util.EntranceUtils.ENTRANCE_BROWSER;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_QQ;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_QQ_GROUP;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_WEB;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_DATA;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_NEXT_TO;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TO;
|
||||
import static com.gh.common.util.EntranceUtils.KEY_TYPE;
|
||||
import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL;
|
||||
@ -155,6 +163,7 @@ public class MainActivity extends BaseActivity {
|
||||
public final static String SWITCH_TO_VIDEO = "switch_to_video";
|
||||
|
||||
private final static String IS_SKIPPED = "is_skipped";
|
||||
private final static String CURRENT_PAGE = "current_page";
|
||||
|
||||
private PackageViewModel mPackageViewModel;
|
||||
|
||||
@ -170,118 +179,6 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
private Handler handler = new Handler();
|
||||
|
||||
// todo 全局监听可能不应该放这里, MainActivity 销毁后此处无法工作
|
||||
// 黄壮华 添加观察者 修改2015/8/15
|
||||
private DataWatcher dataWatcher = new DataWatcher() {
|
||||
@Override
|
||||
public void onDataChanged(DownloadEntity downloadEntity) {
|
||||
if (downloadEntity.getStatus() != DownloadStatus.downloading) {
|
||||
LogUtils.uploadDownloadEvent(downloadEntity);
|
||||
}
|
||||
|
||||
if (DownloadStatus.hijack.equals(downloadEntity.getStatus())) {
|
||||
// 链接被劫持
|
||||
processHijack(downloadEntity);
|
||||
String nameAndPlatform = downloadEntity.getName() + ":"
|
||||
+ PlatformUtils.getInstance(getApplicationContext()).getPlatformName(downloadEntity.getPlatform());
|
||||
DataUtils.onMtaEvent(getApplicationContext(), "下载劫持", "游戏名字", nameAndPlatform, "网络状态" + DeviceUtils.getNetwork(getApplication()));
|
||||
return;
|
||||
} else if (DownloadStatus.notfound.equals(downloadEntity.getStatus())) {
|
||||
// 404 Not Found
|
||||
// 删除任务
|
||||
downloadEntity.setStatus(DownloadStatus.cancel);
|
||||
DownloadManager.getInstance(getApplicationContext()).cancel(downloadEntity.getUrl());
|
||||
toast("该链接已失效!请联系管理员。");
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
|
||||
"游戏", downloadEntity.getName(),
|
||||
"平台", downloadEntity.getPlatform());
|
||||
|
||||
DialogUtils.showAlertDialog(AppManager.getInstance().currentActivity()
|
||||
, "下载失败"
|
||||
, "下载链接已失效,建议提交反馈"
|
||||
, "立即反馈", "取消"
|
||||
, () -> SuggestionActivity.startSuggestionActivity(AppManager.getInstance().currentActivity(),
|
||||
SuggestType.gameQuestion, "notfound",
|
||||
StringUtils.buildString(downloadEntity.getName(), ",问题反馈:下载链接失效"),
|
||||
new SimpleGameEntity(downloadEntity.getGameId(), downloadEntity.getName(), "")), null);
|
||||
return;
|
||||
} else if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|
||||
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())) {
|
||||
|
||||
toast("网络不稳定,下载任务已暂停");
|
||||
DataLogUtils.uploadNeterrorLog(MainActivity.this, downloadEntity);
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
|
||||
"游戏", downloadEntity.getName(),
|
||||
"平台", downloadEntity.getPlatform());
|
||||
}
|
||||
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
if (downloadEntity.getName().contains(getString(R.string.app_name))) {
|
||||
DataUtils.onEvent(MainActivity.this, "软件更新", "下载完成");
|
||||
startActivity(PackageUtils.getInstallIntent(MainActivity.this, downloadEntity.getPath(), true));
|
||||
DataLogUtils.uploadUpgradeLog(MainActivity.this, "install"); //上传更新安装数据
|
||||
} else {
|
||||
statDoneEvent(downloadEntity);
|
||||
|
||||
String platform = PlatformUtils.getInstance(getApplicationContext())
|
||||
.getPlatformName(downloadEntity.getPlatform());
|
||||
if (platform != null) {
|
||||
if (downloadEntity.isPluggable()) {
|
||||
// 弹出插件化提示框
|
||||
EventBus.getDefault().post(new EBShowDialog(PLUGGABLE, downloadEntity.getPath()));
|
||||
} else if (downloadEntity.isPlugin()) {
|
||||
toast(downloadEntity.getName() + " - " + platform + " - 下载完成");
|
||||
} else {
|
||||
toast(downloadEntity.getName() + " - 下载完成");
|
||||
}
|
||||
} else {
|
||||
toast(downloadEntity.getName() + " - 下载完成");
|
||||
}
|
||||
if (!downloadEntity.isPluggable()) {
|
||||
// 是否是自动安装
|
||||
if (mSp.getBoolean(SettingsFragment.AUTO_INSTALL_SP_KEY, true)) {
|
||||
if (FileUtils.isEmptyFile(downloadEntity.getPath())) {
|
||||
toast(R.string.install_failure_hint);
|
||||
DownloadManager.getInstance(MainActivity.this).cancel(downloadEntity.getUrl());
|
||||
} else {
|
||||
if (PackageUtils.isCanLaunchSetup(getApplicationContext(), downloadEntity.getPath())) {
|
||||
downloadEntity.getMeta().put(Constants.MARK_ALREADY_TRIGGERED_INSTALLATION, "YES");
|
||||
startActivity(PackageUtils.getInstallIntent(MainActivity.this, downloadEntity.getPath()));
|
||||
} else {
|
||||
// 弹出卸载提示框
|
||||
EventBus.getDefault().post(new EBShowDialog(PLUGGABLE, downloadEntity.getPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计下载完成
|
||||
uploadData(downloadEntity.getGameId(), downloadEntity.getPlatform());
|
||||
}
|
||||
|
||||
// 下载过程分析统计
|
||||
PackageManager pm = getApplicationContext().getPackageManager();
|
||||
PackageInfo packageInfo = pm.getPackageArchiveInfo(downloadEntity.getPath(), PackageManager.GET_ACTIVITIES);
|
||||
if (packageInfo == null) {
|
||||
MtaHelper.onEventWithBasicDeviceInfo("解析包错误分析"
|
||||
, "游戏名字", downloadEntity.getName() + ":"
|
||||
+ PlatformUtils.getInstance(getApplicationContext()).getPlatformName(downloadEntity.getPlatform()));
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo(
|
||||
"解析包错误_新",
|
||||
"游戏", downloadEntity.getName() + ":" + PlatformUtils.getInstance(getApplicationContext()).getPlatformName(downloadEntity.getPlatform()));
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadEntity.getStatus() == DownloadStatus.done) {
|
||||
EventBus.getDefault().post(new EBDownloadStatus("done", "", "", "", "", ""));
|
||||
}
|
||||
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -323,9 +220,6 @@ public class MainActivity extends BaseActivity {
|
||||
DataUtils.getGid();
|
||||
}
|
||||
|
||||
// 添加观察者
|
||||
DownloadManager.getInstance(this).addObserver(dataWatcher);
|
||||
|
||||
mPackageViewModel = ViewModelProviders.of(this, new PackageViewModel.Factory()).get(PackageViewModel.class);
|
||||
|
||||
final String message = Config.getExceptionMsg();
|
||||
@ -377,7 +271,7 @@ public class MainActivity extends BaseActivity {
|
||||
}, 2000);
|
||||
|
||||
// 耗时操作
|
||||
HaloApp.getInstance().getMainExecutor().execute(() -> {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
// 上传数据
|
||||
DataCollectionManager.getInstance(getApplicationContext()).upload();
|
||||
// 获取默认配置
|
||||
@ -391,26 +285,49 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
//启动app删除视频缓存文件
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
File cacheFileDirectory = StorageUtils.getIndividualCacheDirectory(this);
|
||||
if (cacheFileDirectory.exists() && cacheFileDirectory.isDirectory()) {
|
||||
for (File file : cacheFileDirectory.listFiles()) {
|
||||
FileUtils.deleteFile(file.getPath());
|
||||
}
|
||||
}
|
||||
//创建nomedia文件
|
||||
File noMediaFile = new File(cacheFileDirectory.getParent(), ".nomedia");
|
||||
|
||||
if (!cacheFileDirectory.exists()) {
|
||||
cacheFileDirectory.mkdirs();
|
||||
}
|
||||
try {
|
||||
/*File cacheFileDirectory = StorageUtils.getIndividualCacheDirectory(this);
|
||||
if (cacheFileDirectory.exists() && cacheFileDirectory.isDirectory()) {
|
||||
for (File file : cacheFileDirectory.listFiles()) {
|
||||
FileUtils.deleteFile(file.getPath());
|
||||
}
|
||||
}
|
||||
//创建nomedia文件
|
||||
File noMediaFile = new File(cacheFileDirectory.getParent(), ".nomedia");
|
||||
|
||||
if (!cacheFileDirectory.exists()) {
|
||||
cacheFileDirectory.mkdirs();
|
||||
}
|
||||
|
||||
if (!noMediaFile.exists()) {
|
||||
noMediaFile.createNewFile();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}*/
|
||||
String dirPath = getCacheDir().getAbsolutePath() + File.separator + "exo";
|
||||
FileUtils.deleteFolder(new File(dirPath));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
//恢复顶部视频默认静音状态
|
||||
SPUtils.setBoolean(Constants.SP_TOP_VIDEO_VOICE, true);
|
||||
//恢复视频流非Wifi提醒
|
||||
SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
int currentPageIndex = savedInstanceState.getInt(CURRENT_PAGE, -1);
|
||||
if (currentPageIndex >= 0) {
|
||||
EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, currentPageIndex));
|
||||
if (currentPageIndex == MainWrapperFragment.INDEX_VIDEO) {
|
||||
DisplayUtils.setLightStatusBar(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -437,8 +354,6 @@ public class MainActivity extends BaseActivity {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
// 退出后,同样需要更新通知栏进度
|
||||
// DownloadManager.getInstance(this).removeObserver(dataWatcher);
|
||||
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
@ -474,7 +389,14 @@ public class MainActivity extends BaseActivity {
|
||||
} else {
|
||||
Intent skipIntent = new Intent(MainActivity.this, clazz);
|
||||
skipIntent.putExtras(bundle);
|
||||
startActivity(skipIntent);
|
||||
// startActivity(skipIntent);
|
||||
AvoidOnResultManager.Companion.getInstance(this)
|
||||
.startForResult(skipIntent, (resultCode, data) -> {
|
||||
Bundle nextToBundle = getIntent().getBundleExtra(KEY_NEXT_TO);
|
||||
if (nextToBundle != null) {
|
||||
EntranceUtils.jumpActivity(this, nextToBundle);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 使用光环进行二次跳转的页面会经过这里
|
||||
@ -502,11 +424,6 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
private void checkNotificationPermission() {
|
||||
// 仅登录后再启动光环时请求一次权限
|
||||
/*if (!SPUtils.getBoolean(Constants.HAS_REQUESTED_NOTIFICATION_PERMISSIONS)
|
||||
&& UserManager.getInstance().isLoggedIn()) {
|
||||
SPUtils.setBoolean(Constants.HAS_REQUESTED_NOTIFICATION_PERMISSIONS, true);
|
||||
showNotificationHintDialog();
|
||||
}*/
|
||||
if (UserManager.getInstance().isLoggedIn()) {
|
||||
NotificationHelper.showNotificationHintDialog(NotificationUgc.LOGIN);
|
||||
}
|
||||
@ -525,73 +442,6 @@ public class MainActivity extends BaseActivity {
|
||||
.subscribe(new Response<>());
|
||||
}
|
||||
|
||||
// 统计下载完成事件
|
||||
private void statDoneEvent(DownloadEntity downloadEntity) {
|
||||
ExposureUtils.DownloadType type;
|
||||
String platform = PlatformUtils.getInstance(HaloApp.getInstance().getApplication()).getPlatformName(downloadEntity.getPlatform());
|
||||
|
||||
Map<String, Object> kv1 = new HashMap<>();
|
||||
kv1.put("版本", platform);
|
||||
kv1.put("状态", "下载完成");
|
||||
kv1.put("用户机型", Build.MODEL);
|
||||
kv1.put("设备IMEI", Util_System_Phone_State.getDeviceId(HaloApp.getInstance().getApplication()));
|
||||
kv1.put("网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
kv1.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
if (downloadEntity.isUpdate()) {
|
||||
type = ExposureUtils.DownloadType.UPDATE;
|
||||
if (downloadEntity.isPlugin()) {
|
||||
type = ExposureUtils.DownloadType.PLUGIN_UPDATE;
|
||||
}
|
||||
DataUtils.onEvent(MainActivity.this, "游戏更新", downloadEntity.getName(), kv1);
|
||||
} else {
|
||||
type = ExposureUtils.DownloadType.DOWNLOAD;
|
||||
}
|
||||
|
||||
Map<String, Object> kv2 = new HashMap<>();
|
||||
kv2.put("版本", downloadEntity.getPlatform());
|
||||
kv2.put("状态", "下载完成");
|
||||
kv2.put("位置", downloadEntity.getEntrance());
|
||||
kv2.put("游戏分平台", downloadEntity.getName() + "-" + platform);
|
||||
kv2.put("光环助手版本", BuildConfig.VERSION_NAME);
|
||||
DataUtils.onEvent(MainActivity.this, "游戏下载位置", downloadEntity.getName(), kv2);
|
||||
|
||||
if (downloadEntity.isPluggable()) {
|
||||
Map<String, Object> kv3 = new HashMap<>();
|
||||
kv3.put("下载", "下载完成");
|
||||
kv3.put("版本", downloadEntity.getPlatform());
|
||||
kv3.put("位置", downloadEntity.getEntrance());
|
||||
type = ExposureUtils.DownloadType.PLUGIN_DOWNLOAD;
|
||||
DataUtils.onEvent(MainActivity.this, "插件化", downloadEntity.getName(), kv3);
|
||||
|
||||
DataUtils.onMtaEvent(this,
|
||||
"插件化_新",
|
||||
"位置", downloadEntity.getEntrance(),
|
||||
"游戏", downloadEntity.getName() + "-" + downloadEntity.getPlatform(),
|
||||
"操作", "下载完成",
|
||||
"网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication()));
|
||||
}
|
||||
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
new GameEntity(downloadEntity.getGameId(), downloadEntity.getName()),
|
||||
downloadEntity.getPlatform(),
|
||||
downloadEntity.getExposureTrace(),
|
||||
type);
|
||||
|
||||
DataCollectionUtils.uploadDownload(this, downloadEntity, "完成");
|
||||
}
|
||||
|
||||
private void processHijack(DownloadEntity downloadEntity) {
|
||||
// 删除任务
|
||||
downloadEntity.setStatus(DownloadStatus.cancel);
|
||||
DownloadManager.getInstance(getApplicationContext()).cancel(downloadEntity.getUrl());
|
||||
// 弹出提示框
|
||||
EventBus.getDefault().post(new EBShowDialog(DOWNLOAD_HIJACK));
|
||||
// 记录链接被劫持
|
||||
DataCollectionUtils.uploadHijack(this, downloadEntity);
|
||||
// 上传劫持log
|
||||
DataLogUtils.uploadHijack(this, downloadEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 && !mMainWrapperFragment.onHandleBackPressed()) {
|
||||
@ -656,6 +506,7 @@ public class MainActivity extends BaseActivity {
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(IS_SKIPPED, isSkipped);
|
||||
outState.putInt(CURRENT_PAGE, mMainWrapperFragment.getCurrentItem());
|
||||
if (mMainWrapperFragment != null) {
|
||||
outState.putInt(BaseFragment_ViewPager.ARGS_INDEX, mMainWrapperFragment.getCurrentItem());
|
||||
}
|
||||
@ -778,24 +629,6 @@ public class MainActivity extends BaseActivity {
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void showNotificationHintDialog() {
|
||||
if (!SPUtils.getBoolean(Constants.SP_SHOWED_NOTIFICATION_LOGIN)) {
|
||||
RetrofitManager.getInstance(this).getApi().getBootPopup()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BiResponse<NotificationHint>() {
|
||||
@Override
|
||||
public void onSuccess(NotificationHint data) {
|
||||
try {
|
||||
NotificationHelper.showEnableNotificationDialogIfItsDisabled(MainActivity.this, data);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void oldUserSkip(String deviceId) {
|
||||
mSp.edit().putString("syncDeviceID", deviceId).apply();
|
||||
DialogUtils.showForceDialog(MainActivity.this, "数据同步提醒"
|
||||
@ -810,7 +643,7 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
// 获取META-INF中的plugin_update 文件,判断是否从游戏插件中下载的app,是则获取游戏id,启动游戏更新,下载该游戏
|
||||
private void getPluginUpdate() {
|
||||
HaloApp.getInstance().getMainExecutor().execute(() -> {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
ApplicationInfo appinfo = getApplicationInfo();
|
||||
String sourceDir = appinfo.sourceDir;
|
||||
ZipFile zipfile = null;
|
||||
|
||||
@ -211,7 +211,7 @@ class NetworkDiagnosisActivity : ToolBarActivity() {
|
||||
builder.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
super.updateDrawState(ds)
|
||||
ds.color = resources.getColor(R.color.theme)
|
||||
ds.color = resources.getColor(R.color.theme_font)
|
||||
ds.isUnderlineText = false
|
||||
}
|
||||
|
||||
|
||||
@ -15,8 +15,8 @@ import com.gh.gamecenter.DisplayType.*
|
||||
import com.gh.gamecenter.db.SearchHistoryDao
|
||||
import com.gh.gamecenter.eventbus.EBSearch
|
||||
import com.gh.gamecenter.search.SearchDefaultFragment
|
||||
import com.gh.gamecenter.search.SearchGameDetailFragment
|
||||
import com.gh.gamecenter.search.SearchGameListFragment
|
||||
import com.gh.gamecenter.search.SearchGameIndexFragment
|
||||
import com.gh.gamecenter.search.SearchGameResultFragment
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
import com.qq.gdt.action.ActionType
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
@ -118,6 +118,7 @@ open class SearchActivity : BaseActivity() {
|
||||
val newSearchKey = editable.toString().trim { it <= ' ' }
|
||||
if (newSearchKey.isEmpty()) {
|
||||
updateDisplayType(DisplayType.DEFAULT)
|
||||
mPublishSubject?.onNext(newSearchKey)
|
||||
} else if (!mIsAutoSearchDisabled) {
|
||||
mPublishSubject?.onNext(newSearchKey)
|
||||
}
|
||||
@ -186,13 +187,13 @@ open class SearchActivity : BaseActivity() {
|
||||
transaction.replace(R.id.search_result, SearchDefaultFragment(), SearchDefaultFragment::class.java.simpleName)
|
||||
}
|
||||
DisplayType.GAME_DIGEST -> {
|
||||
val digestListFragment = SearchGameListFragment()
|
||||
digestListFragment.setParams(mSearchKey, mSearchType.value)
|
||||
val digestListFragment = SearchGameIndexFragment()
|
||||
digestListFragment.setParams(mSearchKey ?: "", mSearchType.value)
|
||||
transaction.replace(R.id.search_result, digestListFragment)
|
||||
}
|
||||
DisplayType.GAME_DETAIL -> {
|
||||
val detailListFragment = SearchGameDetailFragment()
|
||||
detailListFragment.setParams(mSearchKey, mSearchType.value)
|
||||
val detailListFragment = SearchGameResultFragment()
|
||||
detailListFragment.setParams(mSearchKey ?: "", mSearchType.value)
|
||||
transaction.replace(R.id.search_result, detailListFragment)
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import com.gh.gamecenter.entity.CommunityEntity;
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
@ -33,6 +33,7 @@ import static com.gh.common.util.EntranceUtils.HOST_QUESTION;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_SUGGESTION;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_TOOLBOX;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_UPLOAD_VIDEO;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_USERHOME;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_VIDEO;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_VIDEO_COLLECTION;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_VIDEO_MORE;
|
||||
@ -91,7 +92,7 @@ public class SkipActivity extends BaseActivity {
|
||||
DirectUtils.directToArticle(this, path, ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_GAME:
|
||||
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, false);
|
||||
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, false, "libao".equals(to));
|
||||
break;
|
||||
case HOST_COLUMN:
|
||||
DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
|
||||
@ -169,13 +170,11 @@ public class SkipActivity extends BaseActivity {
|
||||
String categoryId = uri.getQueryParameter("category_id");
|
||||
String link = uri.getQueryParameter("link");
|
||||
VideoLinkEntity linkEntity = new VideoLinkEntity(title, categoryId, link);
|
||||
if (!CheckLoginUtils.isLogin()) {
|
||||
HaloApp.put(HOST_UPLOAD_VIDEO, linkEntity);
|
||||
}
|
||||
|
||||
CheckLoginUtils.checkLogin(this, EntranceUtils.ENTRANCE_BROWSER, () -> {
|
||||
DirectUtils.directToVideoManager(this,linkEntity, EntranceUtils.ENTRANCE_BROWSER, "");
|
||||
});
|
||||
// if (!CheckLoginUtils.isLogin()) {
|
||||
// HaloApp.put(HOST_UPLOAD_VIDEO, linkEntity);
|
||||
// }
|
||||
Bundle nextToBundle = VideoManagerActivity.getVideoManagerBundle(linkEntity, EntranceUtils.ENTRANCE_BROWSER, "");
|
||||
CheckLoginUtils.checkLogin(this, nextToBundle, true, EntranceUtils.ENTRANCE_BROWSER, null);
|
||||
break;
|
||||
case HOST_VIDEO_SINGLE:
|
||||
DirectUtils.directToVideoDetail(this, path, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.getValue(),
|
||||
@ -227,6 +226,10 @@ public class SkipActivity extends BaseActivity {
|
||||
case HOST_LIBAO:
|
||||
DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER);
|
||||
break;
|
||||
case HOST_USERHOME:
|
||||
String position = uri.getQueryParameter("position");
|
||||
DirectUtils.directToHomeActivity(this, path, TextUtils.isEmpty(position) ? -1 : Integer.parseInt(position), ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
default:
|
||||
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
|
||||
return;
|
||||
|
||||
@ -15,13 +15,9 @@ import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.g00fy2.versioncompare.Version;
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.DeviceTokenUtils;
|
||||
@ -43,7 +39,6 @@ import com.gh.gamecenter.manager.FilterManager;
|
||||
import com.gh.gamecenter.retrofit.BiResponse;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.gh.gamecenter.user.UserRepository;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.download.DownloadEntity;
|
||||
import com.lightgame.download.FileUtils;
|
||||
import com.qq.gdt.action.ActionType;
|
||||
@ -56,6 +51,10 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import pub.devrel.easypermissions.AfterPermissionGranted;
|
||||
@ -135,7 +134,7 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
launchMainActivity();
|
||||
}
|
||||
|
||||
HaloApp.getInstance().getMainExecutor().execute(() -> {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
Config.getGhzsSettings();
|
||||
|
||||
UsageStatsHelper.checkAndPostUsageStats();
|
||||
@ -243,7 +242,7 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
if (EasyPermissions.hasPermissions(this, mPermissions)) {
|
||||
MtaHelper.onEvent("授权情况", "启动授权", "都授权");
|
||||
// 检查是否有旧版本光环,有就删掉
|
||||
HaloApp.getInstance().getMainExecutor().execute(this::deleteOutdatedUpdatePackage);
|
||||
AppExecutor.getIoExecutor().execute(this::deleteOutdatedUpdatePackage);
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, mPermissions, REQUEST_PERMISSION_TAG);
|
||||
}
|
||||
@ -270,7 +269,7 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
private void logGrantedPermission(List<String> perms) {
|
||||
if (perms.size() == 1) {
|
||||
MtaHelper.onEvent("授权情况", "启动授权", "只授权存储");
|
||||
HaloApp.getInstance().getMainExecutor().execute(this::deleteOutdatedUpdatePackage);
|
||||
AppExecutor.getIoExecutor().execute(this::deleteOutdatedUpdatePackage);
|
||||
} else {
|
||||
if (perms.contains(Manifest.permission.READ_PHONE_STATE)) {
|
||||
MtaHelper.onEvent("授权情况", "启动授权", "都不授权");
|
||||
|
||||
@ -815,6 +815,9 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
message = content;
|
||||
if (mSuggestType == SuggestType.crash) {
|
||||
params.put("log", readFromFile());
|
||||
if (BuildConfig.BUILD_TIME != 0) {
|
||||
message = message + " [此闪退基于" + BuildConfig.BUILD_TIME + "测试包]";
|
||||
}
|
||||
}
|
||||
}
|
||||
message = mHideHint + message;
|
||||
|
||||
@ -11,6 +11,8 @@ import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -19,17 +21,12 @@ import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
||||
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.imagepipeline.core.ImagePipeline;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.gh.base.BaseActivity;
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.Base64ImageHolder;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
@ -49,6 +46,7 @@ import com.github.piasy.biv.view.BigImageView;
|
||||
import com.github.piasy.biv.view.FrescoImageViewFactory;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -60,6 +58,11 @@ import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
||||
import butterknife.BindView;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
@ -288,11 +291,36 @@ public class ViewImageActivity extends BaseActivity implements OnPageChangeListe
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void loadImage(String url, final BigImageView imageView) {
|
||||
// 添加GIF支持
|
||||
imageView.setImageViewFactory(new FrescoImageViewFactory());
|
||||
imageView.showImage(Uri.parse(url));
|
||||
if (TextUtils.isEmpty(url)) return;
|
||||
|
||||
if (url.startsWith("data:image/png;base64")) {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
String base64String = url.replace("data:image/png;base64", "");
|
||||
try {
|
||||
File imageFile = new File(getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".png");
|
||||
|
||||
byte[] decodedString = Base64.decode(base64String, Base64.DEFAULT);
|
||||
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(imageFile));
|
||||
bos.write(decodedString);
|
||||
bos.flush();
|
||||
bos.close();
|
||||
|
||||
AppExecutor.getUiExecutor().execute(() -> {
|
||||
imageView.setImageViewFactory(new FrescoImageViewFactory());
|
||||
imageView.showImage(Uri.fromFile(imageFile));
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 添加GIF支持
|
||||
imageView.setImageViewFactory(new FrescoImageViewFactory());
|
||||
imageView.showImage(Uri.parse(url));
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewImageAdapter extends PagerAdapter implements OnSingleTapListener {
|
||||
|
||||
@ -5,8 +5,6 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.gamecenter.entity.ConcernEntity;
|
||||
@ -18,6 +16,8 @@ import java.net.URLEncoder;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/10/18.
|
||||
*/
|
||||
@ -130,7 +130,7 @@ public class WebActivity extends NormalActivity {
|
||||
url = Constants.BADGE_ADDRESS;
|
||||
}
|
||||
|
||||
url = String.format(Locale.CHINA, "%s?user_id=%s&name=%s&icon=%s×tamp=%d", url, userId, name, URLEncoder.encode(icon), Math.round(new Date().getTime() / 1000));
|
||||
url = String.format(Locale.CHINA, "%s?user_id=%s&name=%s&icon=%s×tamp=%d", url, userId, name, URLEncoder.encode(icon), Math.round((new Date().getTime() / 1000) / 1000));
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_URL, url);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, true);
|
||||
|
||||
@ -220,7 +220,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter<KcSelectGameViewHolder>
|
||||
|
||||
if (gameEntity.getInstallStatus() == INSTALLED) {
|
||||
holder.gameSize.setText(R.string.installed);
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
} else {
|
||||
holder.gameSize.setText(R.string.installed_not);
|
||||
holder.gameSize.setTextColor(ContextCompat.getColor(mContext, R.color.red));
|
||||
|
||||
@ -5,6 +5,9 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.gh.common.constant.ItemViewType;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.CommentUtils;
|
||||
@ -26,8 +29,6 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
@ -149,13 +150,10 @@ public class CommentDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
private void initCommentViewHolder(final CommentViewHolder holder, int position) {
|
||||
final CommentEntity commentEntity = mCommentList.get(position);
|
||||
|
||||
holder.commentLine.setVisibility(View.VISIBLE);
|
||||
holder.commentLineBottom.setVisibility(View.GONE);
|
||||
|
||||
CommentUtils.setCommentUserView(mContext, holder, commentEntity);
|
||||
|
||||
CommentUtils.setCommentTime(holder.commentTimeTv, commentEntity.getTime());
|
||||
|
||||
|
||||
TextHelper.highlightTextThatIsWrappedInsideWrapperByDefault(holder.commentContentTv, commentEntity.getContent());
|
||||
ArticleCommentParent parent = commentEntity.getParent();
|
||||
if (parent != null && !TextUtils.isEmpty(parent.getUser().getName())) {
|
||||
@ -180,16 +178,23 @@ public class CommentDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
holder.quoteContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
holder.commentLikeIv.setOnClickListener(v -> CheckLoginUtils.checkLogin(mContext,
|
||||
holder.commentLikeContainer.setOnClickListener(v -> CheckLoginUtils.checkLogin(mContext,
|
||||
"资讯文章-评论-点赞", () ->
|
||||
CommentUtils.postVote(mContext,
|
||||
commentEntity, holder.commentLikeCountTv,
|
||||
holder.commentLikeIv, null)));
|
||||
|
||||
holder.itemView.setOnClickListener(v ->
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (holder.commentReply.getVisibility() == View.VISIBLE) {
|
||||
CheckLoginUtils.checkLogin(mContext, "资讯文章-评论-回复", () -> {
|
||||
mOnCommentCallBackListener.onCommentCallback(commentEntity);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
holder.commentMore.setOnClickListener(v ->
|
||||
CommentUtils.showReportDialog(commentEntity,
|
||||
mContext, false,
|
||||
mOnCommentCallBackListener, null, "资讯文章-评论"));
|
||||
mContext, false, "资讯文章-评论"));
|
||||
|
||||
holder.commentUserIconDv.setOnClickListener(v -> DirectUtils.directToHomeActivity(mContext, commentEntity.getUser().getId(), "", "文章-评论详情"));
|
||||
holder.commentUserNameTv.setOnClickListener(v -> DirectUtils.directToHomeActivity(mContext, commentEntity.getUser().getId(), "", "文章-评论详情"));
|
||||
|
||||
@ -9,6 +9,9 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.CommentUtils;
|
||||
@ -53,8 +56,6 @@ import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import retrofit2.HttpException;
|
||||
@ -390,7 +391,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
final CommentEntity finalCommentEntity = commentEntity;
|
||||
final boolean finalIsHotComment = isHotComment;
|
||||
final int finalCommentPosition = commentPosition;
|
||||
holder.commentLikeIv.setOnClickListener(v ->
|
||||
holder.commentLikeContainer.setOnClickListener(v ->
|
||||
CheckLoginUtils.checkLogin(mContext, "资讯文章详情-评论详情-点赞",
|
||||
() -> CommentUtils.postVote(mContext, finalCommentEntity, holder.commentLikeCountTv,
|
||||
holder.commentLikeIv, () -> {
|
||||
@ -410,10 +411,17 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
})
|
||||
));
|
||||
|
||||
holder.itemView.setOnClickListener(v ->
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (holder.commentReply.getVisibility() == View.VISIBLE) {
|
||||
CheckLoginUtils.checkLogin(mContext, "资讯文章详情-评论详情-回复", () -> {
|
||||
mOnCommentCallBackListener.onCommentCallback(finalCommentEntity);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
holder.commentMore.setOnClickListener(v ->
|
||||
CommentUtils.showReportDialog(finalCommentEntity,
|
||||
mContext, true,
|
||||
mOnCommentCallBackListener, null, "资讯文章详情-评论详情"));
|
||||
mContext, true, "资讯文章详情-评论详情"));
|
||||
|
||||
holder.commentUserNameTv.setOnClickListener(v -> DirectUtils.directToHomeActivity(mContext, finalCommentEntity.getUser().getId(), mEntrance, "文章-评论详情"));
|
||||
holder.commentUserIconDv.setOnClickListener(v -> DirectUtils.directToHomeActivity(mContext, finalCommentEntity.getUser().getId(), mEntrance, "文章-评论详情"));
|
||||
@ -472,11 +480,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
viewHolder.itemView.setPadding(0, DisplayUtils.dip2px(mContext, 30), 0, 0);
|
||||
viewHolder.hint.setText(R.string.comment_empty);
|
||||
} else {
|
||||
if (mNormalCommentList.size() > 10) {
|
||||
viewHolder.hint.setText(R.string.comment_nomore);
|
||||
} else {
|
||||
viewHolder.hint.setText("");
|
||||
}
|
||||
viewHolder.hint.setText(R.string.comment_nomore);
|
||||
viewHolder.loading.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
@ -16,12 +16,12 @@ import butterknife.BindView;
|
||||
*/
|
||||
public class CommentViewHolder extends BaseRecyclerViewHolder {
|
||||
|
||||
@BindView(R.id.comment_line)
|
||||
public View commentLine;
|
||||
@BindView(R.id.comment_content)
|
||||
public TextView commentContentTv;
|
||||
@BindView(R.id.comment_like)
|
||||
public ImageView commentLikeIv;
|
||||
@BindView(R.id.comment_like_container)
|
||||
public View commentLikeContainer;
|
||||
@BindView(R.id.comment_like_count)
|
||||
public TextView commentLikeCountTv;
|
||||
@BindView(R.id.comment_time)
|
||||
@ -32,8 +32,8 @@ public class CommentViewHolder extends BaseRecyclerViewHolder {
|
||||
public SimpleDraweeView commentUserBadgeIv;
|
||||
@BindView(R.id.comment_user_name)
|
||||
public TextView commentUserNameTv;
|
||||
@BindView(R.id.comment_line_bottom)
|
||||
public View commentLineBottom;
|
||||
@BindView(R.id.comment_author)
|
||||
public TextView commentAuthorTv;
|
||||
@BindView(R.id.comment_badge)
|
||||
public View commentBadge;
|
||||
|
||||
@ -50,6 +50,12 @@ public class CommentViewHolder extends BaseRecyclerViewHolder {
|
||||
public TextView badgeNameTv;
|
||||
@BindView(R.id.sdv_quote_author_badge)
|
||||
public SimpleDraweeView quoteAuthorBadgeSdv;
|
||||
@BindView(R.id.comment_more)
|
||||
public View commentMore;
|
||||
@BindView(R.id.comment_reply)
|
||||
public View commentReply;
|
||||
@BindView(R.id.reply_dividing_line)
|
||||
public View replyLine;
|
||||
|
||||
public CommentViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
@ -180,10 +180,7 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
|
||||
binding.amwayContentTv.setTextWithHighlightedTextWrappedInsideWrapper(amway.comment.content, copyClickedText = true)
|
||||
}
|
||||
|
||||
val exposureEvent = ExposureEvent.createEvent(
|
||||
gameEntity = amway.game.toGameEntity(),
|
||||
source = listOf(basicExposureSource))
|
||||
itemData.exposureEvent = exposureEvent
|
||||
itemData.exposureEvent = ExposureEvent.createEvent(amway.game.toGameEntity(), listOf(basicExposureSource))
|
||||
|
||||
binding.gameContainer.setOnClickListener {
|
||||
GameDetailActivity.startGameDetailActivity(binding.root.context, amway.game.id, "(安利墙)", itemData.exposureEvent)
|
||||
|
||||
@ -61,6 +61,9 @@ public abstract class ListAdapter<DataType> extends BaseRecyclerAdapter {
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
if (oldItemPosition >= mEntityList.size()) return false;
|
||||
if (newItemPosition >= updateData.size()) return false;
|
||||
|
||||
DataType oldItem = mEntityList.get(oldItemPosition);
|
||||
DataType newItem = updateData.get(newItemPosition);
|
||||
return ListAdapter.this.areItemsTheSame(oldItem, newItem);
|
||||
@ -68,6 +71,9 @@ public abstract class ListAdapter<DataType> extends BaseRecyclerAdapter {
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
if (oldItemPosition >= mEntityList.size()) return false;
|
||||
if (newItemPosition >= updateData.size()) return false;
|
||||
|
||||
DataType oldItem = mEntityList.get(oldItemPosition);
|
||||
DataType newItem = updateData.get(newItemPosition);
|
||||
return ListAdapter.this.areContentsTheSame(oldItem, newItem);
|
||||
|
||||
@ -1,17 +1,28 @@
|
||||
package com.gh.gamecenter.collection;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.gh.base.OnListClickListener;
|
||||
import com.gh.common.constant.ItemViewType;
|
||||
import com.gh.common.util.CollectionUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
|
||||
import com.gh.gamecenter.baselist.LoadType;
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding;
|
||||
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder;
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.gamecenter.qa.questions.detail.AnswerViewHolder;
|
||||
import com.gh.gamecenter.baselist.ListAdapter;
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
/**
|
||||
* Created by khy on 22/12/17.
|
||||
@ -21,12 +32,17 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> {
|
||||
|
||||
private OnListClickListener mListClickListener;
|
||||
|
||||
private String mEntrance;
|
||||
private AnswerViewModel mListViewModel;
|
||||
|
||||
public AnswerAdapter(Context context, OnListClickListener listClickListener, String entrance) {
|
||||
private String mEntrance;
|
||||
private AnswerFragment.Type mType;
|
||||
|
||||
public AnswerAdapter(Context context, AnswerViewModel viewModel, AnswerFragment.Type type, OnListClickListener listClickListener, String entrance) {
|
||||
super(context);
|
||||
mListViewModel = viewModel;
|
||||
mListClickListener = listClickListener;
|
||||
mEntrance = entrance;
|
||||
this.mType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -43,8 +59,8 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> {
|
||||
view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false);
|
||||
return new FooterViewHolder(view, mListClickListener);
|
||||
case ItemViewType.ITEM_BODY:
|
||||
view = mLayoutInflater.inflate(R.layout.ask_answer_item, parent, false);
|
||||
return new AnswerViewHolder(view, mListClickListener);
|
||||
view = mLayoutInflater.inflate(R.layout.community_answer_item, parent, false);
|
||||
return new CommunityAnswerItemViewHolder(CommunityAnswerItemBinding.bind(view));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -54,7 +70,41 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> {
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
switch (getItemViewType(position)) {
|
||||
case ItemViewType.ITEM_BODY:
|
||||
((AnswerViewHolder) holder).initCollectionAnswerViewHolder(mEntityList.get(position), mEntrance);
|
||||
CommunityAnswerItemViewHolder viewHolder = (CommunityAnswerItemViewHolder) holder;
|
||||
AnswerEntity entity = mEntityList.get(position);
|
||||
String path;
|
||||
if (mType == AnswerFragment.Type.COLLECTION) {
|
||||
path = "我的收藏-回答列表";
|
||||
} else if (mType == AnswerFragment.Type.HISTORY) {
|
||||
path = "浏览记录-回答列表";
|
||||
} else {
|
||||
path = "插入回答-收藏回答列表";
|
||||
}
|
||||
viewHolder.bindAnswerItem(entity, mEntrance, path);
|
||||
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (entity.getActive()) {
|
||||
mContext.startActivity(AnswerDetailActivity.getIntent(mContext, entity.getId(), mEntrance, path));
|
||||
} else {
|
||||
showDeleteDialog(entity.getId());
|
||||
}
|
||||
|
||||
if (!entity.getRead()) {
|
||||
entity.setRead(true);
|
||||
notifyItemChanged(position);
|
||||
mListViewModel.postCollectionAnswerRead(entity.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
viewHolder.getBinding().title.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Questions questions = entity.getQuestions();
|
||||
mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
|
||||
}
|
||||
});
|
||||
break;
|
||||
case ItemViewType.ITEM_FOOTER:
|
||||
FooterViewHolder footerViewHolder = (FooterViewHolder) holder;
|
||||
@ -64,6 +114,26 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
private void showDeleteDialog(String answerId) {
|
||||
DialogUtils.showCancelAlertDialog(mContext, "提示"
|
||||
, "内容已被删除,是否取消收藏?"
|
||||
, "取消收藏", "暂不"
|
||||
, () -> CollectionUtils.INSTANCE.deleteCollection(mContext, answerId
|
||||
, CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Utils.toast(mContext, R.string.collection_cancel);
|
||||
mListViewModel.load(LoadType.REFRESH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
Utils.toast(mContext, R.string.collection_cancel_failure);
|
||||
}
|
||||
}), null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mEntityList == null || mEntityList.isEmpty() ? 0 : mEntityList.size() + FOOTER_ITEM_COUNT;
|
||||
|
||||
@ -4,18 +4,13 @@ import android.view.View;
|
||||
|
||||
import com.gh.common.history.HistoryDatabase;
|
||||
import com.gh.common.util.CollectionUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.baselist.ListAdapter;
|
||||
import com.gh.gamecenter.baselist.ListFragment;
|
||||
import com.gh.gamecenter.baselist.LoadType;
|
||||
import com.gh.gamecenter.baselist.NormalListViewModel;
|
||||
import com.gh.gamecenter.eventbus.EBCollectionChanged;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
@ -23,13 +18,14 @@ import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import io.reactivex.Single;
|
||||
|
||||
/**
|
||||
* Created by khy on 22/12/17.
|
||||
*/
|
||||
|
||||
public class AnswerFragment extends ListFragment<AnswerEntity, NormalListViewModel> {
|
||||
public class AnswerFragment extends ListFragment<AnswerEntity, AnswerViewModel> {
|
||||
|
||||
private AnswerAdapter mAdapter;
|
||||
private Type mType;
|
||||
@ -42,7 +38,7 @@ public class AnswerFragment extends ListFragment<AnswerEntity, NormalListViewMod
|
||||
|
||||
@Override
|
||||
protected ListAdapter provideListAdapter() {
|
||||
return mAdapter == null ? mAdapter = new AnswerAdapter(getContext(), this, mEntrance) : mAdapter;
|
||||
return mAdapter == null ? mAdapter = new AnswerAdapter(getContext(), mListViewModel, mType, this, mEntrance) : mAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,49 +51,23 @@ public class AnswerFragment extends ListFragment<AnswerEntity, NormalListViewMod
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListClick(View view, int position, Object data) {
|
||||
AnswerEntity entity;
|
||||
switch (view.getId()) {
|
||||
case R.id.footerview_item:
|
||||
if (mAdapter.isNetworkError()) {
|
||||
mListViewModel.load(LoadType.RETRY);
|
||||
}
|
||||
break;
|
||||
case R.id.ask_answer_item_constraintlayout:
|
||||
case R.id.ask_answer_item_content:
|
||||
entity = (AnswerEntity) data;
|
||||
if (entity.getActive()) {
|
||||
startActivity(AnswerDetailActivity.getIntent(getContext(), entity.getId(), mEntrance, "我的收藏-回答"));
|
||||
} else {
|
||||
showDeleteDialog(entity.getId());
|
||||
}
|
||||
break;
|
||||
case R.id.ask_answer_item_title:
|
||||
entity = (AnswerEntity) data;
|
||||
Questions questions = entity.getQuestions();
|
||||
startActivity(QuestionsDetailActivity.getIntent(getContext(), questions.getId(), mEntrance, "我的收藏-回答"));
|
||||
break;
|
||||
protected AnswerViewModel provideListViewModel() {
|
||||
AnswerViewModel viewModel = ViewModelProviders.of(this).get(AnswerViewModel.class);
|
||||
// TODO 因为 mType 是从外面传进来的,所以在应用回收重构时会为空,这里设置为 Type.Collection 只是为了不闪退,会影响逻辑(譬如当前类型为历史的时候)
|
||||
if (mType == null) {
|
||||
mType = Type.COLLECTION;
|
||||
}
|
||||
viewModel.setType(mType);
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
|
||||
private void showDeleteDialog(String answerId) {
|
||||
DialogUtils.showCancelAlertDialog(getContext(), "提示"
|
||||
, "内容已被删除,是否取消收藏?"
|
||||
, "取消收藏", "暂不"
|
||||
, () -> CollectionUtils.INSTANCE.deleteCollection(getContext(), answerId
|
||||
, CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
toast(R.string.collection_cancel);
|
||||
mListViewModel.load(LoadType.REFRESH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
toast(R.string.collection_cancel_failure);
|
||||
}
|
||||
}), null);
|
||||
@Override
|
||||
public void onListClick(View view, int position, Object data) {
|
||||
if (view.getId() == R.id.footerview_item) {
|
||||
if (mAdapter.isNetworkError()) {
|
||||
mListViewModel.load(LoadType.RETRY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 收藏事件
|
||||
@ -111,6 +81,8 @@ public class AnswerFragment extends ListFragment<AnswerEntity, NormalListViewMod
|
||||
public enum Type {
|
||||
COLLECTION,
|
||||
|
||||
COLLECTION_ANSWER,
|
||||
|
||||
HISTORY
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package com.gh.gamecenter.collection
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.gamecenter.baselist.ListViewModel
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
|
||||
class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, AnswerEntity>(application) {
|
||||
|
||||
private var mApi = RetrofitManager.getInstance(getApplication()).api
|
||||
|
||||
var type: AnswerFragment.Type = AnswerFragment.Type.COLLECTION
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<AnswerEntity>>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun provideDataSingle(page: Int): Single<List<AnswerEntity>> {
|
||||
return if (type == AnswerFragment.Type.COLLECTION) {
|
||||
Single.fromObservable(mApi.getCollectionAnswer(UserManager.getInstance().userId, page))
|
||||
} else {
|
||||
HistoryDatabase.instance.answerDao().getAnswersWithOffset(20, (page - 1) * 20)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource<List<AnswerEntity>>(mListLiveData) { mResultLiveData.postValue(it) }
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun postCollectionAnswerRead(answerId: String) {
|
||||
mApi
|
||||
.postCollectionAnswerRead(UserManager.getInstance().userId, answerId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,21 @@
|
||||
package com.gh.gamecenter.collection
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Paint
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.constant.ItemViewType
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.baselist.ListAdapter
|
||||
import com.gh.gamecenter.databinding.CollectionComunityArticleItemBinding
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
|
||||
class CommunityArticleAdapter(context: Context,
|
||||
val mType: CommunityArticleFragment.Type,
|
||||
private val mViewModel: CommunityArticleViewModel,
|
||||
private val mEntrance: String) : ListAdapter<ArticleEntity>(context) {
|
||||
|
||||
@ -28,7 +28,7 @@ class CommunityArticleAdapter(context: Context,
|
||||
return ItemViewType.ITEM_BODY
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view: View
|
||||
return when (viewType) {
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
@ -36,8 +36,8 @@ class CommunityArticleAdapter(context: Context,
|
||||
FooterViewHolder(view)
|
||||
}
|
||||
else -> {
|
||||
view = mLayoutInflater.inflate(R.layout.collection_comunity_article_item, parent, false)
|
||||
CollectionCommunityArticleViewHolder(CollectionComunityArticleItemBinding.bind(view))
|
||||
view = mLayoutInflater.inflate(R.layout.community_answer_item, parent, false)
|
||||
CommunityAnswerItemViewHolder(CommunityAnswerItemBinding.bind(view))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,19 +45,12 @@ class CommunityArticleAdapter(context: Context,
|
||||
override fun getItemCount(): Int = if (mEntityList.size == 0) 0 else mEntityList.size + 1
|
||||
|
||||
|
||||
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is CollectionCommunityArticleViewHolder) {
|
||||
val path = "我的收藏-文章"
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is CommunityAnswerItemViewHolder) {
|
||||
val path = if (mType == CommunityArticleFragment.Type.COLLECTION) "我的收藏-文章列表" else "浏览记录-文章列表"
|
||||
val entity = mEntityList[position]
|
||||
holder.binding.data = entity
|
||||
holder.bindArticleItem(entity, mEntrance, path)
|
||||
|
||||
if (entity.active) {
|
||||
holder.binding.content.paint.flags = Paint.ANTI_ALIAS_FLAG
|
||||
holder.binding.content.setTextColor(ContextCompat.getColor(mContext, R.color.title))
|
||||
} else {
|
||||
holder.binding.content.paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
|
||||
holder.binding.content.setTextColor(ContextCompat.getColor(mContext, R.color.hint))
|
||||
}
|
||||
holder.itemView.setOnClickListener {
|
||||
if (entity.active) {
|
||||
mContext.startActivity(ArticleDetailActivity.getIntent(mContext, entity.community, entity.id, mEntrance, path))
|
||||
@ -66,13 +59,12 @@ class CommunityArticleAdapter(context: Context,
|
||||
mViewModel.deleteCollection(entity.community.id, entity.id)
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
holder.binding.userIconContainer.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(mContext, entity.user.id, mEntrance, path)
|
||||
}
|
||||
|
||||
holder.binding.userName.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(mContext, entity.user.id, mEntrance, path)
|
||||
if (!entity.read) {
|
||||
entity.read = true
|
||||
holder.binding.unreadHint.visibility = View.GONE
|
||||
mViewModel.postCollectionArticleRead(entity.community.id, entity.id)
|
||||
}
|
||||
}
|
||||
} else if (holder is FooterViewHolder) {
|
||||
holder.initItemPadding()
|
||||
|
||||
@ -16,7 +16,7 @@ class CommunityArticleFragment : ListFragment<ArticleEntity, CommunityArticleVie
|
||||
|
||||
override fun provideListAdapter(): CommunityArticleAdapter {
|
||||
if (mAdapter == null) {
|
||||
mAdapter = CommunityArticleAdapter(context!!, mListViewModel, mEntrance)
|
||||
mAdapter = CommunityArticleAdapter(context!!,mType, mListViewModel, mEntrance)
|
||||
}
|
||||
return mAdapter!!
|
||||
}
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
package com.gh.gamecenter.collection
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.baselist.ListViewModel
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
import com.gh.gamecenter.retrofit.Response
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.lightgame.utils.Utils
|
||||
@ -66,4 +68,15 @@ class CommunityArticleViewModel(application: Application) : ListViewModel<Articl
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun postCollectionArticleRead(communityId: String, articleId: String){
|
||||
RetrofitManager.getInstance(getApplication()).api
|
||||
.postCollectionArticleRead(UserManager.getInstance().userId, communityId, articleId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,7 @@ class VideoAdapter(context: Context,
|
||||
if (mVideoStyle == VideoFragment.VideoStyle.COLLECT.value) {
|
||||
DirectUtils.directToVideoDetail(mContext, entity.id, VideoDetailContainerViewModel.Location.USER_FAVORITE_VIDEO.value, false, path = getPath())
|
||||
} else {
|
||||
DirectUtils.directToVideoDetail(mContext, entity.id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value, false, path = getPath())
|
||||
DirectUtils.directToVideoDetail(mContext, entity.id, VideoDetailContainerViewModel.Location.VIDEO_HOT.value, false, path = getPath())
|
||||
}
|
||||
}
|
||||
} else if (holder is FooterViewHolder) {
|
||||
|
||||
@ -10,6 +10,7 @@ import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.view.GridSpacingItemDecoration
|
||||
import com.gh.gamecenter.baselist.ListFragment
|
||||
import com.gh.gamecenter.baselist.LoadStatus
|
||||
import com.gh.gamecenter.baselist.NormalListViewModel
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
@ -24,7 +25,7 @@ class VideoFragment : ListFragment<MyVideoEntity, NormalListViewModel<MyVideoEnt
|
||||
|
||||
override fun provideListAdapter(): VideoAdapter {
|
||||
if (mAdapter == null) {
|
||||
mAdapter = VideoAdapter(context!!, mListViewModel,mVideoStyle)
|
||||
mAdapter = VideoAdapter(context!!, mListViewModel, mVideoStyle)
|
||||
}
|
||||
return mAdapter!!
|
||||
}
|
||||
@ -66,6 +67,10 @@ class VideoFragment : ListFragment<MyVideoEntity, NormalListViewModel<MyVideoEnt
|
||||
}
|
||||
|
||||
override fun provideDataSingle(page: Int): Single<MutableList<MyVideoEntity>>? {
|
||||
if (page > 5) {
|
||||
mAdapter?.loadChange(LoadStatus.LIST_OVER)
|
||||
return null
|
||||
}
|
||||
if (mVideoStyle == VideoStyle.BROWSING_HISTORY.value) {
|
||||
return HistoryDatabase.instance.videoHistoryDao().getVideoWithOffset(20, (page - 1) * 20)
|
||||
}
|
||||
|
||||
@ -51,6 +51,18 @@ public class GameTrendsDao {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public long findInternetPostTime(String userId){
|
||||
try {
|
||||
GameTrendsInfo gameTrendsInfo = dao.queryForId(userId);
|
||||
if (gameTrendsInfo != null) {
|
||||
return gameTrendsInfo.getInternetPostTime();
|
||||
}
|
||||
return 0;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void add(GameTrendsInfo info) {
|
||||
try {
|
||||
|
||||
@ -13,6 +13,7 @@ import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.base.fragment.BaseFragment
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.databinding.PieceDiscoverItemBinding
|
||||
@ -140,7 +141,7 @@ class DiscoverFragment : BaseFragment<Any>() {
|
||||
}
|
||||
|
||||
private fun showDot() {
|
||||
AppExecutor.ioExecutor.execute {
|
||||
runOnIoThread {
|
||||
val gameTrendsInfo = mGameTrendsDao.findGameTrendsInfo(UserManager.getInstance().userId)
|
||||
if (gameTrendsInfo != null) {
|
||||
AppExecutor.uiExecutor.execute {
|
||||
@ -152,7 +153,7 @@ class DiscoverFragment : BaseFragment<Any>() {
|
||||
}
|
||||
|
||||
private fun removeDot() {
|
||||
HaloApp.getInstance().mainExecutor.execute {
|
||||
runOnIoThread {
|
||||
val gameTrendsInfo = mGameTrendsDao.findGameTrendsInfo(UserManager.getInstance().userId)
|
||||
if (gameTrendsInfo != null) {
|
||||
gameTrendsInfo.readPostTime = gameTrendsInfo.internetPostTime
|
||||
|
||||
@ -131,7 +131,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
|
||||
downloadEntity.getPath()), downloadEntity.getUrl());
|
||||
|
||||
// 用户焦点在下载管理页面时有任务完成,直接把所有下载完成的任务标记为已读
|
||||
DownloadManager.getInstance(requireContext()).markDownloadedTaskAsRead();
|
||||
DownloadManager.getInstance(HaloApp.getInstance().getApplication()).markDownloadedTaskAsRead();
|
||||
} else if (DownloadStatus.cancel.equals(downloadEntity.getStatus())) { // 有可能由于网络劫持造成的
|
||||
adapter.initMap();
|
||||
adapter.notifyDataSetChanged();
|
||||
@ -389,7 +389,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
|
||||
}
|
||||
DownloadManager.getInstance(getContext()).pauseAll();
|
||||
mDownloadmanagerAllstartTv.setText("全部开始");
|
||||
mDownloadmanagerAllstartTv.setTextColor(ContextCompat.getColor(getContext(), R.color.theme));
|
||||
mDownloadmanagerAllstartTv.setTextColor(ContextCompat.getColor(getContext(), R.color.theme_font));
|
||||
}
|
||||
|
||||
private void startAll() {
|
||||
|
||||
@ -196,14 +196,14 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
0, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lparams.weight = 4;
|
||||
viewHolder.dmDownloads.setLayoutParams(lparams);
|
||||
viewHolder.dmDownloads.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.dmDownloads.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
viewHolder.dmDownloads.setText(String.format("%s(剩%s)",
|
||||
SpeedUtils.getSpeed(downloadEntity.getSpeed()),
|
||||
SpeedUtils.getRemainTime(downloadEntity.getSize(), downloadEntity.getProgress(), downloadEntity.getSpeed() * 1024)));
|
||||
viewHolder.dmDelete.setVisibility(View.GONE);
|
||||
viewHolder.dmStartorpause.setBackgroundResource(R.drawable.game_item_btn_downloading_bg);
|
||||
viewHolder.dmStartorpause.setText("暂停");
|
||||
viewHolder.dmStartorpause.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.dmStartorpause.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
viewHolder.dmSpeed.setText(downloadEntity.getPercent() + "%");
|
||||
}
|
||||
} else if (status.equals(DownloadStatus.waiting)) {
|
||||
@ -272,7 +272,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
0, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lparams.weight = 4;
|
||||
viewHolder.dmDownloads.setLayoutParams(lparams);
|
||||
viewHolder.dmDownloads.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.dmDownloads.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
viewHolder.dmDownloads.setText(String.format("%s(剩%s)",
|
||||
SpeedUtils.getSpeed(downloadEntity.getSpeed()),
|
||||
SpeedUtils.getRemainTime(downloadEntity.getSize(),
|
||||
@ -281,7 +281,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
|
||||
viewHolder.dmStartorpause.setBackgroundResource(R.drawable.game_item_btn_downloading_bg);
|
||||
viewHolder.dmStartorpause.setText("暂停");
|
||||
viewHolder.dmStartorpause.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.dmStartorpause.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
statusMap.put(url, DownloadStatus.downloading.getStatus());
|
||||
notifyItemChanged(doneList.isEmpty() ? 0 : 1 + doneList.size());
|
||||
|
||||
@ -399,7 +399,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
viewHolder.dm_item_head_tv_allstart.setTextColor(ContextCompat.getColor(mContext, R.color.btn_gray));
|
||||
} else {
|
||||
viewHolder.dm_item_head_tv_allstart.setText(R.string.download_all_start);
|
||||
viewHolder.dm_item_head_tv_allstart.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.dm_item_head_tv_allstart.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
}
|
||||
|
||||
viewHolder.dm_item_head_tv_allstart.setOnClickListener(v -> {
|
||||
@ -450,7 +450,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
// DownloadManager.getInstance(mContext).pauseAll();
|
||||
|
||||
viewHolder.dm_item_head_tv_allstart.setText("全部开始");
|
||||
viewHolder.dm_item_head_tv_allstart.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.dm_item_head_tv_allstart.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -394,7 +394,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
|
||||
}
|
||||
} else {
|
||||
viewHolder.guUpdate.setText(R.string.launch);
|
||||
viewHolder.guUpdate.setTextColor(ContextCompat.getColor(mContext, R.color.theme));
|
||||
viewHolder.guUpdate.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
|
||||
viewHolder.guUpdate.setBackgroundResource(R.drawable.detail_downloading_normal_style);
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -7,7 +7,6 @@ import android.widget.TextView
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
@ -15,6 +14,7 @@ import com.ethanhua.skeleton.ViewSkeletonScreen
|
||||
import com.gh.base.OnRequestCallBackListener
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.DownloadItemUtils
|
||||
import com.gh.common.view.FixLinearLayoutManager
|
||||
import com.gh.common.view.VerticalItemDecoration
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.MainActivity
|
||||
@ -81,7 +81,7 @@ class InstalledGameFragment : NormalFragment(), OnRequestCallBackListener<Any> {
|
||||
MainActivity.skipToMainActivity(getActivity(), MainWrapperFragment.INDEX_HOME)
|
||||
}
|
||||
|
||||
mInstallRv.layoutManager = LinearLayoutManager(requireContext())
|
||||
mInstallRv.layoutManager = FixLinearLayoutManager(requireContext())
|
||||
(mInstallRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
mAdapter = InstalledGameFragmentAdapter(this)
|
||||
mExposureListener = ExposureListener(this, mAdapter!!)
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.gamecenter.download;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.constant.ItemViewType;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureSource;
|
||||
@ -28,7 +29,6 @@ import com.gh.gamecenter.entity.GameInstall;
|
||||
import com.gh.gamecenter.game.GameItemViewHolder;
|
||||
import com.gh.gamecenter.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -97,7 +97,7 @@ public class InstalledGameFragmentAdapter extends BaseRecyclerAdapter<ViewHolder
|
||||
if (sortedList.isEmpty()) {
|
||||
mFragment.loadEmpty();
|
||||
} else {
|
||||
HaloApp.getInstance().getMainExecutor().execute(() -> {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
List<String> ids = new ArrayList<>();
|
||||
Collections.sort(sortedList, (lhs, rhs) -> { // 按安装时间排序
|
||||
if (rhs.getInstallTime() > lhs.getInstallTime()) {
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
data class AddonsUnreadEntity(
|
||||
var favorite: Int = 0//我的收藏未读
|
||||
)
|
||||
@ -19,9 +19,16 @@ data class FunctionalLinkEntity(
|
||||
var icon: String = "",// 客户端展示的icon
|
||||
@DrawableRes
|
||||
var iconRes: Int = 0, // 客户端展示的icon
|
||||
var message: String = ""
|
||||
@SerializedName("remind_switch")
|
||||
var remind: Boolean = false,//分组提醒
|
||||
var message: FunctionalMessageType? = null
|
||||
) : LinkEntity()
|
||||
|
||||
enum class FunctionalMessageType {
|
||||
NEW_VERSION,
|
||||
NEW_MESSAGE
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
data class FunctionalLinkEntity(
|
||||
|
||||
@ -161,7 +161,9 @@ data class GameEntity(
|
||||
@SerializedName("played_time")
|
||||
val playedTime: Long = 0,
|
||||
@SerializedName("played_game_id")
|
||||
val playedGameId: String = "") : Parcelable {
|
||||
val playedGameId: String = "",
|
||||
@SerializedName("mutex_package")
|
||||
val mutexPackage: List<String>? = null) : Parcelable {
|
||||
|
||||
@IgnoredOnParcel
|
||||
private var entryMap: androidx.collection.ArrayMap<String, DownloadEntity>? = androidx.collection.ArrayMap()
|
||||
|
||||
@ -4,6 +4,7 @@ import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class PersonalEntity(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
@ -13,8 +14,8 @@ data class PersonalEntity(
|
||||
val count: Count = Count(),
|
||||
val auth: Auth? = null,
|
||||
val badge: Badge? = null,
|
||||
val me: MeEntity = MeEntity()) {
|
||||
|
||||
val me: MeEntity = MeEntity()) : Parcelable {
|
||||
@Parcelize
|
||||
data class Count(
|
||||
// 包括回答点赞和社区文章点赞
|
||||
val vote: Int? = 0,
|
||||
@ -26,7 +27,7 @@ data class PersonalEntity(
|
||||
val communityArticle: Int = 0,
|
||||
@SerializedName("game_comment")
|
||||
val gameComment: Int = 0,
|
||||
val video: Int = 0) {
|
||||
val video: Int = 0) : Parcelable {
|
||||
|
||||
fun getQaCount() = answer + question + communityArticle
|
||||
}
|
||||
|
||||
@ -5,22 +5,23 @@ import com.gh.gamecenter.qa.entity.CommunityVideoEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class PersonalHistoryEntity(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val type: String = "",
|
||||
val question: Question = Question(),
|
||||
val brief: String = "",
|
||||
var question: Question = Question(),
|
||||
var brief: String = "",
|
||||
var count: Count = Count(),
|
||||
val time: Long = 0,
|
||||
val title: String = "",
|
||||
var title: String = "",
|
||||
val community: CommunityEntity = CommunityEntity(),
|
||||
var videos: List<CommunityVideoEntity> = ArrayList(),
|
||||
var user: PersonalEntity? = null,
|
||||
@SerializedName("fold_users")
|
||||
var foldUsers: List<UserEntity>? = null,
|
||||
val images: List<String> = ArrayList(),
|
||||
val comment: Comment = Comment()) {
|
||||
var comment: Comment = Comment()) :Parcelable{
|
||||
|
||||
fun getPassVideos(): List<CommunityVideoEntity> {
|
||||
val passVideos = arrayListOf<CommunityVideoEntity>()
|
||||
@ -31,23 +32,24 @@ data class PersonalHistoryEntity(
|
||||
}
|
||||
|
||||
|
||||
@Parcelize
|
||||
data class Question(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val title: String = "")
|
||||
|
||||
var title: String = ""):Parcelable
|
||||
@Parcelize
|
||||
data class Count(
|
||||
var comment: Int = -1,
|
||||
val vote: Int = -1,
|
||||
val answer: Int = -1,
|
||||
val reply: Int = -1)
|
||||
|
||||
var vote: Int = -1,
|
||||
var answer: Int = -1,
|
||||
var reply: Int = -1):Parcelable
|
||||
@Parcelize
|
||||
data class Comment(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val star: Int = 0,
|
||||
val content: String = "",
|
||||
val game: Game = Game())
|
||||
var star: Int = 0,
|
||||
var content: String = "",
|
||||
val game: Game = Game()):Parcelable
|
||||
|
||||
@Parcelize
|
||||
data class Game(
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class RatingReplyEntity(@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val content: String = "",
|
||||
@ -10,7 +13,7 @@ class RatingReplyEntity(@SerializedName("_id")
|
||||
val user: UserEntity = UserEntity(),
|
||||
var vote: Int = 0,
|
||||
val weight: Int = 0,
|
||||
val parent: Parent? = null) {
|
||||
|
||||
class Parent(val user: UserEntity)
|
||||
val parent: Parent? = null) : Parcelable {
|
||||
@Parcelize
|
||||
class Parent(val user: UserEntity) : Parcelable
|
||||
}
|
||||
@ -41,6 +41,7 @@ data class SubjectRecommendEntity(
|
||||
|
||||
@Parcelize
|
||||
data class Display(var slide: Boolean = true,
|
||||
var recommend: Boolean = true) : Parcelable
|
||||
var recommend: Boolean = true,
|
||||
var refresh: Boolean = false) : Parcelable
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class SubjectRefreshEntity(@SerializedName("column_id")
|
||||
val columnId: String = "",
|
||||
val games: List<GameEntity>)
|
||||
@ -0,0 +1,27 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
// "game": {},// 游戏详情数据
|
||||
// "articles": [],// 游戏文章
|
||||
// "toolkits": [],// 游戏工具箱
|
||||
// "libao": [],// 游戏礼包
|
||||
// "community": {},// 社区,无数据时,此字段不存在
|
||||
// "community_column_contents": []// 社区专题内容(热门回答),无数据时,此字段不存在
|
||||
|
||||
@Parcelize
|
||||
data class UnifiedGameDetailEntity(
|
||||
var game: GameDetailEntity,
|
||||
var articles: List<NewsEntity>?,
|
||||
var toolkits: List<ToolBoxEntity>?,
|
||||
var libao: List<LibaoEntity>?,
|
||||
var community: CommunityEntity?,
|
||||
@SerializedName("community_column_contents")
|
||||
var communityColumnContents: List<AnswerEntity>?) : Parcelable {
|
||||
companion object {
|
||||
const val TAG: String = "UnifiedGameDetailEntity"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class UnifiedUserTrendEntity(
|
||||
var game: List<GameDetailEntity>?,
|
||||
var toolkit: List<ToolBoxEntity>?,
|
||||
var libao: List<LibaoEntity>?,
|
||||
@SerializedName("community_column_content")
|
||||
var communityColumnContents: List<AnswerEntity>?)
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.gamecenter.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
@ -93,7 +94,7 @@ public class LoginFragment extends NormalFragment implements LoginUtils.onCaptch
|
||||
mLoginCaptcha.setText(arg1 + "s后重新获取");
|
||||
} else {
|
||||
mLoginCaptcha.setText("重新获取");
|
||||
mLoginCaptcha.setTextColor(ContextCompat.getColor(getContext(), R.color.text_1383EB));
|
||||
mLoginCaptcha.setTextColor(ContextCompat.getColor(getContext(), R.color.theme_font));
|
||||
// mLoginCaptcha.setBackgroundResource(R.drawable.border_black_bg);
|
||||
mLoginCaptcha.setEnabled(true);
|
||||
}
|
||||
@ -131,7 +132,7 @@ public class LoginFragment extends NormalFragment implements LoginUtils.onCaptch
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(getResources().getColor(R.color.theme));
|
||||
ds.setColor(getResources().getColor(R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@ -148,7 +149,7 @@ public class LoginFragment extends NormalFragment implements LoginUtils.onCaptch
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(getResources().getColor(R.color.text_1383EB));
|
||||
ds.setColor(getResources().getColor(R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
@ -268,13 +269,13 @@ public class LoginFragment extends NormalFragment implements LoginUtils.onCaptch
|
||||
mUserViewModel.retryCheckLogin();
|
||||
}
|
||||
|
||||
Object videoLinkEntity = HaloApp.get(HOST_UPLOAD_VIDEO, true);
|
||||
/*Object videoLinkEntity = HaloApp.get(HOST_UPLOAD_VIDEO, true);
|
||||
if (videoLinkEntity instanceof VideoLinkEntity) {
|
||||
startActivity(VideoManagerActivity.getIntent(
|
||||
requireContext(),
|
||||
(VideoLinkEntity) videoLinkEntity,
|
||||
EntranceUtils.ENTRANCE_BROWSER, ""));
|
||||
}
|
||||
}*/
|
||||
|
||||
if (getActivity() != null) getActivity().finish();
|
||||
}
|
||||
|
||||
@ -51,6 +51,7 @@ import com.gh.gamecenter.game.GameFragment;
|
||||
import com.gh.gamecenter.home.HomeFragment;
|
||||
import com.gh.gamecenter.manager.UserManager;
|
||||
import com.gh.gamecenter.message.MessageUnreadRepository;
|
||||
import com.gh.gamecenter.message.MessageUnreadViewModel;
|
||||
import com.gh.gamecenter.personal.PersonalFragment;
|
||||
import com.gh.gamecenter.qa.CommunityFragment;
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerFragment;
|
||||
@ -73,6 +74,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
import static com.gh.gamecenter.MainActivity.EB_SKIP_MAIN;
|
||||
@ -85,6 +87,8 @@ import static com.gh.gamecenter.MainActivity.EB_SKIP_MAIN;
|
||||
|
||||
public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implements OnBackPressedListener {
|
||||
|
||||
@BindView(R.id.view_shadow)
|
||||
View mShadowView;
|
||||
@BindView(R.id.main_tab_game)
|
||||
View mMainTab;
|
||||
@BindView(R.id.main_iv_message_hint)
|
||||
@ -121,6 +125,7 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
private SearchToolWrapperFragment mGameWrapperFragment;
|
||||
|
||||
private MainWrapperViewModel mViewModel;
|
||||
private MessageUnreadViewModel mMessageUnreadViewModel;
|
||||
private GameTrendsDao mGameTrendsDao;
|
||||
private VideoDetailContainerFragment videoDetailContainerFragment;
|
||||
private String[] resAssets = {"lottie/tab_home.json", "lottie/tab_game.json", "lottie/tab_video.json", "tab_community.gif", "tab_mine.gif"};
|
||||
@ -188,8 +193,9 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
}
|
||||
|
||||
mViewModel = ViewModelProviders.of(this).get(MainWrapperViewModel.class);
|
||||
mMessageUnreadViewModel = ViewModelProviders.of(this).get(MessageUnreadViewModel.class);
|
||||
mViewModel.getNavBar().observe(this, this::updateGameBarContent);
|
||||
mViewModel.getConcernData().observe(this, concernData -> {
|
||||
/*mViewModel.getConcernData().observe(this, concernData -> {
|
||||
if (concernData != null && concernData.size() > 0) {
|
||||
ConcernEntity entity = concernData.get(0);
|
||||
long internetPostTime = entity.getTime();
|
||||
@ -200,7 +206,7 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
EventBus.getDefault().post(new EBReuse(DiscoverFragment.SHOW_DISCOVERY_DOT));
|
||||
}
|
||||
}
|
||||
});
|
||||
});*/
|
||||
|
||||
mViewModel.getReserveDialog().observe(this, reserveData -> {
|
||||
if (reserveData != null && !reserveData.isEmpty()) {
|
||||
@ -214,6 +220,9 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
MessageUnreadRepository.INSTANCE.loadMessageUnreadData();
|
||||
}
|
||||
});
|
||||
mMessageUnreadViewModel.getUnreadMessageTotalLiveData().observe(this, isShow -> {
|
||||
mMessageHintIv.setVisibility(isShow ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
|
||||
// 判断是否是第一次启动应用,不是的话不弹启动弹窗
|
||||
if (HaloApp.get(MainWrapperViewModel.SHOULD_SHOW_OPENING_DIALOG, false) == null) {
|
||||
@ -265,7 +274,8 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mViewModel.getDiscoveryData(false);
|
||||
//mViewModel.getDiscoveryData(false);
|
||||
MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -314,10 +324,12 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
|
||||
private void changeColor(int toCheck) {
|
||||
if (toCheck == INDEX_VIDEO) {
|
||||
mShadowView.setVisibility(View.GONE);
|
||||
mCheckableGroup.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.transparent));
|
||||
changeTabImageColor(R.color.text_A1A5B7, PorterDuff.Mode.SRC_ATOP);
|
||||
changeTabTextColor(R.color.text_A1A5B7, false);
|
||||
} else {
|
||||
mShadowView.setVisibility(View.VISIBLE);
|
||||
mCheckableGroup.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
changeTabImageColor(R.color.text_50556B, PorterDuff.Mode.DST);
|
||||
changeTabTextColor(R.color.tab_selector, true);
|
||||
@ -516,7 +528,7 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
// 控制 我的光环消息未读红点
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(EBReuse reuse) {
|
||||
if (PersonalFragment.MESSAGE_READ_OVER.equals(reuse.getType())) { // 消息阅读完成
|
||||
/*if (PersonalFragment.MESSAGE_READ_OVER.equals(reuse.getType())) { // 消息阅读完成
|
||||
if (mMessageHintIv != null) {
|
||||
mMessageHintIv.setVisibility(View.GONE);
|
||||
}
|
||||
@ -524,7 +536,7 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
if (mMessageHintIv != null) {
|
||||
mMessageHintIv.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}/* else if (DiscoverFragment.SHOW_DISCOVERY_DOT.equals(reuse.getType())) {
|
||||
} else if (DiscoverFragment.SHOW_DISCOVERY_DOT.equals(reuse.getType())) {
|
||||
if (mDiscoveryHintIv != null) {
|
||||
mDiscoveryHintIv.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@ -540,7 +552,8 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
|
||||
if (mDiscoveryHintIv != null) {
|
||||
mViewModel.getDiscoveryData(true);
|
||||
}
|
||||
} */ else if ("Refresh".equals(reuse.getType())) {
|
||||
} */
|
||||
if ("Refresh".equals(reuse.getType())) {
|
||||
SettingsEntity settings = Config.getSettings();
|
||||
if (settings != null && !settings.showCommunityEntrance()) {
|
||||
mTabCommunity.setVisibility(View.GONE);
|
||||
|
||||
@ -12,7 +12,9 @@ import com.ethanhua.skeleton.Skeleton
|
||||
import com.ethanhua.skeleton.ViewSkeletonScreen
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.toJson
|
||||
import com.gh.common.util.visibleIf
|
||||
import com.gh.common.view.FixLinearLayoutManager
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
@ -29,6 +31,8 @@ import com.gh.gamecenter.normal.NormalFragment
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import com.lightgame.view.CheckableImageView
|
||||
import kotterknife.bindView
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
@ -37,6 +41,7 @@ class GameFragment : NormalFragment() {
|
||||
|
||||
private val mNoConn by bindView<View>(R.id.reuse_no_connection)
|
||||
private val mLoading by bindView<View>(R.id.reuse_ll_loading)
|
||||
private val mReplaceDataButton by bindView<CheckableImageView>(R.id.replace_data_button)
|
||||
|
||||
private lateinit var mViewModel: GameViewModel
|
||||
|
||||
@ -100,11 +105,20 @@ class GameFragment : NormalFragment() {
|
||||
layoutManager = mLayoutManager
|
||||
adapter = mListAdapter
|
||||
}
|
||||
|
||||
var listScrollHeight = 0
|
||||
mBinding.gameList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
if (mLayoutManager.findLastVisibleItemPosition() == mListAdapter.itemCount - 1
|
||||
&& RecyclerView.SCROLL_STATE_IDLE == newState) mViewModel.getSubjectList(false)
|
||||
mReplaceDataButton.isEnabled = RecyclerView.SCROLL_STATE_IDLE == newState
|
||||
}
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
listScrollHeight += dy
|
||||
mReplaceDataButton.visibleIf(mViewModel.blockData?.display?.refresh == true && listScrollHeight > 100F.dip2px())
|
||||
}
|
||||
})
|
||||
|
||||
@ -116,6 +130,14 @@ class GameFragment : NormalFragment() {
|
||||
}
|
||||
|
||||
mNoConn.setOnClickListener { mViewModel.initData() }
|
||||
mReplaceDataButton.setOnClickListener {
|
||||
val firstVisiblePosition = mLayoutManager.findFirstVisibleItemPosition()
|
||||
val lastVisiblePosition = mLayoutManager.findLastVisibleItemPosition()
|
||||
for (position in firstVisiblePosition..lastVisiblePosition) {
|
||||
val itemData = mListAdapter.getItemDataByPosition(position)
|
||||
if (itemData != null && mViewModel.replaceRefreshData(itemData)) mListAdapter.notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
mSkeleton = Skeleton.bind(mBinding.gameSkeletonContainer).shimmer(false).load(R.layout.fragment_game_skeleton).show()
|
||||
}
|
||||
@ -170,6 +192,7 @@ class GameFragment : NormalFragment() {
|
||||
fun onEventMainThread(busNine: EBUISwitch) {
|
||||
if (MainWrapperFragment.EB_MAIN_SCROLL_TOP == busNine.from
|
||||
&& MainWrapperFragment.INDEX_GAME == busNine.position) {
|
||||
mBinding.gameList.stopScroll()
|
||||
mLayoutManager.scrollToPosition(0)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user