Compare commits
164 Commits
v4.0.0-bug
...
v4.0.1-bug
| Author | SHA1 | Date | |
|---|---|---|---|
| e1fc23a1bb | |||
| 2d551a3f73 | |||
| 9b205366f7 | |||
| 4727f22b0f | |||
| a3d693ddc1 | |||
| 79cbb44d51 | |||
| dcde3db33a | |||
| 44fbc7a182 | |||
| d7a85edb76 | |||
| ceb9dc6707 | |||
| b0f20ee017 | |||
| cdf78f2bc5 | |||
| d3f0a8fe4a | |||
| 17acf1bd86 | |||
| 31a0bb24c7 | |||
| 13ff1f4343 | |||
| ec76be9d5e | |||
| 84d53616a0 | |||
| 2758216ae2 | |||
| c492f066ca | |||
| 897478e30e | |||
| a94d825ead | |||
| ba05e6137e | |||
| dc55342343 | |||
| 3ea96d27db | |||
| 48842c099b | |||
| 4f87cac46a | |||
| 52680b63b9 | |||
| f89defc78f | |||
| 46e9a161a4 | |||
| 8e602e8169 | |||
| c60df98577 | |||
| ad7db50336 | |||
| e40ef5292e | |||
| 94b844788c | |||
| 9c222baf91 | |||
| 0794606e57 | |||
| be34c486bf | |||
| fa7a5fef9b | |||
| 9e518d5414 | |||
| 2d17ecd438 | |||
| 56d6c28811 | |||
| 86b77e29e2 | |||
| 23b8b09834 | |||
| 30eb397c66 | |||
| 05bcc0f818 | |||
| 3f9434239f | |||
| 4caf7eabc0 | |||
| 0aee08bbb0 | |||
| 602dbff3c8 | |||
| d52cfd475f | |||
| 4512accb37 | |||
| 2d57c00149 | |||
| cae908da6a | |||
| 38f97673b8 | |||
| ed2bf89413 | |||
| 259d343e31 | |||
| 8e9dbafb4d | |||
| 7e737d7a46 | |||
| 50fd30d173 | |||
| 4c7310f71e | |||
| b3e7168922 | |||
| 261cc5b0eb | |||
| 60218eea97 | |||
| bc1945326a | |||
| 2fd12d56ed | |||
| cb28838b40 | |||
| 4cfd6952c0 | |||
| f5761e378e | |||
| 314144c384 | |||
| 81debc1cd8 | |||
| 9a2baf1d8c | |||
| 55ec26bd3d | |||
| 4c372eeb2b | |||
| c2f9e28edd | |||
| 65a8297fe0 | |||
| 1a48cca197 | |||
| 24984b5d67 | |||
| 619660e5e5 | |||
| c9c4a996dc | |||
| b8ae8b68dc | |||
| a9f4620d8b | |||
| 66abdb1eed | |||
| 1dc4be2d54 | |||
| a286f51801 | |||
| 27708da1bf | |||
| 3aa0e19b0f | |||
| 4d5627348a | |||
| 2aefeb5e53 | |||
| 728b663c7a | |||
| 36156cddc4 | |||
| 2b98702ceb | |||
| 2c2ab02398 | |||
| 8ae8c6d6fb | |||
| 1171424f19 | |||
| 3444922861 | |||
| 5821a519ee | |||
| 439a2353b0 | |||
| 8f8f3193dd | |||
| 5907b8b1a5 | |||
| ba5783417e | |||
| 56573deea1 | |||
| 892933888c | |||
| b3725baad0 | |||
| cf79735780 | |||
| ad059fe18d | |||
| 03fa2052da | |||
| d7d55b7341 | |||
| 6ea9a7de90 | |||
| 3bc65f42c7 | |||
| 854227304f | |||
| 62d34c6c06 | |||
| 69f0beff9c | |||
| 2a32859c48 | |||
| c6bdb4ee8d | |||
| cf5e981758 | |||
| 2bf246562b | |||
| c1cd25b89b | |||
| 2eb259055a | |||
| fe743590c9 | |||
| d3de1c238c | |||
| 931593d726 | |||
| 8f002fc804 | |||
| 10e0d0123e | |||
| b93cb06662 | |||
| 5471099e7b | |||
| 5a2f86be87 | |||
| 3d7ce17b07 | |||
| cf0e237529 | |||
| 60c84153e5 | |||
| f9a8efe084 | |||
| 6b48c546c4 | |||
| b1893718f6 | |||
| 7ad95d5f26 | |||
| 778b0e8f16 | |||
| ad847f6113 | |||
| 27778c2b31 | |||
| 484694cbdb | |||
| 969680a7ad | |||
| 6357e008dc | |||
| a570cfe32b | |||
| ccba561d47 | |||
| f5abd7e075 | |||
| 35cd97c751 | |||
| 147bc150f5 | |||
| 7f0e59aba5 | |||
| 6986bd9a57 | |||
| a6feb57f85 | |||
| 50fee01249 | |||
| 4ff12e91aa | |||
| 24b196f216 | |||
| d36b2f99ee | |||
| 704b73aef7 | |||
| 72cfcd66b1 | |||
| 0cb65ab216 | |||
| d18731ccfe | |||
| 91f79a5ff1 | |||
| d37929548e | |||
| 663891dd54 | |||
| 79d1c4fed4 | |||
| ecc8196701 | |||
| 83e44808cb | |||
| bfbc9900ed | |||
| 1735ba3312 |
@ -65,6 +65,8 @@ android {
|
||||
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
|
||||
buildConfigField "String", "MTA_APPKEY", "\"${MTA_APPKEY}\""
|
||||
buildConfigField "String", "TD_APPID", "\"${TD_APPID}\""
|
||||
buildConfigField "String", "LETO_APPID", "\"${LETO_APPID}\""
|
||||
buildConfigField "String", "TTAD_APPID", "\"${TTAD_APPID}\""
|
||||
|
||||
/**
|
||||
* Build Time 供区分 jenkins 打包时间用
|
||||
@ -121,7 +123,6 @@ android {
|
||||
publish {
|
||||
dimension "nonsense"
|
||||
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
|
||||
buildConfigField "String", "COMMENT_HOST", "\"${COMMENT_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${UMENG_MESSAGE_SECRET}\""
|
||||
@ -138,7 +139,6 @@ android {
|
||||
versionNameSuffix "-debug"
|
||||
|
||||
buildConfigField "String", "API_HOST", "\"${DEV_API_HOST}\""
|
||||
buildConfigField "String", "COMMENT_HOST", "\"${DEV_COMMENT_HOST}\""
|
||||
|
||||
buildConfigField "String", "UMENG_APPKEY", "\"${DEBUG_UMENG_APPKEY}\""
|
||||
buildConfigField "String", "UMENG_MESSAGE_SECRET", "\"${DEBUG_UMENG_MESSAGE_SECRET}\""
|
||||
@ -171,7 +171,7 @@ rebuildChannel {
|
||||
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs/aars'
|
||||
dirs 'libs','libs/aars'
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,9 +195,6 @@ dependencies {
|
||||
implementation "androidx.annotation:annotation:${annotation}"
|
||||
implementation "androidx.constraintlayout:constraintlayout:${constraintLayout}"
|
||||
implementation "androidx.recyclerview:recyclerview:${recyclerView}"
|
||||
// implementation "androidx.lifecycle:lifecycle-runtime:${lifeCycle}"
|
||||
// implementation "androidx.lifecycle:lifecycle-extensions:${lifeCycle}"
|
||||
// kapt "androidx.lifecycle:lifecycle-compiler:${lifeCycle}"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifeCycle"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifeCycle"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifeCycle"
|
||||
@ -206,7 +203,6 @@ dependencies {
|
||||
implementation "androidx.core:core-ktx:${ktx}"
|
||||
implementation "androidx.viewpager2:viewpager2:${viewpager2}"
|
||||
kapt "androidx.room:room-compiler:${room}"
|
||||
// kapt "androidx.databinding:databinding-compiler:${databinding}"
|
||||
|
||||
implementation "com.google.android.material:material:${material}"
|
||||
|
||||
@ -297,9 +293,6 @@ 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')
|
||||
|
||||
@ -240,4 +240,12 @@
|
||||
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
|
||||
-dontwarn com.shuyu.gsyvideoplayer.utils.**
|
||||
-keep class tv.danmaku.ijk.** { *; }
|
||||
-dontwarn tv.danmaku.ijk.**
|
||||
-dontwarn tv.danmaku.ijk.**
|
||||
|
||||
#穿山甲
|
||||
-keep class com.bytedance.sdk.openadsdk.** { *; }
|
||||
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
|
||||
-keep class com.pgl.sys.ces.* {*;}
|
||||
|
||||
-keep class com.gyf.immersionbar.* {*;}
|
||||
-dontwarn com.gyf.immersionbar.**
|
||||
@ -36,6 +36,15 @@
|
||||
<uses-permission android:name="android.permission.READ_LOGS" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<!--可选,穿山甲提供“获取地理位置权限”和“不给予地理位置权限,开发者传入地理位置参数”两种方式上报用户位置,两种方式均可不选,添加位置权限或参数将帮助投放定位广告-->
|
||||
<!--请注意:无论通过何种方式提供给穿山甲用户地理位置,均需向用户声明地理位置权限将应用于穿山甲广告投放,穿山甲不强制获取地理位置信息-->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
|
||||
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,
|
||||
com.shuyu.gsyvideoplayer.lib,
|
||||
com.shuyu.gsyvideoplayer.armv7a,
|
||||
@ -44,7 +53,13 @@
|
||||
com.google.android.exoplayer2,
|
||||
tv.danmaku.ijk.media.exo2,
|
||||
shuyu.com.androidvideocache,
|
||||
pl.droidsonroids.gif" />
|
||||
pl.droidsonroids.gif,
|
||||
com.ledong.lib.minigame,
|
||||
com.ledong.lib.leto,
|
||||
com.leto.game.base.glide4,
|
||||
com.leto.game.ad.gdt,
|
||||
com.leto.game.fcm,
|
||||
com.leto.game.ad.toutiao" />
|
||||
|
||||
<!-- 去掉 SDK 一些流氓权限 -->
|
||||
<uses-permission
|
||||
@ -161,6 +176,7 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:name="com.gh.gamecenter.MessageDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
@ -191,6 +207,7 @@
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.CommentDetailActivity"
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
@ -401,6 +418,7 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:theme="@style/TransparentStatusBarAndNavigationBar"
|
||||
android:name="com.gh.gamecenter.gamedetail.rating.RatingReplyActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
@ -492,6 +510,10 @@
|
||||
android:name="com.gh.gamecenter.QaActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".qa.answer.draft.AnswerDraftActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 使用小米/华为推送弹窗功能提高推送成功率-->
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.PushProxyActivity"
|
||||
@ -587,6 +609,39 @@
|
||||
|
||||
<!--<service android:name = "com.gh.gamecenter.statistics.AppStaticService" />-->
|
||||
|
||||
<!-- 梦工厂配置 开始 -->
|
||||
<!--<meta-data
|
||||
android:name="MGC_APPID"
|
||||
android:value="1001276" />
|
||||
|
||||
<provider
|
||||
android:name="com.leto.game.base.provider.LetoFileProvider"
|
||||
android:authorities="${applicationId}.leto.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/leto_file_path"
|
||||
tools:replace="android:resource" />
|
||||
</provider>-->
|
||||
<!-- 梦工厂配置 结束 -->
|
||||
|
||||
<!-- 穿山甲配置 开始 -->
|
||||
<!--<provider
|
||||
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
|
||||
android:authorities="${applicationId}.TTFileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
|
||||
android:authorities="${applicationId}.TTMultiProvider"
|
||||
android:exported="false" />-->
|
||||
<!-- 穿山甲配置 结束 -->
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
File diff suppressed because one or more lines are too long
@ -11,6 +11,7 @@ import android.text.TextUtils;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.gh.base.fragment.BaseFragment;
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
@ -36,6 +37,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import butterknife.ButterKnife;
|
||||
import pub.devrel.easypermissions.EasyPermissions;
|
||||
@ -182,6 +184,11 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy
|
||||
super.onPause();
|
||||
if (isFinishing()) {
|
||||
onFinish();
|
||||
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
|
||||
if (fragment.isAdded() && fragment instanceof BaseFragment) {
|
||||
((BaseFragment) fragment).onParentActivityFinish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.widget.TextView
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
@ -16,6 +17,7 @@ import com.gh.common.view.RichEditor
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity
|
||||
import com.gh.gamecenter.qa.editor.GameActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertAnswerWrapperActivity
|
||||
import com.gh.gamecenter.qa.editor.InsertArticleWrapperActivity
|
||||
@ -31,6 +33,7 @@ import kotterknife.bindView
|
||||
abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
|
||||
val mRichEditor by bindView<RichEditor>(R.id.rich_editor)
|
||||
val mDraftBtn by bindView<TextView>(R.id.draft_btn)
|
||||
|
||||
private val mEditorFont by bindView<CheckableImageView>(R.id.editor_font)
|
||||
private val mEditorLink by bindView<CheckableImageView>(R.id.editor_link)
|
||||
@ -87,6 +90,10 @@ abstract class BaseRichEditorActivity : ToolBarActivity() {
|
||||
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
|
||||
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
|
||||
mRichEditor.setInputEnabled(true)
|
||||
|
||||
mDraftBtn.text = if (this is AnswerEditActivity) {
|
||||
"回答草稿"
|
||||
} else "文章草稿"
|
||||
}
|
||||
|
||||
@OnClick(R.id.editor_image, R.id.editor_font, R.id.editor_link, R.id.editor_paragraph,
|
||||
|
||||
@ -12,11 +12,9 @@ import android.preference.PreferenceManager
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.text.htmlEncode
|
||||
import com.gh.common.notifier.Notifier
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.StringUtils
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.PushEntity
|
||||
import com.gh.gamecenter.entity.PushMessageEntity
|
||||
@ -132,7 +130,7 @@ class GHUmengNotificationService : UmengMessageService() {
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setTicker(pushData.body?.ticker)
|
||||
.setContentTitle(pushData.body?.title)
|
||||
.setContentText(pushData.body?.text)
|
||||
.setContentText(pushData.body?.text?.fromHtml())
|
||||
.setContentIntent(clickPendingIntent)
|
||||
.setDeleteIntent(deletePendingIntent)
|
||||
.build()
|
||||
|
||||
@ -3,7 +3,6 @@ package com.gh.base;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
@ -12,7 +11,6 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
@ -52,6 +50,8 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
@Nullable
|
||||
private PackageViewModel mPackageViewModel;
|
||||
|
||||
protected RelativeLayout mToolbarContainer;
|
||||
|
||||
protected Toolbar mToolbar;
|
||||
|
||||
protected TextView mTitleTv;
|
||||
@ -62,7 +62,6 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setStatusBarDarkMode(true, this);
|
||||
initToolbar();
|
||||
|
||||
@ -88,6 +87,7 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
mToolbarContainer = findViewById(R.id.normal_toolbar_container);
|
||||
mToolbar = findViewById(R.id.normal_toolbar);
|
||||
mTitleTv = findViewById(R.id.normal_title);
|
||||
if (mToolbar != null) {
|
||||
@ -253,4 +253,11 @@ public abstract class ToolBarActivity extends BaseActivity implements ToolbarCon
|
||||
protected boolean showDownloadMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideToolbar(boolean isHide) {
|
||||
if (mToolbarContainer != null) {
|
||||
mToolbarContainer.setVisibility(isHide ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,14 +9,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.base.OnListClickListener;
|
||||
import com.gh.base.OnRequestCallBackListener;
|
||||
import com.gh.common.constant.Constants;
|
||||
@ -37,6 +29,13 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.ButterKnife;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
@ -304,6 +303,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
|
||||
return this;
|
||||
}
|
||||
|
||||
public void onParentActivityFinish() {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected RecyclerView.Adapter provideSyncAdapter() {
|
||||
return null;
|
||||
|
||||
@ -4,20 +4,18 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.LibaoDetailActivity
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
|
||||
import com.gh.common.util.DirectUtils.directToGameVideo
|
||||
import com.gh.common.util.DirectUtils.directToVideoDetail
|
||||
import com.gh.gamecenter.*
|
||||
import com.gh.gamecenter.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.VideoLinkEntity
|
||||
import com.gh.gamecenter.subject.SubjectActivity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
|
||||
object DefaultWebViewUrlHandler {
|
||||
|
||||
@JvmStatic
|
||||
@ -135,19 +133,78 @@ object DefaultWebViewUrlHandler {
|
||||
val position = uri.getQueryParameter("position")
|
||||
DirectUtils.directToHomeActivity(context, id, if (position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_VIDEO_MORE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
val type = uri.getQueryParameter("type") ?: ""
|
||||
val act = uri.getQueryParameter("act") ?: ""
|
||||
val loaction = if (TextUtils.isEmpty(act)) id else VideoDetailContainerViewModel.Location.VIDEO_ACTIVITY.value
|
||||
DirectUtils.directToVideoDetail(context, id, loaction, false, "", entrance, "", referer, type, act)
|
||||
directToVideoDetail(context, id, loaction, false, "", entrance, "", referer, type, act)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_SINGLE -> {
|
||||
val referer = uri.getQueryParameter("referer") ?: ""
|
||||
directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
|
||||
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_STREAMING_HOME -> {
|
||||
intent = Intent(context, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_STREAMING_DESC -> {
|
||||
directToGameDetailVideoStreaming(context, id, entrance)
|
||||
}
|
||||
EntranceUtils.HOST_VIDEO_COLLECTION -> {
|
||||
directToGameVideo(context, id, entrance, "")
|
||||
}
|
||||
|
||||
EntranceUtils.HOST_CATEGORY -> {
|
||||
val title = uri.getQueryParameter("title")
|
||||
DirectUtils.directCategoryDirectory(context, id, title ?: "", entrance, "")
|
||||
}
|
||||
EntranceUtils.HOST_COLUMN_COLLECTION -> {
|
||||
val name = uri.getQueryParameter("name")
|
||||
DirectUtils.directToColumnCollection(context, id, -1, entrance, name ?: "")
|
||||
}
|
||||
EntranceUtils.HOST_COLUMN -> {
|
||||
DirectUtils.directToSubject(context, id, uri.getQueryParameter(EntranceUtils.KEY_NAME), entrance)
|
||||
}
|
||||
EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = uri.getQueryParameter("community_id") ?: ""
|
||||
community.name = uri.getQueryParameter("community_name") ?: ""
|
||||
val tag = uri.getQueryParameter("tag") ?: ""
|
||||
DirectUtils.directAskColumnLabelDetail(context, tag, community, entrance, "")
|
||||
}
|
||||
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL -> {
|
||||
val community = CommunityEntity()
|
||||
community.id = uri.getQueryParameter("community_id") ?: ""
|
||||
community.name = uri.getQueryParameter("community_name") ?: ""
|
||||
val columnId = uri.getQueryParameter("column_id") ?: ""
|
||||
DirectUtils.directAskColumnDetail(context, columnId, community, entrance, "")
|
||||
}
|
||||
|
||||
else -> DialogUtils.showLowVersionDialog(context)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (url.startsWith("alipays:") || url.startsWith("alipay")) {
|
||||
try {
|
||||
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
|
||||
} catch (e: java.lang.Exception) {
|
||||
ToastUtils.showToast("请安装支付宝客户端")
|
||||
}
|
||||
return true
|
||||
} else if (url.startsWith("weixin")) {
|
||||
try {
|
||||
context.startActivity(Intent("android.intent.action.VIEW", Uri.parse(url)))
|
||||
} catch (e: java.lang.Exception) {
|
||||
ToastUtils.showToast("请安装微信客户端")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if ("http" != uri.scheme && "https" != uri.scheme) return true
|
||||
return false
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@ import io.reactivex.schedulers.Schedulers;
|
||||
public class Config {
|
||||
|
||||
public static final String API_HOST = BuildConfig.API_HOST;
|
||||
public static final String COMMENT_HOST = BuildConfig.COMMENT_HOST;
|
||||
|
||||
/**
|
||||
* 需要配置的请使用{@link PreferenceManager#getDefaultSharedPreferences(Context)}
|
||||
@ -49,6 +48,8 @@ public class Config {
|
||||
public static final String UMENG_APPKEY = BuildConfig.UMENG_APPKEY;
|
||||
public static final String UMENG_MESSAGE_SECRET = BuildConfig.UMENG_MESSAGE_SECRET;
|
||||
public static final String BUGLY_APPID = BuildConfig.BUGLY_APPID;
|
||||
public static final String LETO_APPID = BuildConfig.LETO_APPID;
|
||||
public static final String TTAD_APPID = BuildConfig.TTAD_APPID;
|
||||
// http://www.ghzs666.com/article/${articleId}.html
|
||||
public static final String URL_ARTICLE = "http://www.ghzs666.com/article/"; // ghzs/ghzs666 统一
|
||||
public static final String PATCHES = "patches";
|
||||
|
||||
@ -28,8 +28,16 @@ public class Constants {
|
||||
public static final String XPOSED_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
||||
|
||||
public static final String EB_QUIT_LOGIN = "quit_login";
|
||||
|
||||
public static final String GAME_ID_DIVIDER = ":"; // 用于避免历史下载掺和到普通下载状态的 ID 修饰符
|
||||
|
||||
// 用于避免历史下载掺和到普通下载状态的 ID 修饰符
|
||||
public static final String GAME_ID_DIVIDER = ":";
|
||||
// 用于避免历史下载影响到部分依赖名字作为数据更新条件的修饰符
|
||||
public static final String GAME_NAME_DECORATOR = " ";
|
||||
|
||||
// 游戏详情进入时的自定义栏目标签是否已经默认展开过一次的标记
|
||||
public static final String SP_HAS_EXPANDED_GAME_DETAIL_TAGS = "has_expanded_game_detail_tags";
|
||||
// 游戏详情进入时的自定义栏目标签是否已经显示过一次展开更多的浮窗提示
|
||||
public static final String SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT = "has_shown_expanded_game_detail_tags_hint";
|
||||
|
||||
// 最近显示的弹窗信息
|
||||
public static final String SP_LAST_OPENING_ID = "last_opening_dialog_id";
|
||||
@ -73,9 +81,11 @@ public class Constants {
|
||||
//游戏设备弹窗不再提示
|
||||
public static final String SP_NO_REMIND_AGAIN = "no_remind_again";
|
||||
//游戏详情过滤标签数据
|
||||
public static final String SP_FILTER_TAGS= "filter_tags";
|
||||
public static final String SP_FILTER_TAGS = "filter_tags";
|
||||
//实名认证弹窗分类数据
|
||||
public static final String SP_AUTH_DIALOG= "auth_dialog";
|
||||
public static final String SP_AUTH_DIALOG = "auth_dialog";
|
||||
//顶部视频进度保存,重启恢复
|
||||
public static final String SP_TOP_VIDEO_SCHEDULE = "top_video_schedule";
|
||||
|
||||
//手机号码匹配规则
|
||||
public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
|
||||
@ -112,13 +122,16 @@ public class Constants {
|
||||
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)";
|
||||
|
||||
public static final String DEFAULT_TEXT_WRAPPER = "###";
|
||||
|
||||
|
||||
// 触发了安装事件的标记
|
||||
public static final String MARK_ALREADY_TRIGGERED_INSTALLATION = "triggered_installation";
|
||||
|
||||
// 标记下载重试标记(值为任务已下载大小,为空表示需要重试)
|
||||
public static final String MARK_RETRY_DOWNLOAD = "retry_download";
|
||||
}
|
||||
|
||||
@ -13,19 +13,13 @@ import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.base.OnViewClickListener;
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.DataUtils;
|
||||
@ -59,6 +53,7 @@ import com.gh.gamecenter.entity.LinkEntity;
|
||||
import com.gh.gamecenter.entity.PluginLocation;
|
||||
import com.gh.gamecenter.entity.ServerCalendarEntity;
|
||||
import com.gh.gamecenter.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.entity.TestEntity;
|
||||
import com.gh.gamecenter.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
|
||||
@ -69,9 +64,16 @@ import com.lightgame.utils.Utils;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
/**
|
||||
* Created by khy on 12/02/18.
|
||||
*/
|
||||
@ -236,6 +238,14 @@ public class BindingAdapters {
|
||||
view.setPadding(view.getPaddingLeft(), DisplayUtils.dip2px(paddingTopInDp), view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
|
||||
/**
|
||||
* lazy 的 paddingBottom
|
||||
*/
|
||||
@BindingAdapter("lazyPaddingBottom")
|
||||
public static void lazyPaddingBottom(View view, int paddingBottomInDp) {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), DisplayUtils.dip2px(paddingBottomInDp));
|
||||
}
|
||||
|
||||
@BindingAdapter("visibleInvisible")
|
||||
public static void visibleInvisible(View view, Boolean show) {
|
||||
if (show != null && show) {
|
||||
@ -411,6 +421,7 @@ public class BindingAdapters {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
});
|
||||
@ -425,6 +436,7 @@ public class BindingAdapters {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
}
|
||||
@ -465,9 +477,15 @@ public class BindingAdapters {
|
||||
}
|
||||
break;
|
||||
case H5_GAME:
|
||||
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
|
||||
LinkEntity linkEntity = gameEntity.getH5Link();
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), "play".equals(linkEntity.getType())));
|
||||
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
|
||||
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
|
||||
|
||||
if (isPlay) {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
}
|
||||
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(progressBar.getContext(), linkEntity.getLink(), gameEntity.getName(), isPlay));
|
||||
progressBar.getContext().startActivity(i);
|
||||
break;
|
||||
}
|
||||
@ -613,9 +631,6 @@ public class BindingAdapters {
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(progressBar.getContext(), gameEntity.getName(), apkEntity.getPlatform(), entrance, "下载开始", method);
|
||||
|
||||
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, method);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
|
||||
|
||||
DownloadManager.createDownload(progressBar.getContext(),
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
@ -623,7 +638,7 @@ public class BindingAdapters {
|
||||
entrance,
|
||||
location + gameEntity.getName(),
|
||||
isSubscribe,
|
||||
downloadExposureEvent);
|
||||
traceEvent);
|
||||
|
||||
progressBar.setProgress(0);
|
||||
progressBar.setDownloadType("插件化".equals(method) ?
|
||||
@ -638,6 +653,33 @@ public class BindingAdapters {
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
|
||||
}
|
||||
|
||||
// 包含测试开服标签
|
||||
@BindingAdapter("setGameTags")
|
||||
public static void setGameTags(LinearLayout layout, GameEntity gameEntity) {
|
||||
try {
|
||||
ArrayList<TagStyleEntity> tagStyle = new ArrayList<>();
|
||||
TestEntity test = gameEntity.getTest();
|
||||
if (test != null) {
|
||||
TagStyleEntity typeTag = new TagStyleEntity();
|
||||
typeTag.setName(test.getType() != null ? test.getType() : "");
|
||||
typeTag.setBackground("FFF3E0");
|
||||
typeTag.setColor("FA8500");
|
||||
tagStyle.add(typeTag);
|
||||
|
||||
TagStyleEntity timeTag = new TagStyleEntity();
|
||||
timeTag.setName(GameViewUtils.getGameTestDate(test.getStart()));
|
||||
timeTag.setBackground("E0FFF9");
|
||||
timeTag.setColor("00A887");
|
||||
tagStyle.add(timeTag);
|
||||
} else {
|
||||
tagStyle = gameEntity.getTagStyle();
|
||||
}
|
||||
GameViewUtils.setLabelList(layout.getContext(), layout, tagStyle);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("isRefreshing")
|
||||
public static void isRefreshing(SwipeRefreshLayout layout, LoadStatus status) {
|
||||
if (status != LoadStatus.INIT_LOADING && status != LoadStatus.LIST_LOADING) {
|
||||
|
||||
@ -30,7 +30,6 @@ import com.halo.assistant.fragment.SettingsFragment.AUTO_INSTALL_SP_KEY
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.android.synthetic.main.dialog_device_remind.view.*
|
||||
import java.lang.ref.WeakReference
|
||||
@ -179,7 +178,7 @@ class DeviceRemindDialog(context: Context, val entity: DeviceDialogEntity, val g
|
||||
|
||||
inner class BannerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_ad_banner, parent, false)) {}
|
||||
return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_device_remind_banner, parent, false)) {}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = if (mDatas.size == 1) mDatas.size else Int.MAX_VALUE
|
||||
|
||||
@ -15,6 +15,7 @@ import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.common.repository.ReservationRepository
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
@ -49,6 +50,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
|
||||
private var mSuccessCallback: SuccessCallback? = null
|
||||
|
||||
private var mGame: GameEntity? = null
|
||||
private var mGameId: String = ""
|
||||
private var mGameName: String = ""
|
||||
|
||||
@ -86,6 +88,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
if (it.success) {
|
||||
showSuccessDialog(it.withMobile, it.boundWechat)
|
||||
mSuccessCallback?.onSuccess()
|
||||
HistoryHelper.insertGameEntity(mGame!!)
|
||||
}
|
||||
}
|
||||
dialog?.setCanceledOnTouchOutside(true)
|
||||
@ -149,6 +152,7 @@ class ReserveDialogFragment : BaseTrackableDialogFragment() {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(gameEntity: GameEntity, successCallback: SuccessCallback) = ReserveDialogFragment().apply {
|
||||
this.mGame = gameEntity
|
||||
this.mGameId = gameEntity.id
|
||||
this.mGameName = gameEntity.name ?: ""
|
||||
this.mSuccessCallback = successCallback
|
||||
|
||||
@ -4,6 +4,7 @@ import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.meta.Meta
|
||||
import com.gh.common.exposure.meta.MetaUtil
|
||||
import com.gh.common.exposure.time.TimeUtil
|
||||
@ -28,7 +29,7 @@ data class ExposureEvent(
|
||||
fun createEvent(gameEntity: GameEntity?, source: List<ExposureSource>, eTrace: List<ExposureEvent>? = null, event: ExposureType = ExposureType.EXPOSURE): ExposureEvent {
|
||||
return ExposureEvent(
|
||||
payload = ExposureEntity(gameId = gameEntity?.id,
|
||||
gameName = gameEntity?.name,
|
||||
gameName = gameEntity?.name?.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
sequence = gameEntity?.sequence,
|
||||
platform = gameEntity?.platform,
|
||||
downloadType = gameEntity?.downloadType,
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.g00fy2.versioncompare.Version
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.toObject
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
@ -15,6 +17,11 @@ object ExposureUtils {
|
||||
traceEvent: ExposureEvent?,
|
||||
downloadType: DownloadType): ExposureEvent {
|
||||
val gameEntity = entity.clone()
|
||||
gameEntity.id = if (entity.id.contains(Constants.GAME_ID_DIVIDER)) {
|
||||
entity.id.split(Constants.GAME_ID_DIVIDER).toTypedArray()[0]
|
||||
} else {
|
||||
entity.id
|
||||
}
|
||||
gameEntity.platform = platform
|
||||
gameEntity.downloadType = downloadType.toString()
|
||||
val exposureEvent = ExposureEvent.createEvent(gameEntity = gameEntity,
|
||||
@ -43,29 +50,26 @@ object ExposureUtils {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDownloadType(apkEntity: ApkEntity, method: String) : DownloadType {
|
||||
return if ("更新" == method) {
|
||||
if (PackageUtils.isSignature(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
DownloadType.PLUGIN_UPDATE
|
||||
fun getDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
|
||||
return if (PackageUtils.isInstalled(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
if (PackageUtils.isSignedByGh(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
if (PackageUtils.isCanUpdate(apkEntity, gameId)) {
|
||||
DownloadType.PLUGIN_UPDATE
|
||||
} else {
|
||||
if (Version(apkEntity.version).isHigherThan(PackageUtils.getVersionByPackage(apkEntity.packageName))) {
|
||||
DownloadType.UPDATE
|
||||
} else {
|
||||
DownloadType.DOWNLOAD
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DownloadType.UPDATE
|
||||
DownloadType.PLUGIN_DOWNLOAD
|
||||
}
|
||||
} else if ("插件化" == method) {
|
||||
DownloadType.PLUGIN_DOWNLOAD
|
||||
} else {
|
||||
DownloadType.DOWNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUpdateType(apkEntity: ApkEntity) : DownloadType {
|
||||
return if (PackageUtils.isSignature(HaloApp.getInstance().application, apkEntity.packageName)) {
|
||||
DownloadType.PLUGIN_UPDATE
|
||||
} else {
|
||||
DownloadType.UPDATE
|
||||
}
|
||||
}
|
||||
|
||||
enum class DownloadType {
|
||||
DOWNLOAD,
|
||||
|
||||
|
||||
@ -4,9 +4,7 @@ import com.gh.common.runOnIoThread
|
||||
import com.gh.common.util.clearHtmlFormatCompletely
|
||||
import com.gh.common.util.removeInsertedContent
|
||||
import com.gh.common.util.removeVideoContent
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.HistoryGameEntity
|
||||
import com.gh.gamecenter.entity.NewsEntity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.qa.entity.AnswerDetailEntity
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
@ -24,11 +22,32 @@ object HistoryHelper {
|
||||
runOnIoThread { HistoryDatabase.instance.articleDao().addArticle(articleEntity) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun insertGameEntity(gameEntity: GameEntity) {
|
||||
val historyGameEntity = convertGameEntityToHistoryGameEntity(gameEntity)
|
||||
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun insertGameEntity(updateEntity: GameUpdateEntity) {
|
||||
val historyGameEntity = convertGameUpdateEntityToHistoryGameEntity(updateEntity)
|
||||
runOnIoThread { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) }
|
||||
}
|
||||
|
||||
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity{
|
||||
val historyGame = HistoryGameEntity()
|
||||
|
||||
historyGame.orderTag = System.currentTimeMillis()
|
||||
historyGame.id = updateEntity.id
|
||||
historyGame.brief = updateEntity.brief
|
||||
historyGame.des = ""
|
||||
historyGame.icon = updateEntity.icon
|
||||
historyGame.name = updateEntity.name
|
||||
historyGame.tagStyle = updateEntity.tagStyle
|
||||
historyGame.tag = updateEntity.tag
|
||||
return historyGame
|
||||
}
|
||||
|
||||
private fun convertGameEntityToHistoryGameEntity(gameEntity: GameEntity): HistoryGameEntity {
|
||||
val historyGame = HistoryGameEntity()
|
||||
|
||||
@ -70,6 +89,11 @@ object HistoryHelper {
|
||||
runOnIoThread { HistoryDatabase.instance.answerDao().deleteAnswer(AnswerEntity().apply { primaryKey = answerId }) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteVideoEntity(videoId: String) {
|
||||
runOnIoThread { HistoryDatabase.instance.videoHistoryDao().deleteVideo(MyVideoEntity().apply { id = videoId }) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun emptyDatabase() {
|
||||
runOnIoThread { HistoryDatabase.instance.clearAllTables() }
|
||||
|
||||
@ -10,6 +10,7 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.gh.base.CurrentActivityHolder
|
||||
import com.gh.common.util.doOnMainProcessOnly
|
||||
import com.gh.gamecenter.R
|
||||
import com.m7.imkfsdk.chat.ChatActivity
|
||||
import com.m7.imkfsdk.utils.Utils
|
||||
@ -25,51 +26,53 @@ class ImReceiver : BroadcastReceiver() {
|
||||
var notificationManager: NotificationManager? = null
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
intent?.let {
|
||||
if (intent.action == IMChatManager.NEW_MSG_ACTION) {
|
||||
notificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
// 判断 ImActivity 是否在最顶端
|
||||
if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
|
||||
ImManager.showFloatingWindow()
|
||||
ImManager.updateShouldShowFloatingWindowDot(false)
|
||||
} else {
|
||||
val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
|
||||
|
||||
contentIntent.putExtra("PeerId", "")
|
||||
contentIntent.putExtra("type", "peedId")
|
||||
|
||||
contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
val resultPendingIntent = PendingIntent.getActivity(
|
||||
Utils.getApp(),
|
||||
0,
|
||||
contentIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
// 新的通知
|
||||
val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
|
||||
val notification = builder.setTicker("您有新的消息")
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(resultPendingIntent)
|
||||
.setContentTitle("光环助手客服回复")
|
||||
.setContentText("您有新的消息")
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
notificationManager?.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
if (notification != null) {
|
||||
notificationManager?.notify(NOTIFICATION_ID, notification)
|
||||
context?.doOnMainProcessOnly {
|
||||
intent?.let {
|
||||
if (intent.action == IMChatManager.NEW_MSG_ACTION) {
|
||||
notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
// 判断 ImActivity 是否在最顶端
|
||||
if (CurrentActivityHolder.getCurrentActivity() is ChatActivity) {
|
||||
ImManager.showFloatingWindow()
|
||||
ImManager.updateShouldShowFloatingWindowDot(false)
|
||||
} else {
|
||||
val contentIntent = Intent(Utils.getApp(), ChatActivity::class.java)
|
||||
|
||||
contentIntent.putExtra("PeerId", "")
|
||||
contentIntent.putExtra("type", "peedId")
|
||||
|
||||
contentIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
val resultPendingIntent = PendingIntent.getActivity(
|
||||
Utils.getApp(),
|
||||
0,
|
||||
contentIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
// 新的通知
|
||||
val builder = NotificationCompat.Builder(Utils.getApp(), "Halo_IM")
|
||||
val notification = builder.setTicker("您有新的消息")
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(resultPendingIntent)
|
||||
.setContentTitle("光环助手客服回复")
|
||||
.setContentText("您有新的消息")
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel("Halo_IM", "Halo_IM", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
notificationManager?.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
if (notification != null) {
|
||||
notificationManager?.notify(NOTIFICATION_ID, notification)
|
||||
ImManager.showFloatingWindow()
|
||||
}
|
||||
}
|
||||
} else if (intent.action == IMChatManager.FINISH_ACTION) {
|
||||
ImManager.dismissFloatingWindow()
|
||||
}
|
||||
} else if (intent.action == IMChatManager.FINISH_ACTION) {
|
||||
ImManager.dismissFloatingWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -51,8 +52,12 @@ public class CommentUtils {
|
||||
public static void setCommentTime(TextView textView, long time) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
try {
|
||||
long today = format.parse(format.format(new Date())).getTime();
|
||||
long day = time * 1000;
|
||||
String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
|
||||
format.applyPattern("yyyy");
|
||||
String currentYear = format.format(day);
|
||||
format.applyPattern("yyyyMMdd");
|
||||
long today = format.parse(format.format(new Date())).getTime();
|
||||
if (day >= today && day < today + 86400 * 1000) {
|
||||
long min = new Date().getTime() / 1000 - day / 1000;
|
||||
int hour = (int) (min / (60 * 60));
|
||||
@ -68,6 +73,13 @@ public class CommentUtils {
|
||||
} else if (day >= today - 86400 * 1000 && day < today) {
|
||||
format.applyPattern("HH:mm");
|
||||
textView.setText("昨天 ");
|
||||
} else if (day >= today - 86400 * 1000 * 7 && day < today - 86400 * 1000) {
|
||||
format.applyPattern("HH:mm");
|
||||
long days = (today - day) / 86400000 + 1;
|
||||
textView.setText(String.format(Locale.getDefault(), "%d天前 ", days));
|
||||
} else if (day < today - 86400 * 1000 * 7 && year.equals(currentYear)) {
|
||||
format.applyPattern("MM-dd");
|
||||
textView.setText(format.format(day));
|
||||
} else {
|
||||
format.applyPattern("yyyy-MM-dd");
|
||||
textView.setText(format.format(day));
|
||||
@ -199,7 +211,7 @@ public class CommentUtils {
|
||||
final TextView commentLikeCountTv, final ImageView commentLikeIv,
|
||||
final OnVoteListener listener) {
|
||||
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
|
||||
Utils.toast(context, "已经点过赞啦!");
|
||||
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
|
||||
return;
|
||||
}
|
||||
commentEntity.setVote(commentEntity.getVote() + 1);
|
||||
@ -236,7 +248,7 @@ public class CommentUtils {
|
||||
try {
|
||||
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
|
||||
if ("voted".equals(detail)) {
|
||||
Utils.toast(context, "已经点过赞啦!");
|
||||
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
@ -265,7 +277,7 @@ public class CommentUtils {
|
||||
}
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme_font)) {
|
||||
Utils.toast(context, "已经点过赞啦!");
|
||||
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
|
||||
return;
|
||||
}
|
||||
commentEntity.setVote(commentEntity.getVote() + 1);
|
||||
@ -301,7 +313,7 @@ public class CommentUtils {
|
||||
try {
|
||||
String detail = new JSONObject(exception.response().errorBody().string()).getString("detail");
|
||||
if ("voted".equals(detail)) {
|
||||
Utils.toast(context, "已经点过赞啦!");
|
||||
ToastUtils.INSTANCE.showToast("已经点过赞啦!");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
@ -421,7 +433,7 @@ public class CommentUtils {
|
||||
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cmb.setText(copyContent);
|
||||
|
||||
Utils.toast(context, "复制成功");
|
||||
ToastUtils.INSTANCE.showToast("复制成功");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.common.util;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.gh.common.constant.Constants;
|
||||
import com.gh.gamecenter.entity.GameEntity;
|
||||
import com.gh.gamecenter.entity.NewsDetailEntity;
|
||||
import com.gh.gamecenter.manager.DataCollectionManager;
|
||||
@ -12,6 +13,8 @@ import com.lightgame.download.DownloadEntity;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import kotlin.text.StringsKt;
|
||||
|
||||
/**
|
||||
* Created by LGT on 2016/12/9.
|
||||
* 数据收集 工具类(data.ghzs666.com)
|
||||
@ -31,8 +34,8 @@ public class DataCollectionUtils {
|
||||
// 上传下载数据(开始、完成)
|
||||
public static void uploadDownload(Context context, DownloadEntity downloadEntity, String status) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("game", downloadEntity.getName());
|
||||
map.put("game_id", downloadEntity.getGameId());
|
||||
map.put("game", StringsKt.removeSuffix(downloadEntity.getName(), Constants.GAME_NAME_DECORATOR));
|
||||
map.put("game_id", downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER));
|
||||
if (downloadEntity.isPluggable()) {
|
||||
map.put("method", "插件化");
|
||||
map.put("btn_status", "插件化");
|
||||
|
||||
@ -215,6 +215,8 @@ object DirectUtils {
|
||||
|
||||
"anliwall" -> directToAmway(context, fixedTopAmwayCommentId = null, entrance = entrance, path = path)
|
||||
|
||||
//"h5_game_center" -> directLetoGameCenter(context)
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
@ -245,6 +247,7 @@ object DirectUtils {
|
||||
/**
|
||||
* 跳转至专题合集
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String, columnName: String = "") {
|
||||
context.startActivity(ColumnCollectionDetailActivity.getIntent(context, id, position, entrance, columnName))
|
||||
}
|
||||
@ -647,4 +650,70 @@ object DirectUtils {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转梦工厂小游戏
|
||||
*/
|
||||
/*@JvmStatic
|
||||
fun directLetoGameCenter(context: Context) {
|
||||
if (UserManager.getInstance().isLoggedIn) {
|
||||
UserManager.getInstance().userInfoEntity?.run {
|
||||
MgcAccountManager.syncAccount(context, if (idCard != null) idCard!!.name else name, mobile, name, icon, true,
|
||||
object : SyncUserInfoListener {
|
||||
override fun onSuccess(data: LoginResultBean?) {}
|
||||
|
||||
override fun onFail(code: String?, message: String?) {}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
MgcAccountManager.exitAccount(context, object : SyncUserInfoListener {
|
||||
override fun onSuccess(data: LoginResultBean?) {}
|
||||
|
||||
override fun onFail(code: String?, message: String?) {}
|
||||
})
|
||||
}
|
||||
Leto.getInstance().startGameCenter(context)
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 跳转分类
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directCategoryDirectory(context: Context, categoryId: String, categoryTitle: String, entrance: String? = null, path: String? = "") {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
|
||||
bundle.putString(KEY_CATEGORY_ID, categoryId)
|
||||
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到问题标签详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directAskColumnLabelDetail(context: Context, tag: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_ASK_TAG, tag)
|
||||
bundle.putParcelable(KEY_COMMUNITY_DATA, community)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到专栏详情
|
||||
*/
|
||||
@JvmStatic
|
||||
fun directAskColumnDetail(context: Context, columnId: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_COLUMN_ID, columnId)
|
||||
bundle.putParcelable(KEY_COMMUNITY_DATA, community)
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_PATH, path)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
}
|
||||
@ -206,6 +206,13 @@ public class DisplayUtils {
|
||||
public static void setStatusBarColor(Activity activity, int color, boolean lightStatusBar) {
|
||||
Window window = activity.getWindow();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (!isMiuiOs()) {
|
||||
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
}
|
||||
|
||||
window.setStatusBarColor(ContextCompat.getColor(activity, color));
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
@ -250,6 +257,20 @@ public class DisplayUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getScreenWidth() {
|
||||
WindowManager manager = (WindowManager) HaloApp.getInstance().getApplication().getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
manager.getDefaultDisplay().getMetrics(metrics);
|
||||
return metrics.widthPixels;
|
||||
}
|
||||
|
||||
public static int getScreenHeight() {
|
||||
WindowManager manager = (WindowManager) HaloApp.getInstance().getApplication().getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
manager.getDefaultDisplay().getMetrics(metrics);
|
||||
return metrics.heightPixels;
|
||||
}
|
||||
|
||||
public static boolean hasSoftKeys(Context context) {
|
||||
if (!(context instanceof Activity)) return false;
|
||||
|
||||
|
||||
@ -8,18 +8,12 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.common.constant.Config;
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.DeviceRemindDialog;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
import com.gh.download.DownloadManager;
|
||||
import com.gh.download.dialog.DownloadDialog;
|
||||
@ -40,6 +34,12 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* todo 下载判断不能以按钮文案为判断条件,否则按钮文案修改时又要修改判断逻辑
|
||||
*/
|
||||
@ -426,7 +426,15 @@ public class DownloadItemUtils {
|
||||
if (gameEntity.getApk().size() == 0 && gameEntity.getH5Link() != null) {
|
||||
downloadBtn.setOnClickListener(v -> {
|
||||
MtaHelper.onEvent("H5页面", "入口", "列表页_" + gameEntity.getName());
|
||||
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), "play".equals(gameEntity.getH5Link().getType()));
|
||||
|
||||
LinkEntity linkEntity = gameEntity.getH5Link();
|
||||
|
||||
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
|
||||
if (isPlay) {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
}
|
||||
|
||||
Intent i = WebActivity.getIntentForWebGame(context, gameEntity.getH5Link().getLink(), gameEntity.getName(), isPlay);
|
||||
context.startActivity(i);
|
||||
});
|
||||
} else if (gameEntity.getApk().size() == 1) {
|
||||
@ -456,6 +464,7 @@ public class DownloadItemUtils {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
v.getContext(),
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location);
|
||||
});
|
||||
@ -513,7 +522,7 @@ public class DownloadItemUtils {
|
||||
MtaHelper.onEvent("我的游戏_启动", "插件化", gameEntity.getName());
|
||||
}
|
||||
if (gameEntity.getPluggableCollection() != null) {
|
||||
DownloadDialog.showDownloadDialog(context, gameEntity, entrance, location);
|
||||
DownloadDialog.showDownloadDialog(context, gameEntity, traceEvent, entrance, location);
|
||||
} else {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, () -> {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, () -> {
|
||||
@ -557,9 +566,7 @@ public class DownloadItemUtils {
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "下载");
|
||||
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.DOWNLOAD);
|
||||
|
||||
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, isSubscribe, downloadExposureEvent);
|
||||
DownloadManager.createDownload(context, gameEntity, context.getString(R.string.download), entrance, location, isSubscribe, traceEvent);
|
||||
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
|
||||
|
||||
downloadBtn.setText(R.string.downloading);
|
||||
@ -578,9 +585,7 @@ public class DownloadItemUtils {
|
||||
if (TextUtils.isEmpty(msg)) {
|
||||
DataUtils.onGameDownloadEvent(context, gameEntity.getName(), gameEntity.getApk().get(0).getPlatform(), entrance, "下载开始", "插件化");
|
||||
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getApk().get(0).getPlatform(), traceEvent, ExposureUtils.DownloadType.PLUGIN_DOWNLOAD);
|
||||
|
||||
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, downloadExposureEvent);
|
||||
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent);
|
||||
Utils.toast(context, gameEntity.getName() + "已加入下载队列");
|
||||
|
||||
downloadBtn.setText(R.string.downloading);
|
||||
@ -617,12 +622,8 @@ public class DownloadItemUtils {
|
||||
private static void update(Context context, GameEntity gameEntity, String entrance, String location, boolean isSubscribe, @Nullable ExposureEvent traceEvent) {
|
||||
ApkEntity apkEntity = gameEntity.getApk().get(0);
|
||||
|
||||
ExposureUtils.DownloadType downloadType = ExposureUtils.getUpdateType(apkEntity);
|
||||
DataUtils.onGameUpdateEvent(context, gameEntity.getName(), apkEntity.getPlatform(), "下载开始");
|
||||
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity
|
||||
.getPlatform(), traceEvent, downloadType);
|
||||
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, downloadExposureEvent);
|
||||
DownloadManager.createDownload(context, gameEntity, "更新", entrance, location, isSubscribe, traceEvent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -38,11 +38,13 @@ object DownloadObserver {
|
||||
|
||||
private val mApplication = HaloApp.getInstance().application
|
||||
|
||||
// 如果在WIFI状态下,下载自动暂停,则再重试一遍
|
||||
@JvmStatic
|
||||
fun initObserver() {
|
||||
val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
val gameId = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER)
|
||||
val downloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
|
||||
|
||||
if (downloadEntity.status != DownloadStatus.downloading) {
|
||||
LogUtils.uploadDownloadEvent(downloadEntity)
|
||||
@ -61,7 +63,7 @@ object DownloadObserver {
|
||||
// 404 Not Found
|
||||
// 删除任务
|
||||
downloadEntity.status = DownloadStatus.cancel
|
||||
DownloadManager.getInstance(mApplication).cancel(downloadEntity.url)
|
||||
downloadManager.cancel(downloadEntity.url)
|
||||
Utils.toast(mApplication, "该链接已失效!请联系管理员。")
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载失败弹窗",
|
||||
@ -76,13 +78,25 @@ object DownloadObserver {
|
||||
}, null)
|
||||
return
|
||||
} else if (DownloadStatus.neterror == downloadEntity.status || DownloadStatus.timeout == downloadEntity.status) {
|
||||
if (downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD].isNullOrEmpty()
|
||||
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
|
||||
downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD] = downloadEntity.progress.toString()
|
||||
downloadManager.updateDownloadEntity(downloadEntity)
|
||||
downloadManager.startDownload(downloadEntity.url)
|
||||
debugOnly {
|
||||
Utils.log("DownloadObserver", "下载重试->" + downloadEntity.toJson())
|
||||
}
|
||||
} else {
|
||||
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
|
||||
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
|
||||
|
||||
Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
|
||||
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
|
||||
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
|
||||
"游戏", downloadEntity.name,
|
||||
"平台", downloadEntity.platform)
|
||||
MtaHelper.onEventWithBasicDeviceInfo("下载自动暂停",
|
||||
"游戏", downloadEntity.name,
|
||||
"平台", downloadEntity.platform)
|
||||
debugOnly {
|
||||
Utils.log("DownloadObserver", "下载自动暂停->" + downloadEntity.toJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DownloadStatus.done == downloadEntity.status) {
|
||||
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
|
||||
@ -112,7 +126,7 @@ object DownloadObserver {
|
||||
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)
|
||||
downloadManager.cancel(downloadEntity.url)
|
||||
} else {
|
||||
if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
@ -148,6 +162,13 @@ object DownloadObserver {
|
||||
}
|
||||
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
|
||||
// 如果已下载大小发生变化,表示成功恢复下载,则重置重试标记
|
||||
if (downloadEntity.status == DownloadStatus.downloading &&
|
||||
downloadEntity.progress.toString() != downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD]) {
|
||||
downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD] = ""
|
||||
downloadManager.updateDownloadEntity(downloadEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,7 +224,7 @@ object DownloadObserver {
|
||||
}
|
||||
|
||||
ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
GameEntity(downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), downloadEntity.name),
|
||||
GameEntity(id = downloadEntity.getRealGameId(Constants.GAME_ID_DIVIDER), mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR)),
|
||||
downloadEntity.platform,
|
||||
downloadEntity.exposureTrace,
|
||||
type)
|
||||
|
||||
@ -4,6 +4,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.gh.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.common.avoidcallback.Callback;
|
||||
import com.gh.gamecenter.MainActivity;
|
||||
@ -11,8 +13,6 @@ 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
|
||||
@ -37,6 +37,10 @@ public class EntranceUtils {
|
||||
public static final String HOST_VIDEO_COLLECTION = "video_collection";//视频合集
|
||||
public static final String HOST_USERHOME = "userhome";//个人主页
|
||||
public static final String HOST_VIDEO = "video";
|
||||
public static final String HOST_CATEGORY = "category";//分类
|
||||
public static final String HOST_COLUMN_COLLECTION = "column_collection";//专题合集
|
||||
public static final String HOST_COMMUNITY_QUESTION_LABEL_DETAIL = "community_question_label_detail";//问题标签详情
|
||||
public static final String HOST_COMMUNITY_COLUMN_DETAIL = "community_column_detail";//专栏详情
|
||||
public static final String HOST_COMMUNITY_ARTICLE = "community_article";
|
||||
public static final String HOST_COMMUNITY_COLUMN = "community_column";
|
||||
public static final String HOST_GAME = "game";
|
||||
@ -154,6 +158,9 @@ public class EntranceUtils {
|
||||
public static final String KEY_COLUMNNAME = "columnName";
|
||||
public static final String KEY_QA_ID = "qaId";
|
||||
public static final String KEY_QA_COLLECTION_ID = "qaCollectionId";
|
||||
public static final String KEY_SHOW_EDIT_DRAFT = "showEditDraft";
|
||||
public static final String KEY_ARTICLE_OPEN_IN_NEW_PAGE = "openArticleInNewPage";
|
||||
public static final String KEY_ONLY_CREATE_DRAFT = "onlyCreateDraft";
|
||||
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
@ -289,7 +289,7 @@ fun String.copyTextAndToast(toastText: String = "复制成功") {
|
||||
val application = HaloApp.getInstance().application
|
||||
val cmb = application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
cmb.text = this
|
||||
Utils.toast(application, toastText)
|
||||
ToastUtils.showToast(toastText)
|
||||
}
|
||||
|
||||
fun Map<String, String>.createRequestBody(): RequestBody {
|
||||
@ -461,6 +461,22 @@ fun SimpleDraweeView.display(url: String) {
|
||||
ImageUtils.display(this, url)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process related
|
||||
*/
|
||||
fun Context.doOnMainProcessOnly(callback: EmptyCallback) {
|
||||
doOnMainProcessOnly { callback.onCallback() }
|
||||
}
|
||||
|
||||
inline fun Context.doOnMainProcessOnly(f: () -> Unit) {
|
||||
val processName = PackageUtils.obtainProcessName(this)
|
||||
if (processName == null || BuildConfig.APPLICATION_ID == processName) {
|
||||
f.invoke()
|
||||
} else {
|
||||
Utils.log("Block one useless sub process method call.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用包裹
|
||||
*/
|
||||
@ -480,15 +496,15 @@ inline fun testChannelOnly(f: () -> Unit) {
|
||||
* 倒计时,单位s
|
||||
*/
|
||||
inline fun countDownTimer(
|
||||
millisUntilFinish: Long,
|
||||
crossinline block: (finish: Boolean, millisUntilFinished: Long) -> Unit
|
||||
timeInSeconds: Long,
|
||||
crossinline block: (finish: Boolean, remainingTime: Long) -> Unit
|
||||
): Disposable {
|
||||
var subscribe: Disposable? = null
|
||||
subscribe = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it < millisUntilFinish) {
|
||||
block.invoke(false, millisUntilFinish - it)
|
||||
if (it < timeInSeconds) {
|
||||
block.invoke(false, timeInSeconds - it)
|
||||
} else {
|
||||
block.invoke(true, 0)
|
||||
if (subscribe != null && !subscribe!!.isDisposed) {
|
||||
|
||||
@ -110,7 +110,7 @@ public class GameUtils {
|
||||
gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
|
||||
if (gameEntity.getTag() != null && gameEntity.getTag().size() != 0
|
||||
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
|
||||
&& !PackageUtils.isSignature(context, apkEntity.getPackageName())
|
||||
&& !PackageUtils.isSignedByGh(context, apkEntity.getPackageName())
|
||||
&& apkEntity.isShowPlugin(pluginLocation)) {
|
||||
pluginCount++;
|
||||
} else if (gh_id == null || gh_id.equals(gameEntity.getId())) {
|
||||
|
||||
@ -36,9 +36,10 @@ public class GameViewUtils {
|
||||
public static void setLabelList(Context context, LinearLayout labelLayout, List<TagStyleEntity> tagStyle) {
|
||||
labelLayout.removeAllViews();
|
||||
if (tagStyle == null || tagStyle.isEmpty()) {
|
||||
TagStyleEntity tagEntity = new TagStyleEntity();
|
||||
tagEntity.setName("官方版");
|
||||
labelLayout.addView(getNewGameTagView(context, tagEntity, 0));
|
||||
// 没有数据的话默认不显示
|
||||
// TagStyleEntity tagEntity = new TagStyleEntity();
|
||||
// tagEntity.setName("官方版");
|
||||
// labelLayout.addView(getNewGameTagView(context, tagEntity, 0));
|
||||
} else {
|
||||
for (int i = 0, size = tagStyle.size(); i < size; i++) {
|
||||
View view = getNewGameTagView(context, tagStyle.get(i), i == size - 1 ? 0 : DisplayUtils.dip2px(context, 8));
|
||||
|
||||
@ -67,7 +67,7 @@ public class InstallUtils {
|
||||
String installVersion = PackageUtils.getVersionByPackage(packageName);
|
||||
if (!TextUtils.isEmpty(installVersion) && downloadEntity != null &&
|
||||
installVersion.equals(downloadEntity.getVersionName())) {
|
||||
if (!downloadEntity.isPluggable() || PackageUtils.isSignature(context, packageName)) {
|
||||
if (!downloadEntity.isPluggable() || PackageUtils.isSignedByGh(context, packageName)) {
|
||||
EventBus.getDefault().post(new EBPackage("安装", packageName, installVersion));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
@ -75,4 +82,61 @@ public class MD5Utils {
|
||||
return bigInt.toString(16);
|
||||
}
|
||||
|
||||
|
||||
public static boolean checkMD5(String md5, File updateFile) {
|
||||
if (TextUtils.isEmpty(md5) || updateFile == null) {
|
||||
Utils.log("MD5 string empty or updateFile null");
|
||||
return false;
|
||||
}
|
||||
|
||||
String calculatedDigest = calculateMD5(updateFile);
|
||||
if (calculatedDigest == null) {
|
||||
Utils.log("calculatedDigest null");
|
||||
return false;
|
||||
}
|
||||
|
||||
Utils.log("Calculated digest: " + calculatedDigest);
|
||||
Utils.log("Provided digest: " + md5);
|
||||
return calculatedDigest.equalsIgnoreCase(md5);
|
||||
}
|
||||
|
||||
public static String calculateMD5(File updateFile) {
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
} catch (Exception e) {
|
||||
Utils.log("Exception while getting digest", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream is;
|
||||
try {
|
||||
is = new FileInputStream(updateFile);
|
||||
} catch (Exception e) {
|
||||
Utils.log("Exception while getting FileInputStream", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
try {
|
||||
while ((read = is.read(buffer)) > 0) {
|
||||
digest.update(buffer, 0, read);
|
||||
}
|
||||
byte[] md5sum = digest.digest();
|
||||
BigInteger bigInt = new BigInteger(1, md5sum);
|
||||
String output = bigInt.toString(16);
|
||||
// Fill to 32 chars
|
||||
output = String.format("%32s", output).replace(' ', '0');
|
||||
return output;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to process file for MD5", e);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception e) {
|
||||
Utils.log("Exception on closing MD5 input stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +146,8 @@ public class NetworkUtils {
|
||||
return "3G";
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
return "4G";
|
||||
case 20://暂未适配AndroidQ,这里粗暴设置为20
|
||||
return "5G";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -117,64 +118,23 @@ public class NewsUtils {
|
||||
* 设置新闻发布时间
|
||||
*/
|
||||
public static void setNewsPublishOn(TextView textView, long time) {
|
||||
time = time * 1000;
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
try {
|
||||
long today = format.parse(format.format(new Date())).getTime();
|
||||
if (time >= today && time < today + 86400 * 1000) {
|
||||
format.applyPattern("HH:mm");
|
||||
textView.setText(format.format(time));
|
||||
} else if (time >= today - 86400 * 1000 && time < today) {
|
||||
format.applyPattern("HH:mm");
|
||||
textView.setText(String.format("昨天 %s", format.format(time)));
|
||||
} else {
|
||||
format.applyPattern("yyyy年MM月dd日 HH:mm");
|
||||
textView.setText(format.format(time));
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
format.applyPattern("yyyy年MM月dd日 HH:mm");
|
||||
textView.setText(format.format(time));
|
||||
}
|
||||
CommentUtils.setCommentTime(textView, time);
|
||||
}
|
||||
|
||||
|
||||
public static void setNewsDetailTime(TextView textView, long time) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
try {
|
||||
long today = format.parse(format.format(new Date())).getTime();
|
||||
long day = time * 1000;
|
||||
if (day >= today && day < today + 86400 * 1000) {
|
||||
long min = new Date().getTime() / 1000 - day / 1000;
|
||||
int hour = (int) (min / (60 * 60));
|
||||
if (hour == 0) {
|
||||
if (min < 60) {
|
||||
textView.setText("刚刚");
|
||||
} else {
|
||||
textView.setText(String.format(Locale.getDefault(), "%d分钟前", (int) (min / 60)));
|
||||
}
|
||||
} else {
|
||||
textView.setText(String.format(Locale.getDefault(), "%d小时前", hour));
|
||||
}
|
||||
} else if (day >= today - 86400 * 1000 * 100 && day < today) {
|
||||
format.applyPattern("HH:mm");
|
||||
textView.setText("昨天 ");
|
||||
} else {
|
||||
format.applyPattern("yyyy-MM-dd");
|
||||
textView.setText(format.format(day));
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
format.applyPattern("yyyy-MM-dd");
|
||||
textView.setText(format.format(time * 1000));
|
||||
}
|
||||
CommentUtils.setCommentTime(textView, time);
|
||||
}
|
||||
|
||||
public static String getFormattedTime(long time) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
try {
|
||||
long today = format.parse(format.format(new Date())).getTime();
|
||||
long day = time * 1000;
|
||||
String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
|
||||
format.applyPattern("yyyy");
|
||||
String currentYear = format.format(day);
|
||||
format.applyPattern("yyyyMMdd");
|
||||
long today = format.parse(format.format(new Date())).getTime();
|
||||
if (day >= today && day < today + 86400 * 1000) {
|
||||
long min = new Date().getTime() / 1000 - day / 1000;
|
||||
int hour = (int) (min / (60 * 60));
|
||||
@ -190,6 +150,13 @@ public class NewsUtils {
|
||||
} else if (day >= today - 86400 * 1000 && day < today) {
|
||||
format.applyPattern("HH:mm");
|
||||
return ("昨天 ");
|
||||
} else if (day >= today - 86400 * 1000 * 7 && day < today - 86400 * 1000) {
|
||||
format.applyPattern("HH:mm");
|
||||
long days = (today - day) / 86400000 + 1;
|
||||
return String.format(Locale.getDefault(), "%d天前 ", days);
|
||||
} else if (day < today - 86400 * 1000 * 7 && year.equals(currentYear)) {
|
||||
format.applyPattern("MM-dd");
|
||||
return (format.format(day));
|
||||
} else {
|
||||
format.applyPattern("yyyy-MM-dd");
|
||||
return (format.format(day));
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -51,7 +52,7 @@ public class PackageUtils {
|
||||
/*
|
||||
* 判断是否可以更新,只判断gh_version的大小
|
||||
*/
|
||||
public static List<GameUpdateEntity> getUpdateData(Context context, GameEntity gameEntity) {
|
||||
public static List<GameUpdateEntity> getUpdateData(GameEntity gameEntity) {
|
||||
|
||||
List<GameUpdateEntity> updateList = new ArrayList<>();
|
||||
|
||||
@ -88,14 +89,14 @@ public class PackageUtils {
|
||||
String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName());
|
||||
|
||||
// 是否需要显示更新
|
||||
boolean shouldShouldUpdate = apkEntity.getForce();
|
||||
boolean shouldShowUpdate = apkEntity.getForce();
|
||||
|
||||
if (shouldShouldUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
|
||||
if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
|
||||
|
||||
// 根据版本判断是否需要更新
|
||||
shouldShouldUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
|
||||
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
|
||||
|
||||
if (shouldShouldUpdate) {
|
||||
if (shouldShowUpdate) {
|
||||
GameUpdateEntity updateEntity = new GameUpdateEntity();
|
||||
updateEntity.setId(gameEntity.getId());
|
||||
updateEntity.setName(gameEntity.getName());
|
||||
@ -153,7 +154,7 @@ public class PackageUtils {
|
||||
/*
|
||||
* 判断是否是插件包
|
||||
*/
|
||||
public static boolean isSignature(Context context, String packageName) {
|
||||
public static boolean isSignedByGh(Context context, String packageName) {
|
||||
String signature = getApkSignatureByPackageName(context, packageName);
|
||||
return publicKey.equals(signature);
|
||||
}
|
||||
@ -349,6 +350,8 @@ public class PackageUtils {
|
||||
|
||||
/*
|
||||
* 根据包名,判断是否已安装该游戏
|
||||
*
|
||||
* 注意:目测只对能启动的app有效(有桌面图标),对一些没有桌面图标的应用无效(参考应用:魅族游戏框架)
|
||||
*/
|
||||
public static boolean isInstalled(Context context, String packageName) {
|
||||
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
|
||||
@ -502,7 +505,7 @@ public class PackageUtils {
|
||||
/**
|
||||
* todo 统一判断
|
||||
* <p>
|
||||
* 判断游戏包是否可以更新
|
||||
* 判断游戏包(插件包) 是否可以更新
|
||||
*
|
||||
* @param apkEntity apkEntity 必须是已安装的游戏
|
||||
* @param gameId 游戏id
|
||||
@ -547,6 +550,26 @@ public class PackageUtils {
|
||||
return PackageUtils.isInstalled(HaloApp.getInstance().getApplication(), apkEntity.getPackageName())
|
||||
&& gh_id == null
|
||||
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
|
||||
&& !PackageUtils.isSignature(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
|
||||
&& !PackageUtils.isSignedByGh(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调用者的进程名
|
||||
* @param context 调用者的上下文
|
||||
* @return 进程名
|
||||
*/
|
||||
public static String obtainProcessName(Context context) {
|
||||
final int pid = android.os.Process.myPid();
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
|
||||
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
|
||||
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
|
||||
if (info != null && info.pid == pid) {
|
||||
return info.processName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,6 +20,8 @@ import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.net.URLEncoder
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import java.lang.Exception
|
||||
|
||||
|
||||
object UploadImageUtils {
|
||||
@ -109,6 +111,7 @@ object UploadImageUtils {
|
||||
fun compressAndUploadImageList(type: UploadType, imgs: List<String>, compressGif: Boolean, listener: OnUploadImageListListener): Disposable? {
|
||||
var subscription: Disposable? = null
|
||||
val postImageList = LinkedHashMap<String, String>()
|
||||
val errorMap = HashMap<String, Exception>()
|
||||
|
||||
Observable.create(ObservableOnSubscribe<Map<String, String>> {
|
||||
val compressList = compressImageList(imgs, compressGif)
|
||||
@ -145,11 +148,13 @@ object UploadImageUtils {
|
||||
onFailure(IllegalAccessException("HeHe"))
|
||||
}
|
||||
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
// 若遇到错误且 subscription?.isDisposed 为 true 时会抛出 io.reactivex.exceptions.UndeliverableException 异常
|
||||
// if (subscription?.isDisposed == true) return
|
||||
// it.onError(exception) // fuck
|
||||
it.onNext(Collections.emptyMap())
|
||||
// it.onNext(Collections.emptyMap())
|
||||
errorMap[img.path] = exception
|
||||
}
|
||||
})
|
||||
listProgress += img.length()
|
||||
@ -165,18 +170,18 @@ object UploadImageUtils {
|
||||
|
||||
override fun onComplete() {
|
||||
if (postImageList.size == 0) {
|
||||
listener.onError()
|
||||
listener.onError(errorMap)
|
||||
} else {
|
||||
listener.onSuccess(postImageList)
|
||||
listener.onSuccess(postImageList, errorMap)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNext(t: Map<String, String>) {
|
||||
if (!t.isEmpty()) postImageList.putAll(t)
|
||||
if (t.isNotEmpty()) postImageList.putAll(t)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
e.printStackTrace()
|
||||
override fun onError(ignore: Throwable) {
|
||||
|
||||
}
|
||||
})
|
||||
return subscription
|
||||
@ -285,8 +290,8 @@ object UploadImageUtils {
|
||||
}
|
||||
|
||||
interface OnUploadImageListListener {
|
||||
fun onSuccess(imageUrl: LinkedHashMap<String, String>) // key:sourceImage value:compressImage
|
||||
fun onError() // 全部上传失败时回调
|
||||
fun onSuccess(imageUrl: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) // key:sourceImage value:compressImage
|
||||
fun onError(errorMap: Map<String, Exception>) // 全部上传失败时回调
|
||||
fun onProgress(total: Long, progress: Long)
|
||||
}
|
||||
|
||||
|
||||
@ -3,17 +3,18 @@ package com.gh.common.view
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.*
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.rxTimer
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.entity.SettingsEntity
|
||||
import com.squareup.picasso.Picasso
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlin.math.abs
|
||||
|
||||
@ -190,7 +191,7 @@ class AdBannerView : LinearLayout {
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val ad = mDatas[position % mDatas.size]
|
||||
val view = holder.itemView as SimpleDraweeView
|
||||
ImageUtils.display(view, ad.image)
|
||||
ImageUtils.display(view,ad.image)
|
||||
holder.itemView.setOnClickListener {
|
||||
onItemClick?.invoke(position % mDatas.size)
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.common.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@ -11,45 +12,59 @@ import android.text.style.ClickableSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
public class ExpandTextView extends AppCompatTextView {
|
||||
|
||||
|
||||
private CharSequence mSnapshotText;
|
||||
|
||||
|
||||
private String mEndText = "...";
|
||||
private String mExpandText = mEndText + "全文";
|
||||
private boolean mUseGradientAlphaEndText = false;
|
||||
|
||||
|
||||
private int mMaxLines = 3; // 由于sdk版本限制(getMaxLines) 这里设置默认值
|
||||
|
||||
|
||||
private static int DEFAULT_ADDITIONAL_END_TEXT_COUNT = 2;
|
||||
|
||||
|
||||
private boolean mInitLayout = false;
|
||||
private boolean mIsExpanded = false; // 位于 recyclerView 时需要自行在外层管理是否已展开
|
||||
|
||||
|
||||
private ExpandCallback mExpandCallback;
|
||||
|
||||
|
||||
private Rect mLastVisibleLineRect;
|
||||
private Rect mLastActualLineRect;
|
||||
|
||||
public ExpandTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
public ExpandTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
mMaxLines = getMaxLines();
|
||||
}
|
||||
|
||||
mLastVisibleLineRect = new Rect();
|
||||
mLastActualLineRect = new Rect();
|
||||
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandTextView);
|
||||
mUseGradientAlphaEndText = ta.getBoolean(R.styleable.ExpandTextView_useGradientAlphaEndText, false);
|
||||
mEndText = ta.getString(R.styleable.ExpandTextView_endText) == null ? mEndText : ta.getString(R.styleable.ExpandTextView_endText);
|
||||
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta.getString(R.styleable.ExpandTextView_expandText);
|
||||
mExpandText = ta.getString(R.styleable.ExpandTextView_expandText) == null ? mExpandText : ta
|
||||
.getString(R.styleable.ExpandTextView_expandText);
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() - getExtraBottomPadding());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
@ -59,123 +74,162 @@ public class ExpandTextView extends AppCompatTextView {
|
||||
showExpandButton();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setExpendText(String text) {
|
||||
this.mExpandText = text;
|
||||
}
|
||||
|
||||
|
||||
public void setExpandCallback(ExpandCallback callback) {
|
||||
this.mExpandCallback = callback;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setText(CharSequence text, BufferType type) {
|
||||
mInitLayout = true;
|
||||
super.setText(text, type);
|
||||
}
|
||||
|
||||
|
||||
private void showExpandButton() {
|
||||
String finalEndText = "";
|
||||
|
||||
TextPaint paint = getPaint();
|
||||
|
||||
Layout layout = getLayout();
|
||||
int start = layout.getLineStart(0);
|
||||
int lastLineEnd = layout.getLineEnd(mMaxLines - 1);
|
||||
int lastLineStart = layout.getLineStart(mMaxLines - 1);
|
||||
float lastLineRight = layout.getLineRight(mMaxLines - 1);
|
||||
|
||||
|
||||
int viewWidth = getWidth() - getPaddingRight() - getPaddingLeft();
|
||||
int additionalEndTextCount = 0;
|
||||
|
||||
TextPaint paint = getPaint();
|
||||
|
||||
float expandTextWidth;
|
||||
if (mUseGradientAlphaEndText) {
|
||||
additionalEndTextCount = DEFAULT_ADDITIONAL_END_TEXT_COUNT;
|
||||
// 如果不加多个括号的话有可能算不对,惊了,明明是同样的 paint 同样的文字,长度却会略有不同
|
||||
expandTextWidth = paint.measureText(mEndText + mExpandText + " ");
|
||||
expandTextWidth = paint.measureText(mEndText + mExpandText);
|
||||
} else {
|
||||
expandTextWidth = paint.measureText(mExpandText);
|
||||
}
|
||||
|
||||
|
||||
CharSequence content = mSnapshotText.subSequence(start, lastLineEnd);
|
||||
|
||||
|
||||
if (viewWidth - lastLineRight > expandTextWidth) {
|
||||
if (mUseGradientAlphaEndText) {
|
||||
finalEndText = content.toString().substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
|
||||
finalEndText = content.toString()
|
||||
.substring(content.length() - additionalEndTextCount, content.length()) + mEndText;
|
||||
finalEndText = finalEndText.replace("\n", "");
|
||||
|
||||
|
||||
content = content.subSequence(0, content.length() - additionalEndTextCount) + finalEndText + mExpandText;
|
||||
} else {
|
||||
content = content.toString().trim() + mExpandText;
|
||||
}
|
||||
} else {
|
||||
CharSequence lastText = mSnapshotText.subSequence(lastLineStart, lastLineEnd);
|
||||
for (int i = lastText.length() - 1; i > 0; i--) {
|
||||
CharSequence sequence = lastText.subSequence(0, i);
|
||||
float w = paint.measureText(sequence.toString());
|
||||
if (viewWidth - w - DisplayUtils.dip2px(5) > expandTextWidth) {
|
||||
if (mUseGradientAlphaEndText) {
|
||||
finalEndText = lastText.subSequence(i - additionalEndTextCount, i) + mEndText;
|
||||
CharSequence lastLineText = mSnapshotText.subSequence(lastLineStart, lastLineEnd);
|
||||
CharSequence subSequence;
|
||||
float subSequenceWidth;
|
||||
for (int i = lastLineText.length() - 1; i > 0; i--) {
|
||||
if (mUseGradientAlphaEndText) {
|
||||
subSequence = lastLineText.subSequence(0, i - additionalEndTextCount);
|
||||
subSequenceWidth = paint.measureText(subSequence.toString());
|
||||
|
||||
finalEndText = lastLineText.subSequence(i - additionalEndTextCount, i) + mEndText;
|
||||
expandTextWidth = paint.measureText(finalEndText + mExpandText);
|
||||
|
||||
if (viewWidth - subSequenceWidth > expandTextWidth) {
|
||||
finalEndText = finalEndText.replace("\n", "");
|
||||
|
||||
content = mSnapshotText.subSequence(start, lastLineStart + i - additionalEndTextCount) + finalEndText + mExpandText;
|
||||
} else {
|
||||
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
subSequence = lastLineText.subSequence(0, i);
|
||||
subSequenceWidth = paint.measureText(subSequence.toString());
|
||||
|
||||
if (viewWidth - subSequenceWidth > expandTextWidth) {
|
||||
content = mSnapshotText.subSequence(start, lastLineStart + i) + mExpandText;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SpannableStringBuilder msp = new SpannableStringBuilder(mSnapshotText);
|
||||
int length = msp.length();
|
||||
int startPosition = 0;
|
||||
int startPosition;
|
||||
startPosition = content.length() - finalEndText.length() - mExpandText.length();
|
||||
startPosition = Math.max(startPosition, 0);
|
||||
|
||||
|
||||
// 避免越界
|
||||
if (startPosition >= length) return;
|
||||
|
||||
|
||||
msp.replace(startPosition, length, finalEndText + mExpandText);
|
||||
|
||||
|
||||
msp.setSpan(new ClickableSpan() {
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setColor(ContextCompat.getColor(getContext(), R.color.theme_font));
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(View widget) {
|
||||
public void onClick(@NonNull View widget) {
|
||||
mIsExpanded = true;
|
||||
setMaxLines(Integer.MAX_VALUE);
|
||||
setText(mSnapshotText);
|
||||
|
||||
|
||||
if (mExpandCallback != null) {
|
||||
mExpandCallback.onExpand();
|
||||
}
|
||||
}
|
||||
}, startPosition + mEndText.length(), msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
msp.setSpan(new GradientAlphaTextSpan(), startPosition, startPosition + finalEndText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
|
||||
setText(msp);
|
||||
setMovementMethod(CustomLinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取 maxLines + lineSpacingExtra + movementMethod 一起使用时产生的大小与 lineSpacingExtra 一样的底部空间
|
||||
*/
|
||||
private int getExtraBottomPadding() {
|
||||
int result = 0;
|
||||
// 界面上显示的最后一行的 index
|
||||
int lastVisibleLineIndex = Math.min(getMaxLines(), getLineCount()) - 1;
|
||||
// 获取实际文字的最后一行的 index
|
||||
int lastActualLineIndex = getLineCount() - 1;
|
||||
|
||||
if (lastVisibleLineIndex >= 0) {
|
||||
Layout layout = getLayout();
|
||||
int lastVisibleLineBaseline = getLineBounds(lastVisibleLineIndex, mLastVisibleLineRect);
|
||||
getLineBounds(lastActualLineIndex, mLastActualLineRect);
|
||||
int heightBetweenLastVisibleLineRectAndLastActualLineRect = (mLastActualLineRect.bottom - mLastVisibleLineRect.bottom);
|
||||
|
||||
if (getMeasuredHeight() == getLayout().getHeight() - heightBetweenLastVisibleLineRectAndLastActualLineRect) {
|
||||
result = mLastVisibleLineRect.bottom - (lastVisibleLineBaseline + layout.getPaint()
|
||||
.getFontMetricsInt().descent + getPaddingBottom());
|
||||
if (getLineSpacingExtra() > result) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = (int) getLineSpacingExtra();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 此方法仅更改标记,不做实际展开的操作
|
||||
*/
|
||||
public void setIsExpanded(boolean isExpanded) {
|
||||
mIsExpanded = isExpanded;
|
||||
}
|
||||
|
||||
|
||||
public void setExpandMaxLines(int maxLines) {
|
||||
mMaxLines = maxLines;
|
||||
setMaxLines(maxLines);
|
||||
}
|
||||
|
||||
|
||||
public interface ExpandCallback {
|
||||
void onExpand();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
790
app/src/main/java/com/gh/common/view/NestedScrollWebView2.java
Normal file
790
app/src/main/java/com/gh/common/view/NestedScrollWebView2.java
Normal file
@ -0,0 +1,790 @@
|
||||
package com.gh.common.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewParent;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.OverScroller;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import androidx.core.view.AccessibilityDelegateCompat;
|
||||
import androidx.core.view.InputDeviceCompat;
|
||||
import androidx.core.view.NestedScrollingChild2;
|
||||
import androidx.core.view.NestedScrollingChildHelper;
|
||||
import androidx.core.view.NestedScrollingParent;
|
||||
import androidx.core.view.NestedScrollingParentHelper;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityRecordCompat;
|
||||
import wendu.dsbridge.DWebView;
|
||||
|
||||
/**
|
||||
* Copyright (c) Tuenti Technologies. All rights reserved.
|
||||
* <p>
|
||||
* WebView compatible with CoordinatorLayout.
|
||||
* The implementation based on NestedScrollView of design library
|
||||
*/
|
||||
public class NestedScrollWebView2 extends DWebView implements NestedScrollingChild2, NestedScrollingParent {
|
||||
|
||||
private static final int INVALID_POINTER = -1;
|
||||
private static final String TAG = "NestedWebView";
|
||||
|
||||
private final int[] mScrollOffset = new int[2];
|
||||
private final int[] mScrollConsumed = new int[2];
|
||||
|
||||
private int mLastMotionY;
|
||||
private NestedScrollingParentHelper mParentHelper;
|
||||
private NestedScrollingChildHelper mChildHelper;
|
||||
private boolean mIsBeingDragged = false;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private int mTouchSlop;
|
||||
private int mActivePointerId = INVALID_POINTER;
|
||||
private int mNestedYOffset;
|
||||
private OverScroller mScroller;
|
||||
private int mMinimumVelocity;
|
||||
private int mMaximumVelocity;
|
||||
private static final AccessibilityDelegate ACCESSIBILITY_DELEGATE = new AccessibilityDelegate();
|
||||
|
||||
public NestedScrollWebView2(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public NestedScrollWebView2(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
private void init(){
|
||||
setOverScrollMode(WebView.OVER_SCROLL_NEVER);
|
||||
initScrollView();
|
||||
mChildHelper = new NestedScrollingChildHelper(this);
|
||||
mParentHelper = new NestedScrollingParentHelper(this);
|
||||
setNestedScrollingEnabled(true);
|
||||
ViewCompat.setAccessibilityDelegate(this, ACCESSIBILITY_DELEGATE);
|
||||
}
|
||||
|
||||
|
||||
private void initScrollView() {
|
||||
mScroller = new OverScroller(getContext());
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
|
||||
mTouchSlop = configuration.getScaledTouchSlop();
|
||||
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
|
||||
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
if (disallowIntercept) {
|
||||
recycleVelocityTracker();
|
||||
}
|
||||
super.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
|
||||
final int action = ev.getAction();
|
||||
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final int activePointerId = mActivePointerId;
|
||||
if (activePointerId == INVALID_POINTER) {
|
||||
break;
|
||||
}
|
||||
|
||||
final int pointerIndex = ev.findPointerIndex(activePointerId);
|
||||
if (pointerIndex == -1) {
|
||||
Log.e(TAG, "Invalid pointerId=" + activePointerId
|
||||
+ " in onInterceptTouchEvent");
|
||||
break;
|
||||
}
|
||||
|
||||
final int y = (int) ev.getY(pointerIndex);
|
||||
final int yDiff = Math.abs(y - mLastMotionY);
|
||||
if (yDiff > mTouchSlop
|
||||
&& (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0) {
|
||||
mIsBeingDragged = true;
|
||||
mLastMotionY = y;
|
||||
initVelocityTrackerIfNotExists();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
mNestedYOffset = 0;
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
final int y = (int) ev.getY();
|
||||
|
||||
mLastMotionY = y;
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
|
||||
initOrResetVelocityTracker();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
|
||||
mScroller.computeScrollOffset();
|
||||
mIsBeingDragged = !mScroller.isFinished();
|
||||
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
mIsBeingDragged = false;
|
||||
mActivePointerId = INVALID_POINTER;
|
||||
recycleVelocityTracker();
|
||||
if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0, getScrollRange())) {
|
||||
ViewCompat.postInvalidateOnAnimation(this);
|
||||
}
|
||||
stopNestedScroll();
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
onSecondaryPointerUp(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
return mIsBeingDragged;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
boolean returnValue = false;
|
||||
initVelocityTrackerIfNotExists();
|
||||
|
||||
MotionEvent vtev = MotionEvent.obtain(ev);
|
||||
|
||||
final int actionMasked = ev.getActionMasked();
|
||||
|
||||
if (actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
mNestedYOffset = 0;
|
||||
}
|
||||
vtev.offsetLocation(0, mNestedYOffset);
|
||||
|
||||
switch (actionMasked) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
returnValue = super.onTouchEvent(ev);
|
||||
if (mIsBeingDragged = !mScroller.isFinished()) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mScroller.isFinished()) {
|
||||
mScroller.abortAnimation();
|
||||
}
|
||||
mLastMotionY = (int) ev.getY();
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
if (activePointerIndex == -1) {
|
||||
Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
|
||||
break;
|
||||
}
|
||||
|
||||
final int y = (int) ev.getY(activePointerIndex);
|
||||
int deltaY = mLastMotionY - y;
|
||||
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset,
|
||||
ViewCompat.TYPE_TOUCH)) {
|
||||
deltaY -= mScrollConsumed[1];
|
||||
ev.offsetLocation(0, -mScrollOffset[1]);
|
||||
vtev.offsetLocation(0, -mScrollOffset[1]);
|
||||
mNestedYOffset += mScrollOffset[1];
|
||||
}
|
||||
|
||||
boolean notMove = mScrollOffset[1] == 0;
|
||||
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
mIsBeingDragged = true;
|
||||
if (deltaY > 0) {
|
||||
deltaY -= mTouchSlop;
|
||||
} else {
|
||||
deltaY += mTouchSlop;
|
||||
}
|
||||
}
|
||||
if (mIsBeingDragged) {
|
||||
mLastMotionY = y - mScrollOffset[1];
|
||||
final int oldY = getScrollY();
|
||||
final int range = getScrollRange();
|
||||
int unconsumedY = 0;
|
||||
int scrolledDeltaY = deltaY;
|
||||
int expectScroll = oldY + deltaY;
|
||||
if (expectScroll < 0) {
|
||||
unconsumedY = expectScroll;
|
||||
scrolledDeltaY = oldY;
|
||||
} else if (expectScroll > range) {
|
||||
unconsumedY = range - expectScroll;
|
||||
scrolledDeltaY = expectScroll - range;
|
||||
}
|
||||
if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset,
|
||||
ViewCompat.TYPE_TOUCH)) {
|
||||
vtev.offsetLocation(0, mScrollOffset[1]);
|
||||
mNestedYOffset += mScrollOffset[1];
|
||||
mLastMotionY -= mScrollOffset[1];
|
||||
}
|
||||
}
|
||||
notMove &= (mScrollOffset[1] == 0);
|
||||
if (notMove) {
|
||||
returnValue = super.onTouchEvent(ev);
|
||||
} else {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (Math.abs(mNestedYOffset) < mTouchSlop) {
|
||||
returnValue = super.onTouchEvent(ev);
|
||||
} else {
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
returnValue = super.onTouchEvent(ev);
|
||||
}
|
||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
|
||||
if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
|
||||
flingWithNestedDispatch(-initialVelocity);
|
||||
} else if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
|
||||
getScrollRange())) {
|
||||
ViewCompat.postInvalidateOnAnimation(this);
|
||||
}
|
||||
mActivePointerId = INVALID_POINTER;
|
||||
endDrag();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
returnValue = true;
|
||||
if (mIsBeingDragged && getChildCount() > 0) {
|
||||
if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
|
||||
getScrollRange())) {
|
||||
ViewCompat.postInvalidateOnAnimation(this);
|
||||
}
|
||||
}
|
||||
mActivePointerId = INVALID_POINTER;
|
||||
endDrag();
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN: {
|
||||
final int index = ev.getActionIndex();
|
||||
mLastMotionY = (int) ev.getY(index);
|
||||
mActivePointerId = ev.getPointerId(index);
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
onSecondaryPointerUp(ev);
|
||||
mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
|
||||
break;
|
||||
}
|
||||
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.addMovement(vtev);
|
||||
}
|
||||
vtev.recycle();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
int getScrollRange() {
|
||||
//Using scroll range of webview instead of childs as NestedScrollView does.
|
||||
return computeVerticalScrollRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onOverScrolled(int scrollX, int scrollY,
|
||||
boolean clampedX, boolean clampedY) {
|
||||
super.scrollTo(scrollX, scrollY);
|
||||
}
|
||||
|
||||
boolean overScrollByCompat(int deltaX, int deltaY,
|
||||
int scrollX, int scrollY,
|
||||
int scrollRangeX, int scrollRangeY,
|
||||
int maxOverScrollX, int maxOverScrollY,
|
||||
boolean isTouchEvent) {
|
||||
final int overScrollMode = getOverScrollMode();
|
||||
final boolean canScrollHorizontal =
|
||||
computeHorizontalScrollRange() > computeHorizontalScrollExtent();
|
||||
final boolean canScrollVertical =
|
||||
computeVerticalScrollRange() > computeVerticalScrollExtent();
|
||||
final boolean overScrollHorizontal = overScrollMode == View.OVER_SCROLL_ALWAYS
|
||||
|| (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
|
||||
final boolean overScrollVertical = overScrollMode == View.OVER_SCROLL_ALWAYS
|
||||
|| (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
|
||||
|
||||
int newScrollX = scrollX + deltaX;
|
||||
if (!overScrollHorizontal) {
|
||||
maxOverScrollX = 0;
|
||||
}
|
||||
|
||||
int newScrollY = scrollY + deltaY;
|
||||
if (!overScrollVertical) {
|
||||
maxOverScrollY = 0;
|
||||
}
|
||||
|
||||
// Clamp values if at the limits and record
|
||||
final int left = -maxOverScrollX;
|
||||
final int right = maxOverScrollX + scrollRangeX;
|
||||
final int top = -maxOverScrollY;
|
||||
final int bottom = maxOverScrollY + scrollRangeY;
|
||||
|
||||
boolean clampedX = false;
|
||||
if (newScrollX > right) {
|
||||
newScrollX = right;
|
||||
clampedX = true;
|
||||
} else if (newScrollX < left) {
|
||||
newScrollX = left;
|
||||
clampedX = true;
|
||||
}
|
||||
|
||||
boolean clampedY = false;
|
||||
if (newScrollY > bottom) {
|
||||
newScrollY = bottom;
|
||||
clampedY = true;
|
||||
} else if (newScrollY < top) {
|
||||
newScrollY = top;
|
||||
clampedY = true;
|
||||
}
|
||||
|
||||
if (clampedY && !hasNestedScrollingParent(ViewCompat.TYPE_NON_TOUCH)) {
|
||||
mScroller.springBack(newScrollX, newScrollY, 0, 0, 0, getScrollRange());
|
||||
}
|
||||
|
||||
onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
|
||||
|
||||
return clampedX || clampedY;
|
||||
}
|
||||
|
||||
private float mVerticalScrollFactor;
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
if ((event.getSource() & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_SCROLL: {
|
||||
if (!mIsBeingDragged) {
|
||||
final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
|
||||
if (vscroll != 0) {
|
||||
final int delta = (int) (vscroll * getVerticalScrollFactorCompat());
|
||||
final int range = getScrollRange();
|
||||
int oldScrollY = getScrollY();
|
||||
int newScrollY = oldScrollY - delta;
|
||||
if (newScrollY < 0) {
|
||||
newScrollY = 0;
|
||||
} else if (newScrollY > range) {
|
||||
newScrollY = range;
|
||||
}
|
||||
if (newScrollY != oldScrollY) {
|
||||
super.scrollTo(getScrollX(), newScrollY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private float getVerticalScrollFactorCompat() {
|
||||
if (mVerticalScrollFactor == 0) {
|
||||
TypedValue outValue = new TypedValue();
|
||||
final Context context = getContext();
|
||||
if (!context.getTheme().resolveAttribute(
|
||||
android.R.attr.listPreferredItemHeight, outValue, true)) {
|
||||
throw new IllegalStateException(
|
||||
"Expected theme to define listPreferredItemHeight.");
|
||||
}
|
||||
mVerticalScrollFactor = outValue.getDimension(
|
||||
context.getResources().getDisplayMetrics());
|
||||
}
|
||||
return mVerticalScrollFactor;
|
||||
}
|
||||
|
||||
|
||||
private void endDrag() {
|
||||
mIsBeingDragged = false;
|
||||
recycleVelocityTracker();
|
||||
stopNestedScroll();
|
||||
}
|
||||
|
||||
private void onSecondaryPointerUp(MotionEvent ev) {
|
||||
final int pointerIndex = ev.getActionIndex();
|
||||
final int pointerId = ev.getPointerId(pointerIndex);
|
||||
if (pointerId == mActivePointerId) {
|
||||
// This was our active pointer going up. Choose a new
|
||||
// active pointer and adjust accordingly.
|
||||
// TODO: Make this decision more intelligent.
|
||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||
mLastMotionY = (int) ev.getY(newPointerIndex);
|
||||
mActivePointerId = ev.getPointerId(newPointerIndex);
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initOrResetVelocityTracker() {
|
||||
if (mVelocityTracker == null) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
} else {
|
||||
mVelocityTracker.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void initVelocityTrackerIfNotExists() {
|
||||
if (mVelocityTracker == null) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
}
|
||||
}
|
||||
|
||||
private void recycleVelocityTracker() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void flingWithNestedDispatch(int velocityY) {
|
||||
final int scrollY = getScrollY();
|
||||
final boolean canFling = (scrollY > 0 || velocityY > 0)
|
||||
&& (scrollY < getScrollRange() || velocityY < 0);
|
||||
if (!dispatchNestedPreFling(0, velocityY)) {
|
||||
dispatchNestedFling(0, velocityY, canFling);
|
||||
fling(velocityY);
|
||||
}
|
||||
}
|
||||
|
||||
public void fling(int velocityY) {
|
||||
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
|
||||
mScroller.fling(getScrollX(), getScrollY(), // start
|
||||
0, velocityY, // velocities
|
||||
0, 0, // x
|
||||
Integer.MIN_VALUE, Integer.MAX_VALUE, // y
|
||||
0, 0); // overscroll
|
||||
mLastScrollerY = getScrollY();
|
||||
ViewCompat.postInvalidateOnAnimation(this);
|
||||
}
|
||||
|
||||
private int mLastScrollerY;
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
if (mScroller.computeScrollOffset()) {
|
||||
final int x = mScroller.getCurrX();
|
||||
final int y = mScroller.getCurrY();
|
||||
|
||||
int dy = y - mLastScrollerY;
|
||||
|
||||
// Dispatch up to parent
|
||||
if (dispatchNestedPreScroll(0, dy, mScrollConsumed, null, ViewCompat.TYPE_NON_TOUCH)) {
|
||||
dy -= mScrollConsumed[1];
|
||||
}
|
||||
|
||||
if (dy != 0) {
|
||||
final int range = getScrollRange();
|
||||
final int oldScrollY = getScrollY();
|
||||
|
||||
overScrollByCompat(0, dy, getScrollX(), oldScrollY, 0, range, 0, 0, false);
|
||||
|
||||
final int scrolledDeltaY = getScrollY() - oldScrollY;
|
||||
final int unconsumedY = dy - scrolledDeltaY;
|
||||
|
||||
if (!dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, null,
|
||||
ViewCompat.TYPE_NON_TOUCH)) {
|
||||
final int mode = getOverScrollMode();
|
||||
final boolean canOverscroll = mode == OVER_SCROLL_ALWAYS
|
||||
|| (mode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
|
||||
if (canOverscroll) {
|
||||
// ensureGlows();
|
||||
// if (y <= 0 && oldScrollY > 0) {
|
||||
// mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
|
||||
// } else if (y >= range && oldScrollY < range) {
|
||||
// mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally update the scroll positions and post an invalidation
|
||||
mLastScrollerY = y;
|
||||
ViewCompat.postInvalidateOnAnimation(this);
|
||||
} else {
|
||||
// We can't scroll any more, so stop any indirect scrolling
|
||||
if (hasNestedScrollingParent(ViewCompat.TYPE_NON_TOUCH)) {
|
||||
stopNestedScroll(ViewCompat.TYPE_NON_TOUCH);
|
||||
}
|
||||
// and reset the scroller y
|
||||
mLastScrollerY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNestedScrollingEnabled() {
|
||||
return mChildHelper.isNestedScrollingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNestedScrollingEnabled(boolean enabled) {
|
||||
mChildHelper.setNestedScrollingEnabled(enabled);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNestedScrollAxes() {
|
||||
return mParentHelper.getNestedScrollAxes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startNestedScroll(int axes, int type) {
|
||||
return mChildHelper.startNestedScroll(axes, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopNestedScroll(int type) {
|
||||
mChildHelper.stopNestedScroll(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNestedScrollingParent(int type) {
|
||||
return mChildHelper.hasNestedScrollingParent(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
|
||||
int dyUnconsumed, int[] offsetInWindow, int type) {
|
||||
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
|
||||
offsetInWindow, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow,
|
||||
int type) {
|
||||
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
|
||||
int dyUnconsumed) {
|
||||
final int oldScrollY = getScrollY();
|
||||
scrollBy(0, dyUnconsumed);
|
||||
final int myConsumed = getScrollY() - oldScrollY;
|
||||
final int myUnconsumed = dyUnconsumed - myConsumed;
|
||||
dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
|
||||
dispatchNestedPreScroll(dx, dy, consumed, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
|
||||
if (!consumed) {
|
||||
flingWithNestedDispatch((int) velocityY);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
|
||||
return dispatchNestedPreFling(velocityX, velocityY);
|
||||
}
|
||||
|
||||
// nested scroll parent
|
||||
@Override
|
||||
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
|
||||
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
|
||||
mParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
|
||||
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopNestedScroll(View target) {
|
||||
mParentHelper.onStopNestedScroll(target);
|
||||
stopNestedScroll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #scrollTo}, but scroll smoothly instead of immediately.
|
||||
*
|
||||
* @param x the position where to scroll on the X axis
|
||||
* @param y the position where to scroll on the Y axis
|
||||
*/
|
||||
public final void smoothScrollTo(int x, int y) {
|
||||
smoothScrollBy(x - getScrollX(), y - getScrollY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
|
||||
*
|
||||
* @param dx the number of pixels to scroll by on the X axis
|
||||
* @param dy the number of pixels to scroll by on the Y axis
|
||||
*/
|
||||
private long mLastScroll;
|
||||
static final int ANIMATED_SCROLL_GAP = 250;
|
||||
|
||||
public final void smoothScrollBy(int dx, int dy) {
|
||||
long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
|
||||
if (duration > ANIMATED_SCROLL_GAP) {
|
||||
final int height = getHeight() - getPaddingBottom() - getPaddingTop();
|
||||
final int bottom = getHeight();
|
||||
final int maxY = Math.max(0, bottom - height);
|
||||
final int scrollY = getScrollY();
|
||||
dy = Math.max(0, Math.min(scrollY + dy, maxY)) - scrollY;
|
||||
|
||||
mScroller.startScroll(getScrollX(), scrollY, 0, dy);
|
||||
ViewCompat.postInvalidateOnAnimation(this);
|
||||
} else {
|
||||
if (!mScroller.isFinished()) {
|
||||
mScroller.abortAnimation();
|
||||
}
|
||||
scrollBy(dx, dy);
|
||||
}
|
||||
mLastScroll = AnimationUtils.currentAnimationTimeMillis();
|
||||
}
|
||||
|
||||
static class AccessibilityDelegate extends AccessibilityDelegateCompat {
|
||||
@Override
|
||||
public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
|
||||
if (super.performAccessibilityAction(host, action, arguments)) {
|
||||
return true;
|
||||
}
|
||||
final NestedScrollWebView2 nsvHost = (NestedScrollWebView2) host;
|
||||
if (!nsvHost.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
switch (action) {
|
||||
case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
|
||||
final int viewportHeight = nsvHost.getHeight() - nsvHost.getPaddingBottom()
|
||||
- nsvHost.getPaddingTop();
|
||||
final int targetScrollY = Math.min(nsvHost.getScrollY() + viewportHeight,
|
||||
nsvHost.getScrollRange());
|
||||
if (targetScrollY != nsvHost.getScrollY()) {
|
||||
nsvHost.smoothScrollTo(0, targetScrollY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
|
||||
final int viewportHeight = nsvHost.getHeight() - nsvHost.getPaddingBottom()
|
||||
- nsvHost.getPaddingTop();
|
||||
final int targetScrollY = Math.max(nsvHost.getScrollY() - viewportHeight, 0);
|
||||
if (targetScrollY != nsvHost.getScrollY()) {
|
||||
nsvHost.smoothScrollTo(0, targetScrollY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
final NestedScrollWebView2 nsvHost = (NestedScrollWebView2) host;
|
||||
info.setClassName(ScrollView.class.getName());
|
||||
if (nsvHost.isEnabled()) {
|
||||
final int scrollRange = nsvHost.getScrollRange();
|
||||
if (scrollRange > 0) {
|
||||
info.setScrollable(true);
|
||||
if (nsvHost.getScrollY() > 0) {
|
||||
info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
|
||||
}
|
||||
if (nsvHost.getScrollY() < scrollRange) {
|
||||
info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||
super.onInitializeAccessibilityEvent(host, event);
|
||||
final NestedScrollWebView2 nsvHost = (NestedScrollWebView2) host;
|
||||
event.setClassName(ScrollView.class.getName());
|
||||
final boolean scrollable = nsvHost.getScrollRange() > 0;
|
||||
event.setScrollable(scrollable);
|
||||
event.setScrollX(nsvHost.getScrollX());
|
||||
event.setScrollY(nsvHost.getScrollY());
|
||||
AccessibilityRecordCompat.setMaxScrollX(event, nsvHost.getScrollX());
|
||||
AccessibilityRecordCompat.setMaxScrollY(event, nsvHost.getScrollRange());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop any current scroll
|
||||
* #fling(int, int)} or a touch-initiated fling.
|
||||
*/
|
||||
public void stopScroll() {
|
||||
if (mScroller != null) {
|
||||
mScroller.forceFinished(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,11 +8,10 @@ import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.ArrayMap;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.util.AppDebugConfig;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DeviceUtils;
|
||||
@ -31,7 +30,6 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository;
|
||||
import com.google.gson.Gson;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.config.CommonDebug;
|
||||
import com.lightgame.download.ConnectionUtils;
|
||||
import com.lightgame.download.DataChanger;
|
||||
@ -56,11 +54,18 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||
|
||||
public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
private static DownloadManager mInstance;
|
||||
private static Gson gson = new Gson();
|
||||
private static final String HINT_MARK = "hint_mark";
|
||||
private static final String UPDATE_IS_READ_MARK = "update_is_read";
|
||||
private static final String DOWNLOADING_IS_READ_MARK = "downloading_is_read";
|
||||
private static final String DOWNLOADED_IS_READ_MARK = "downloaded_is_read";
|
||||
|
||||
private Context mContext;
|
||||
private Handler mHandler;
|
||||
@ -131,7 +136,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
mContext = context.getApplicationContext();
|
||||
mDownloadDao = DownloadDao.getInstance(mContext);
|
||||
|
||||
mUpdateMarks = SPUtils.getStringSet(HINT_MARK);
|
||||
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
|
||||
|
||||
//TODO unregister this
|
||||
DownloadStatusManager.getInstance().registerTaskStatusListener(this);
|
||||
@ -147,6 +152,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
statusMap = new ArrayMap<>();
|
||||
downloadingMap = new ArrayMap<>();
|
||||
|
||||
// TODO 这里的 handler 类的 case 可能会被多次调用,原因未知
|
||||
mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
@ -187,7 +193,6 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
downloadingMap.put(downloadEntity.getUrl(), downloadEntity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ArrayMap<String, DownloadEntity> getDownloadingMap() {
|
||||
@ -224,21 +229,6 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
boolean isSubscribe,
|
||||
@Nullable ExposureEvent traceEvent) {
|
||||
|
||||
// 安装指引
|
||||
/*if ("Huawei".equalsIgnoreCase(MANUFACTURER) || "Oppo".equalsIgnoreCase(MANUFACTURER)) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final SharedPreferences.Editor edit = sp.edit();
|
||||
if (sp.getBoolean("InstallHint" + PackageUtils.getVersionName(), true)) {
|
||||
try {
|
||||
DialogUtils.showInstallHintDialog(context,
|
||||
() -> edit.putBoolean("InstallHint" + PackageUtils.getVersionName(), false).apply());
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
edit.putBoolean("InstallHint" + PackageUtils.getVersionName(), false).apply();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// 插件版本下载互斥弹窗
|
||||
List<String> mutexPackage = gameEntity.getMutexPackage();
|
||||
if (mutexPackage != null && mutexPackage.size() > 0) {
|
||||
@ -261,7 +251,6 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
downloadEntity.setPackageName(apkEntity.getPackageName());
|
||||
downloadEntity.setGameId(gameEntity.getId());
|
||||
downloadEntity.setEntrance(entrance);
|
||||
downloadEntity.setExposureTrace(gson.toJson(traceEvent));
|
||||
downloadEntity.setLocation(location);
|
||||
downloadEntity.setVersionName(apkEntity.getVersion());
|
||||
int installed = 0;
|
||||
@ -281,9 +270,16 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
|
||||
|
||||
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, gameEntity.getPlatform(), traceEvent, downloadType);
|
||||
|
||||
// 将下载事件放入 downloadEntity 中供下载完成时取出使用
|
||||
downloadEntity.setExposureTrace(gson.toJson(downloadExposureEvent));
|
||||
|
||||
if (isSubscribe) {
|
||||
DownloadManager.getInstance(context).subscribe(downloadEntity);
|
||||
} else {
|
||||
HistoryHelper.insertGameEntity(gameEntity);
|
||||
DownloadManager.getInstance(context).add(downloadEntity);
|
||||
}
|
||||
|
||||
@ -294,6 +290,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
//TODO remove
|
||||
DownloadManager.getInstance(context).putStatus(downloadEntity.getUrl(), DownloadStatus.downloading);
|
||||
|
||||
DownloadManager.getInstance(context).markDownloadingTaskAsUnread();
|
||||
// 收集下载数据
|
||||
DataCollectionUtils.uploadDownload(context, downloadEntity, "开始");
|
||||
GdtHelper.INSTANCE.logAction(ActionType.DOWNLOAD_APP,
|
||||
@ -631,7 +628,6 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
}
|
||||
}
|
||||
|
||||
// 开启下载服务, Fuck me, 即便是在启动页调用的方法,依然有可能触发 `unable is in background`
|
||||
startDownloadService();
|
||||
checkRetryDownload();
|
||||
}
|
||||
@ -648,11 +644,11 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
|
||||
private void startDownloadService() {
|
||||
Intent serviceIntent = new Intent(mContext, DownloadService.class);
|
||||
// 当满足系统版本大于 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);
|
||||
// 当满足系统版本大于 8.0 并且进程处于 CREATED 状态 (ON_STOP后的状态) 的时候才以前台服务开启
|
||||
// "not allowed to start service, app is in background" 的错误概率比 "startForegroundService() did not then call Service.startForeground() " 低
|
||||
// 所以还是老老实实地以 startService 为主吧
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
|
||||
mContext.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
mContext.startService(serviceIntent);
|
||||
@ -674,8 +670,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
Intent serviceIntent = getIntent(downloadEntity, status);
|
||||
// 当满足系统版本大于 8.0 、应用在后台运行时以前台服务开启
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& !HaloApp.getInstance().isRunningForeground) {
|
||||
serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
|
||||
&& ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
|
||||
mContext.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
mContext.startService(serviceIntent);
|
||||
@ -713,19 +708,26 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
*/
|
||||
@Nullable
|
||||
public String getDownloadOrUpdateCount(List<GameUpdateEntity> updateList) {
|
||||
boolean containsReadDownloadingTask = false; // 存在已读的下载中任务
|
||||
boolean showRedPoint = false;
|
||||
int downloadingSize = 0;
|
||||
|
||||
for (DownloadEntity downloadEntity : getAll()) {
|
||||
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
String mark = downloadEntity.getMeta().get(HINT_MARK);
|
||||
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
|
||||
if (TextUtils.isEmpty(mark)) showRedPoint = true;
|
||||
} else {
|
||||
// 存在已读的下载中任务就直接不返回下载中数量,因为在新建下载时就执行了将所有下载中任务的已读变为未读的操作
|
||||
if (!TextUtils.isEmpty(downloadEntity.getMeta().get(DOWNLOADING_IS_READ_MARK))) {
|
||||
containsReadDownloadingTask = true;
|
||||
}
|
||||
downloadingSize++;
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadingSize != 0) return String.valueOf(downloadingSize);
|
||||
if (downloadingSize != 0 && !containsReadDownloadingTask) {
|
||||
return String.valueOf(downloadingSize);
|
||||
}
|
||||
|
||||
if (showRedPoint) return "";
|
||||
|
||||
@ -740,6 +742,31 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getUnreadUpdateCount(List<GameUpdateEntity> updateList) {
|
||||
int unreadUpdateCount = 0;
|
||||
if (updateList != null) {
|
||||
for (GameUpdateEntity updateEntity : updateList) {
|
||||
if (updateEntity.isShowPlugin(PluginLocation.only_index)
|
||||
&& !mUpdateMarks.contains(updateEntity.getId() + updateEntity.getPackageName())) {
|
||||
unreadUpdateCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return unreadUpdateCount;
|
||||
}
|
||||
|
||||
public boolean isContainsUnreadDownloadedTask() {
|
||||
for (DownloadEntity downloadEntity : getAll()) {
|
||||
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
|
||||
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
|
||||
if (TextUtils.isEmpty(mark)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记下载已完成的任务为已读 (用于下载管理页入口的 toolbar 红点显示)
|
||||
*/
|
||||
@ -751,9 +778,54 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
for (DownloadEntity downloadEntity : all) {
|
||||
DownloadStatus status = downloadEntity.getStatus();
|
||||
if (status == DownloadStatus.done) {
|
||||
String mark = downloadEntity.getMeta().get(HINT_MARK);
|
||||
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
|
||||
if (TextUtils.isEmpty(mark)) {
|
||||
downloadEntity.getMeta().put(HINT_MARK, HINT_MARK);
|
||||
downloadEntity.getMeta().put(DOWNLOADED_IS_READ_MARK, DOWNLOADED_IS_READ_MARK);
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
if (!markHasChanged) markHasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (markHasChanged) {
|
||||
EventBus.getDefault().post(new EBDownloadStatus("download", "", "", "", "", ""));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记下载中任务为已读状态(用于下载页及外部toolbar)
|
||||
*/
|
||||
public void markDownloadingTaskAsRead() {
|
||||
markDownloadingTaskAsReadOrUnread(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记下载中任务为未读状态(用于下载页及外部toolbar)
|
||||
*/
|
||||
public void markDownloadingTaskAsUnread() {
|
||||
markDownloadingTaskAsReadOrUnread(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改下载中任务的已读状态(用于下载页及外部toolbar)
|
||||
*/
|
||||
private void markDownloadingTaskAsReadOrUnread(boolean isRead) {
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
List<DownloadEntity> all = getAll();
|
||||
for (DownloadEntity downloadEntity : all) {
|
||||
if (downloadEntity.getStatus() != DownloadStatus.done) {
|
||||
if (isRead) {
|
||||
String mark = downloadEntity.getMeta().get(DOWNLOADING_IS_READ_MARK);
|
||||
if (TextUtils.isEmpty(mark)) {
|
||||
downloadEntity.getMeta().put(DOWNLOADING_IS_READ_MARK, DOWNLOADING_IS_READ_MARK);
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
if (!markHasChanged) markHasChanged = true;
|
||||
}
|
||||
} else {
|
||||
downloadEntity.getMeta().put(DOWNLOADING_IS_READ_MARK, "");
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
if (!markHasChanged) markHasChanged = true;
|
||||
}
|
||||
@ -795,7 +867,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
public void saveUpdateMarkToStorage() {
|
||||
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
if (updates.size() == mUpdateMarks.size()) {
|
||||
SPUtils.setStringSet(HINT_MARK, mUpdateMarks);
|
||||
SPUtils.setStringSet(UPDATE_IS_READ_MARK, mUpdateMarks);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -804,7 +876,18 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
String mark = update.getId() + update.getPackageName();
|
||||
marks.add(mark);
|
||||
}
|
||||
SPUtils.setStringSet(HINT_MARK, marks);
|
||||
SPUtils.setStringSet(UPDATE_IS_READ_MARK, marks);
|
||||
}
|
||||
|
||||
public void updateDownloadEntity(DownloadEntity downloadEntity) {
|
||||
mDownloadDao.newOrUpdate(downloadEntity);
|
||||
}
|
||||
|
||||
public void startDownload(String url) {
|
||||
put(url, System.currentTimeMillis());
|
||||
Message msg = Message.obtain();
|
||||
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_AUTO_TASK;
|
||||
msg.obj = url;
|
||||
sendMessageDelayed(msg, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ 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.GSYDefaultHttpDataSource
|
||||
import tv.danmaku.ijk.media.exo2.source.GSYExoHttpDataSourceFactory
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
@ -25,41 +25,58 @@ object ExoCacheManager {
|
||||
|
||||
private val threads = ConcurrentHashMap<String, AtomicBoolean>()
|
||||
|
||||
private val preLength by lazy {
|
||||
private fun getPreLength(): Long {
|
||||
val totalRamSizeOfDevice = DeviceUtils.getTotalRamSizeOfDevice(HaloApp.getInstance().application)
|
||||
if (totalRamSizeOfDevice <= 2 * 1024) {
|
||||
10 * 1024 * 1024L
|
||||
return if (totalRamSizeOfDevice <= 2 * 1024) {
|
||||
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
|
||||
10 * 1024 * 1024L
|
||||
} else {
|
||||
when (NetworkUtils.getMobileNetworkType(HaloApp.getInstance().application)) {
|
||||
"5G", "4G" -> 10 * 1024 * 1024L
|
||||
"3G" -> 5 * 1024 * 1024L
|
||||
else -> 0L
|
||||
}
|
||||
}
|
||||
} else {
|
||||
50 * 1024 * 1024L
|
||||
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
|
||||
50 * 1024 * 1024L
|
||||
} else {
|
||||
when (NetworkUtils.getMobileNetworkType(HaloApp.getInstance().application)) {
|
||||
"5G", "4G" -> 20 * 1024 * 1024L
|
||||
"3G" -> 5 * 1024 * 1024L
|
||||
else -> 0L
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: Throwable) {
|
||||
threads.remove(videoUri)
|
||||
e.printStackTrace()
|
||||
}
|
||||
val preLength = getPreLength()
|
||||
if (preLength == 0L) return
|
||||
runOnIoThread {
|
||||
Thread.sleep(100)
|
||||
threads[videoUri] = AtomicBoolean(false)
|
||||
val contentLength = getContentLength(videoUri)
|
||||
val cacheLength = if (contentLength >= preLength) preLength else contentLength
|
||||
val dataSpec = DataSpec(Uri.parse(videoUri), 0, cacheLength, null)
|
||||
val simpleCache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
|
||||
val dataSourceFactory = GSYExoHttpDataSourceFactory(Util.getUserAgent(HaloApp.getInstance().application,
|
||||
"ExoCacheManager"), DefaultBandwidthMeter.Builder(HaloApp.getInstance().application).build(),
|
||||
GSYDefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
|
||||
GSYDefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false)
|
||||
val cacheDataSource = CacheDataSource(simpleCache, dataSourceFactory.createDataSource())
|
||||
try {
|
||||
CacheUtil.cache(dataSpec, simpleCache, CacheUtil.DEFAULT_CACHE_KEY_FACTORY, cacheDataSource, CacheUtil.ProgressListener { requestLength, bytesCached, newBytesCached ->
|
||||
if (requestLength == bytesCached) {
|
||||
threads.remove(videoUri)
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Utils.log("$requestLength--$bytesCached--$newBytesCached")
|
||||
}
|
||||
}, threads[videoUri])
|
||||
} catch (e: Throwable) {
|
||||
threads.remove(videoUri)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import androidx.recyclerview.widget.*
|
||||
import androidx.recyclerview.widget.RecyclerView.SmoothScroller
|
||||
import com.gh.base.fragment.BaseDialogFragment
|
||||
import com.gh.common.TimeElapsedHelper
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.*
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
@ -45,6 +46,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
private lateinit var mGestureDetector: GestureDetector
|
||||
|
||||
private var mAdapter: DownloadDialogAdapter? = null
|
||||
private var mTraceEvent: ExposureEvent? = null
|
||||
|
||||
// 合集页面保持和后台一样的顺序
|
||||
private var mCollectionAdapter: DownloadDialogAdapter? = null
|
||||
@ -99,11 +101,12 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
mGameEntity = requireArguments().getParcelable(GameEntity::class.java.simpleName)!!
|
||||
mEntrance = requireArguments().getString(EntranceUtils.KEY_ENTRANCE) ?: ""
|
||||
mLocation = requireArguments().getString(EntranceUtils.KEY_LOCATION) ?: ""
|
||||
mTraceEvent = requireArguments().getParcelable(EntranceUtils.KEY_TRACE_EVENT) ?: null
|
||||
|
||||
val factory = DownloadViewModel.Factory(HaloApp.getInstance().application, mGameEntity)
|
||||
mViewModel = ViewModelProviders.of(this, factory).get(DownloadViewModel::class.java)
|
||||
mViewModel.listLiveData.observeNonNull(this, callback = { itemList ->
|
||||
mAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mEntrance, mLocation)
|
||||
mAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mTraceEvent, mEntrance, mLocation)
|
||||
mBinding.contentList.layoutManager = createLayoutManager(itemList)
|
||||
mBinding.contentList.adapter = mAdapter
|
||||
})
|
||||
@ -124,7 +127,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
itemList.add(DownloadDialogItemData(instruction = collection.downloadInstruction))
|
||||
}
|
||||
|
||||
mCollectionAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, true, mEntrance, mLocation)
|
||||
mCollectionAdapter = DownloadDialogAdapter(requireContext(), mViewModel, itemList, true, mTraceEvent, mEntrance, mLocation)
|
||||
mBinding.collectionList.layoutManager = createLayoutManager(itemList)
|
||||
mBinding.collectionList.adapter = mCollectionAdapter
|
||||
|
||||
@ -383,7 +386,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun showDownloadDialog(context: Context?, gameEntity: GameEntity, entrance: String?, location: String?) {
|
||||
fun showDownloadDialog(context: Context?, gameEntity: GameEntity, traceEvent: ExposureEvent?, entrance: String?, location: String?) {
|
||||
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
|
||||
context
|
||||
} else if (BuildConfig.DEBUG) {
|
||||
@ -405,6 +408,7 @@ class DownloadDialog : BaseDialogFragment(), View.OnTouchListener {
|
||||
bundle.putString(EntranceUtils.KEY_ENTRANCE, entrance)
|
||||
bundle.putString(EntranceUtils.KEY_LOCATION, location)
|
||||
bundle.putParcelable(GameEntity::class.java.simpleName, gameEntity)
|
||||
bundle.putParcelable(EntranceUtils.KEY_TRACE_EVENT, traceEvent)
|
||||
arguments = bundle
|
||||
}
|
||||
downloadDialog.show(fragmentActivity.supportFragmentManager, DownloadDialog::class.java.name)
|
||||
|
||||
@ -5,6 +5,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.OnViewClickListener
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.throwExceptionInDebug
|
||||
import com.gh.gamecenter.NewsDetailActivity
|
||||
@ -19,6 +20,7 @@ class DownloadDialogAdapter(context: Context,
|
||||
val viewModel: DownloadViewModel,
|
||||
val listData: List<DownloadDialogItemData>,
|
||||
val isCollectionPage: Boolean,
|
||||
private val mTraceEvent: ExposureEvent?,
|
||||
private val mEntrance: String,
|
||||
private val mLocation: String) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
|
||||
@ -104,11 +106,11 @@ class DownloadDialogAdapter(context: Context,
|
||||
holder.bindItem(viewModel.gameEntity)
|
||||
}
|
||||
is DownloadDialogInstalledItemViewHolder -> {
|
||||
holder.bindInstalledItem(listData[position].installed!!, viewModel, mEntrance, mPath, mLocation)
|
||||
holder.bindInstalledItem(listData[position].installed!!, viewModel, mTraceEvent, mEntrance, mPath, mLocation)
|
||||
throwExceptionInDebug("合集页面不应该存在该条数据", isCollectionPage)
|
||||
}
|
||||
is DownloadDialogItemViewHolder -> {
|
||||
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mEntrance, mPath, mLocation)
|
||||
holder.bindItem(listData[position].normal!!, viewModel, isCollectionPage, mTraceEvent, mEntrance, mPath, mLocation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.download.dialog
|
||||
import android.view.View
|
||||
import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.util.goneIf
|
||||
import com.gh.common.util.throwExceptionInDebug
|
||||
@ -15,7 +16,7 @@ import com.lightgame.download.DownloadStatus
|
||||
|
||||
class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalledItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
fun bindInstalledItem(apkEntity: ApkEntity, viewModel: DownloadViewModel, entrance: String, path: String, location: String) {
|
||||
fun bindInstalledItem(apkEntity: ApkEntity, viewModel: DownloadViewModel, traceEvent: ExposureEvent?, entrance: String, path: String, location: String) {
|
||||
|
||||
val gameEntity = viewModel.gameEntity
|
||||
val apkCollection = apkEntity.apkCollection
|
||||
@ -122,7 +123,7 @@ class DownloadDialogInstalledItemViewHolder(val binding: DownloadDialogInstalled
|
||||
}
|
||||
}
|
||||
|
||||
DownloadDialogItemViewHolder.setDownloadClickListener(itemView, apkEntity, viewModel, entrance, path, location)
|
||||
DownloadDialogItemViewHolder.setDownloadClickListener(itemView, apkEntity, viewModel, traceEvent, entrance, path, location)
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import com.gh.base.BaseRecyclerViewHolder
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.dialog.CertificationDialog
|
||||
import com.gh.common.dialog.DeviceRemindDialog
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DirectUtils.directToLinkPage
|
||||
import com.gh.download.DownloadManager
|
||||
@ -16,6 +17,7 @@ import com.gh.gamecenter.databinding.DownloadDialogItemBinding
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
import com.gh.gamecenter.entity.GameCollectionEntity
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
@ -28,6 +30,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
fun bindItem(apkEntity: ApkEntity,
|
||||
viewModel: DownloadViewModel,
|
||||
isCollectionPage: Boolean,
|
||||
traceEvent: ExposureEvent?,
|
||||
entrance: String,
|
||||
path: String,
|
||||
location: String) {
|
||||
@ -105,7 +108,8 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
binding.status.text = "可更新"
|
||||
binding.downloadStatusIcon.setImageResource(R.drawable.download_dialog_collection_status_update)
|
||||
itemView.setTag(DownloadDialogAdapter.ITEM_TAG_KEY, DownloadDialogItemStatus.UPDATE)
|
||||
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id) {
|
||||
} else if (PackageUtils.getGhId(apkEntity.packageName) == gameEntity.id ||
|
||||
PackagesManager.isInstalled(apkEntity.packageName) && Config.getSettings()?.gameDownloadBlackList?.contains(apkEntity.packageName) == true) {
|
||||
binding.downloadStatusIcon.visibility = View.GONE
|
||||
binding.status.visibility = View.VISIBLE
|
||||
binding.root.setBackgroundResource(R.drawable.download_dialog_installed_background)
|
||||
@ -140,7 +144,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
}
|
||||
}
|
||||
|
||||
setDownloadClickListener(itemView, apkEntity, viewModel, entrance, path, location)
|
||||
setDownloadClickListener(itemView, apkEntity, viewModel, traceEvent, entrance, path, location)
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
|
||||
@ -157,6 +161,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
fun setDownloadClickListener(itemView: View,
|
||||
apkEntity: ApkEntity,
|
||||
viewModel: DownloadViewModel,
|
||||
traceEvent: ExposureEvent?,
|
||||
entrance: String,
|
||||
path: String,
|
||||
location: String) {
|
||||
@ -166,7 +171,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
var mtaValue = "未知"
|
||||
when (itemView.getTag(DownloadDialogAdapter.ITEM_TAG_KEY)) {
|
||||
DownloadDialogItemStatus.DOWNLOAD -> {
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, "下载", entrance, location)
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, "下载", traceEvent, entrance, location)
|
||||
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_下载"
|
||||
}
|
||||
DownloadDialogItemStatus.LAUNCH -> {
|
||||
@ -218,12 +223,12 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
}
|
||||
}
|
||||
DownloadDialogItemStatus.PLUGGABLE -> {
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, "插件化", entrance, location)
|
||||
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, "插件化", traceEvent, entrance, location)
|
||||
|
||||
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_插件化"
|
||||
}
|
||||
DownloadDialogItemStatus.UPDATE -> {
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, "更新", entrance, location)
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, "更新", traceEvent, entrance, location)
|
||||
|
||||
mtaValue = gameEntity.name + "_" + apkEntity.getPlatformName() + "_更新"
|
||||
}
|
||||
@ -263,26 +268,33 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
apkEntity: ApkEntity,
|
||||
gameEntity: GameEntity,
|
||||
downloadMethod: String,
|
||||
traceEvent: ExposureEvent?,
|
||||
entrance: String,
|
||||
location: String) {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
|
||||
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
|
||||
DownloadManager.createDownload(
|
||||
context,
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
downloadMethod,
|
||||
entrance,
|
||||
location,
|
||||
isSubscribe, null)
|
||||
// todo 有时间存储判断统一处理
|
||||
val msg = FileUtils.isCanDownload(context, apkEntity.size)
|
||||
if (msg.isNullOrEmpty()) {
|
||||
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
CertificationDialog.showCertificationDialog(context, gameEntity, DialogUtils.ConfirmListener {
|
||||
DialogUtils.checkDownload(context, apkEntity.size) { isSubscribe ->
|
||||
DownloadManager.createDownload(
|
||||
context,
|
||||
apkEntity,
|
||||
gameEntity,
|
||||
downloadMethod,
|
||||
entrance,
|
||||
location,
|
||||
isSubscribe, traceEvent)
|
||||
|
||||
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
DeviceRemindDialog.showDeviceRemindDialog(context, gameEntity)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Utils.toast(context, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.entity.ApkEntity
|
||||
@ -61,12 +62,14 @@ class DownloadViewModel(application: Application, val gameEntity: GameEntity) :
|
||||
apk.apkCollection?.saveApkEntity?.let {
|
||||
for (entity in it) {
|
||||
isInstalled = PackagesManager.isInstalled(entity.packageName)
|
||||
&& Config.getSettings()?.gameDownloadBlackList?.contains(entity.packageName) != true
|
||||
if (isInstalled) break
|
||||
}
|
||||
}
|
||||
isInstalled
|
||||
} else {
|
||||
PackagesManager.isInstalled(apk.packageName)
|
||||
&& Config.getSettings()?.gameDownloadBlackList?.contains(apk.packageName) != true
|
||||
}
|
||||
if (installed) {
|
||||
mInstalledApkList.add(apk)
|
||||
|
||||
@ -3,7 +3,10 @@ package com.gh.gamecenter;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.gamecenter.entity.LinkEntity;
|
||||
import com.gh.gamecenter.entity.MessageEntity;
|
||||
@ -11,11 +14,30 @@ import com.gh.gamecenter.qa.comment.CommentActivity;
|
||||
import com.gh.gamecenter.qa.comment.NewCommentConversationFragment;
|
||||
import com.halo.assistant.fragment.comment.CommentDetailFragment;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/3/22.
|
||||
*/
|
||||
public class CommentDetailActivity extends NormalActivity {
|
||||
|
||||
@BindView(R.id.shadowView)
|
||||
public View shadowView;
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.toolbar_shadow;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ViewGroup.LayoutParams layoutParams = shadowView.getLayoutParams();
|
||||
layoutParams.height = DisplayUtils.dip2px(50f) + DisplayUtils.getStatusBarHeight(getResources());
|
||||
shadowView.setLayoutParams(layoutParams);
|
||||
DisplayUtils.setStatusBarColor(this, R.color.transparent, true);
|
||||
}
|
||||
|
||||
// article 不为空则显示跳转原文按钮
|
||||
public static Intent getIntent(Context context, String commentId, MessageEntity.Article article) {
|
||||
Bundle args = new Bundle();
|
||||
|
||||
@ -23,9 +23,6 @@ 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;
|
||||
@ -119,6 +116,8 @@ import java.util.TimerTask;
|
||||
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;
|
||||
@ -265,22 +264,6 @@ public class MainActivity extends BaseActivity {
|
||||
//启动app删除视频缓存文件
|
||||
AppExecutor.getIoExecutor().execute(() -> {
|
||||
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();
|
||||
}*/
|
||||
String dirPath = getCacheDir().getAbsolutePath() + File.separator + "exo";
|
||||
FileUtils.deleteFolder(new File(dirPath));
|
||||
} catch (Exception e) {
|
||||
@ -292,6 +275,8 @@ public class MainActivity extends BaseActivity {
|
||||
SPUtils.setBoolean(Constants.SP_TOP_VIDEO_VOICE, true);
|
||||
//恢复视频流非Wifi提醒
|
||||
SPUtils.setBoolean(Constants.SP_NON_WIFI_TIPS, true);
|
||||
//重置顶部视频播放进度
|
||||
SPUtils.setString(Constants.SP_TOP_VIDEO_SCHEDULE, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -430,7 +415,7 @@ public class MainActivity extends BaseActivity {
|
||||
if (entity.getStatus().equals(DownloadStatus.done)) {
|
||||
if (PackageUtils.isInstalled(getApplicationContext(), entity.getPackageName())
|
||||
&& (!entity.isPlugin()
|
||||
|| PackageUtils.isSignature(getApplicationContext(), entity.getPackageName()))) {
|
||||
|| PackageUtils.isSignedByGh(getApplicationContext(), entity.getPackageName()))) {
|
||||
continue;
|
||||
}
|
||||
if (downloadEntity == null) {
|
||||
@ -523,10 +508,6 @@ public class MainActivity extends BaseActivity {
|
||||
EventBus.getDefault().post(new EBReuse(CommunityFragment.EB_RETRY_PAGE));
|
||||
}
|
||||
|
||||
private void checkRetryDownload() {
|
||||
DownloadManager.getInstance(this).checkRetryDownload();
|
||||
}
|
||||
|
||||
private void checkTinkerPath() {
|
||||
CommonDebug.logMethodWithParams(this, TinkerManager.getTinkerId(), TinkerManager.getNewTinkerId());
|
||||
CommonDebug.logMethodWithParams(this, CrashReport.getAppVer(), CrashReport.getAppID(), CrashReport.getAppChannel(), CrashReport.getSdkExtraData());
|
||||
@ -687,7 +668,6 @@ public class MainActivity extends BaseActivity {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(EBNetworkState busNetworkState) {
|
||||
if (busNetworkState.isNetworkConnected()) {
|
||||
checkRetryDownload();
|
||||
if (Config.getSettings() == null) {
|
||||
Config.getGhzsSettings();
|
||||
}
|
||||
|
||||
@ -2,13 +2,19 @@ package com.gh.gamecenter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.gamecenter.entity.CommentEntity;
|
||||
import com.gh.gamecenter.entity.ConcernEntity;
|
||||
import com.gh.gamecenter.message.MessageDetailFragment;
|
||||
import com.halo.assistant.HaloApp;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/11/8.
|
||||
* 消息详情界面(评论详情)
|
||||
@ -16,6 +22,23 @@ import com.halo.assistant.HaloApp;
|
||||
@Deprecated
|
||||
public class MessageDetailActivity extends NormalActivity {
|
||||
|
||||
@BindView(R.id.shadowView)
|
||||
public View shadowView;
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.toolbar_shadow;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ViewGroup.LayoutParams layoutParams = shadowView.getLayoutParams();
|
||||
layoutParams.height = DisplayUtils.dip2px(50f) + DisplayUtils.getStatusBarHeight(getResources());
|
||||
shadowView.setLayoutParams(layoutParams);
|
||||
DisplayUtils.setStatusBarColor(this, R.color.transparent, false);
|
||||
}
|
||||
|
||||
// 评论回复
|
||||
public static Intent getMessageDetailIntent(Context context, CommentEntity entity, String newsId) {
|
||||
Intent intent = new Intent(context, MessageDetailActivity.class);
|
||||
|
||||
@ -7,11 +7,11 @@ import android.text.TextUtils;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.gh.base.ToolBarActivity;
|
||||
import com.gh.gamecenter.normal.NormalFragment;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
/**
|
||||
* Created by khy on 17/10/17.
|
||||
*/
|
||||
|
||||
@ -52,7 +52,6 @@ open class SearchActivity : BaseActivity() {
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val hint = intent.getStringExtra(EntranceUtils.KEY_HINT)
|
||||
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)
|
||||
|
||||
|
||||
@ -22,9 +22,13 @@ import com.lightgame.utils.Utils;
|
||||
import static com.gh.common.util.EntranceUtils.ENTRANCE_BROWSER;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_ANSWER;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_ARTICLE;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_CATEGORY;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COLUMN;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COLUMN_COLLECTION;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_COLUMN;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_DOWNLOAD;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_GAME;
|
||||
import static com.gh.common.util.EntranceUtils.HOST_LIBAO;
|
||||
@ -239,6 +243,28 @@ public class SkipActivity extends BaseActivity {
|
||||
String columnId = uri.getQueryParameter("column_id");
|
||||
DirectUtils.directToCommunityColumn(this, community, columnId, ENTRANCE_BROWSER, "");
|
||||
break;
|
||||
|
||||
case HOST_CATEGORY:
|
||||
title = uri.getQueryParameter("title");
|
||||
DirectUtils.directCategoryDirectory(this, path, title, ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
case HOST_COLUMN_COLLECTION:
|
||||
DirectUtils.directToColumnCollection(this, path, -1, ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
case HOST_COMMUNITY_QUESTION_LABEL_DETAIL:
|
||||
community = new CommunityEntity();
|
||||
community.setId(uri.getQueryParameter("community_id"));
|
||||
community.setName(uri.getQueryParameter("community_name"));
|
||||
String tag = uri.getQueryParameter("tag");
|
||||
DirectUtils.directAskColumnLabelDetail(this, tag, community, ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
case HOST_COMMUNITY_COLUMN_DETAIL:
|
||||
community = new CommunityEntity();
|
||||
community.setId(uri.getQueryParameter("community_id"));
|
||||
community.setName(uri.getQueryParameter("community_name"));
|
||||
columnId = uri.getQueryParameter("column_id");
|
||||
DirectUtils.directAskColumnDetail(this, columnId, community, ENTRANCE_BROWSER, "浏览器");
|
||||
break;
|
||||
default:
|
||||
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
|
||||
return;
|
||||
|
||||
@ -13,6 +13,7 @@ import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.Html;
|
||||
import android.text.InputFilter;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
@ -23,6 +24,12 @@ import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.gh.base.OnListClickListener;
|
||||
import com.gh.base.OnRequestCallBackListener;
|
||||
import com.gh.base.ToolBarActivity;
|
||||
@ -42,6 +49,7 @@ import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NetworkUtils;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.common.util.ShareUtils;
|
||||
import com.gh.common.util.TextHelper;
|
||||
import com.gh.common.util.UploadImageUtils;
|
||||
import com.gh.common.util.UrlFilterUtils;
|
||||
import com.gh.common.view.FixLinearLayoutManager;
|
||||
@ -81,12 +89,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
@ -421,6 +423,9 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
mSuggestContentEt.setFocusable(true);
|
||||
mSuggestContentEt.setFocusableInTouchMode(true);
|
||||
mSuggestContentEt.requestFocus();
|
||||
mSuggestContentEt.setFilters(new InputFilter[]{TextHelper.getFilter(256, "最多输入256个字")});
|
||||
mSuggestEmailEt.setFilters(new InputFilter[]{TextHelper.getFilter(64, "最多输入64个字")});
|
||||
mTypeOtherName.setFilters(new InputFilter[]{TextHelper.getFilter(30, " 最多输入30个字")});
|
||||
Util_System_Keyboard.showSoftKeyboard(this, mSuggestContentEt);
|
||||
}
|
||||
|
||||
@ -760,7 +765,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@NotNull LinkedHashMap<String, String> imageUrl) {
|
||||
public void onSuccess(@NotNull LinkedHashMap<String, String> imageUrl, @NotNull Map<String, ? extends Exception> errorMap) {
|
||||
Utils.log("意见反馈:图片上传完成");
|
||||
final JSONArray picArray = new JSONArray();
|
||||
for (String s : imageUrl.keySet()) {
|
||||
@ -770,7 +775,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
public void onError(@NotNull Map<String, ? extends Exception> errorMap) {
|
||||
if (postDialog != null) {
|
||||
postDialog.dismissAllowingStateLoss();
|
||||
}
|
||||
@ -934,6 +939,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall
|
||||
View manualContainer = view.findViewById(R.id.dialog_suggest_manual_container);
|
||||
View manualConfirm = view.findViewById(R.id.dialog_suggest_confirm);
|
||||
EditText manualEdit = view.findViewById(R.id.dialog_suggest_edit);
|
||||
manualEdit.setFilters(new InputFilter[]{TextHelper.getFilter(30, " 最多输入30个字")});
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
|
||||
recyclerView.setAdapter(new SuggestSelectGameAdapter(this, pb));
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.gamecenter;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.common.constant.Constants;
|
||||
@ -18,12 +19,37 @@ import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import static com.halo.assistant.fragment.WebFragment.KEY_GAME_NAME;
|
||||
import static com.halo.assistant.fragment.WebFragment.KEY_REQUIRE_BACK_CONFIRMATION;
|
||||
|
||||
/**
|
||||
* Created by khy on 2016/10/18.
|
||||
*/
|
||||
@Deprecated
|
||||
public class WebActivity extends NormalActivity {
|
||||
|
||||
private boolean mIsFullScreen;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Bundle bundle = getIntent().getBundleExtra(NORMAL_FRAGMENT_BUNDLE);
|
||||
if (bundle != null) {
|
||||
String mGameName = bundle.getString(KEY_GAME_NAME);
|
||||
boolean mIsBackpressRequireConfirmation = bundle.getBoolean(KEY_REQUIRE_BACK_CONFIRMATION, false);
|
||||
mIsFullScreen = !TextUtils.isEmpty(mGameName) && mIsBackpressRequireConfirmation;
|
||||
if (mIsFullScreen) {
|
||||
setTheme(R.style.AppFullScreenTheme);
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mIsFullScreen) {
|
||||
hideToolbar(true);
|
||||
}
|
||||
} else {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent provideNormalIntent() {
|
||||
return getTargetIntent(this, WebActivity.class, WebFragment.class);
|
||||
@ -203,10 +229,10 @@ public class WebActivity extends NormalActivity {
|
||||
public static Intent getIntentForWebGame(Context context, String url, String gameName, boolean interveneBackpress) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EntranceUtils.KEY_URL, url);
|
||||
bundle.putString(WebFragment.KEY_GAME_NAME, gameName);
|
||||
bundle.putString(KEY_GAME_NAME, gameName);
|
||||
bundle.putBoolean(WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_TITLE, true);
|
||||
if (interveneBackpress) {
|
||||
bundle.putBoolean(WebFragment.KEY_REQUIRE_BACK_CONFIRMATION, true);
|
||||
bundle.putBoolean(KEY_REQUIRE_BACK_CONFIRMATION, true);
|
||||
bundle.putString(WebFragment.KEY_BACK_CONFIRMATION_CONTENT, "退出后将不保存当前游戏进度,确定退出吗?");
|
||||
}
|
||||
return getTargetIntent(context, WebActivity.class, WebFragment.class, bundle);
|
||||
|
||||
@ -9,9 +9,6 @@ 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;
|
||||
@ -20,6 +17,7 @@ import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DirectUtils;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.common.util.ExtensionsKt;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.MtaHelper;
|
||||
import com.gh.common.util.NewsUtils;
|
||||
@ -55,7 +53,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
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;
|
||||
@ -331,7 +332,7 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
}
|
||||
|
||||
private void initCommentViewHolder(final CommentViewHolder holder, int position) {
|
||||
|
||||
AtomicBoolean isChildLongClick = new AtomicBoolean(false);
|
||||
int index;
|
||||
if (mHotCommentList.size() == 0) {
|
||||
index = 2;
|
||||
@ -412,6 +413,10 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
));
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (isChildLongClick.get()) {
|
||||
isChildLongClick.set(false);
|
||||
return;
|
||||
}
|
||||
if (holder.commentReply.getVisibility() == View.VISIBLE) {
|
||||
CheckLoginUtils.checkLogin(mContext, "资讯文章详情-评论详情-回复", () -> {
|
||||
mOnCommentCallBackListener.onCommentCallback(finalCommentEntity);
|
||||
@ -419,6 +424,17 @@ public class MessageDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
}
|
||||
});
|
||||
|
||||
holder.commentContentTv.setOnLongClickListener(v -> {
|
||||
isChildLongClick.set(true);
|
||||
ExtensionsKt.copyTextAndToast(holder.commentContentTv.getText().toString(), "复制成功");
|
||||
return true;
|
||||
});
|
||||
holder.quoteContentTv.setOnLongClickListener(v -> {
|
||||
isChildLongClick.set(true);
|
||||
ExtensionsKt.copyTextAndToast(holder.quoteContentTv.getText().toString(), "复制成功");
|
||||
return true;
|
||||
});
|
||||
|
||||
holder.commentMore.setOnClickListener(v ->
|
||||
CommentUtils.showReportDialog(finalCommentEntity,
|
||||
mContext, true, "资讯文章详情-评论详情"));
|
||||
|
||||
@ -5,16 +5,12 @@ import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.gh.common.dialog.CertificationDialog;
|
||||
import com.gh.common.dialog.DeviceRemindDialog;
|
||||
import com.gh.common.dialog.GameOffServiceDialogFragment;
|
||||
import com.gh.common.dialog.ReserveDialogFragment;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.util.CheckLoginUtils;
|
||||
import com.gh.common.util.DataLogUtils;
|
||||
import com.gh.common.util.DataUtils;
|
||||
@ -44,6 +40,10 @@ import com.lightgame.utils.Utils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
/**
|
||||
* Created by khy on 27/06/17.
|
||||
* 详情页面下载ViewHolder
|
||||
@ -182,6 +182,7 @@ public class DetailViewHolder {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
mViewHolder.context,
|
||||
mGameEntity,
|
||||
mTraceEvent,
|
||||
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
|
||||
mName + ":" + mTitle);
|
||||
});
|
||||
@ -198,6 +199,7 @@ public class DetailViewHolder {
|
||||
DownloadDialog.showDownloadDialog(
|
||||
mViewHolder.context,
|
||||
mGameEntity,
|
||||
mTraceEvent,
|
||||
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
|
||||
mName + ":" + mTitle);
|
||||
});
|
||||
@ -245,7 +247,13 @@ public class DetailViewHolder {
|
||||
case H5_GAME:
|
||||
MtaHelper.onEvent("H5页面", "入口", "详情页_" + mGameEntity.getName());
|
||||
LinkEntity linkEntity = mGameEntity.getH5Link();
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(mViewHolder.context, linkEntity.getLink(), mGameEntity.getName(), "play".equals(linkEntity.getType())));
|
||||
|
||||
boolean isPlay = "play".equals(linkEntity.getType()); // 是否为开始玩
|
||||
if (isPlay) {
|
||||
HistoryHelper.insertGameEntity(mGameEntity);
|
||||
}
|
||||
|
||||
Intent i = new Intent(WebActivity.getIntentForWebGame(mViewHolder.context, linkEntity.getLink(), mGameEntity.getName(),isPlay));
|
||||
mViewHolder.context.startActivity(i);
|
||||
break;
|
||||
}
|
||||
@ -275,9 +283,6 @@ public class DetailViewHolder {
|
||||
"下载开始",
|
||||
method);
|
||||
|
||||
ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, method);
|
||||
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(mGameEntity, apkEntity.getPlatform(), mTraceEvent, downloadType);
|
||||
|
||||
DownloadManager.createDownload(mViewHolder.context,
|
||||
apkEntity,
|
||||
mGameEntity,
|
||||
@ -285,7 +290,7 @@ public class DetailViewHolder {
|
||||
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
|
||||
mName + ":" + mTitle,
|
||||
isSubscribe,
|
||||
downloadExposureEvent);
|
||||
mTraceEvent);
|
||||
|
||||
mViewHolder.mDownloadPb.setProgress(0);
|
||||
mViewHolder.mDownloadPb.setDownloadType("插件化".equals(method) ?
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
package com.gh.gamecenter.amway
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.gh.common.constant.ItemViewType
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.exposure.ExposureSource
|
||||
@ -23,9 +26,9 @@ import com.gh.gamecenter.gamedetail.rating.RatingFragment
|
||||
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
|
||||
import com.gh.gamecenter.home.LegacyHomeFragmentAdapterAssistant
|
||||
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
|
||||
import com.halo.assistant.fragment.game.GamePluginAdapter
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.view.CheckableImageView
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@ -159,7 +162,6 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
|
||||
when (val adapter = recyclerView?.adapter) {
|
||||
is GameVerticalAdapter -> adapter.notifyItemByDownload(download)
|
||||
is GamePluginAdapter -> adapter.notifyItemByDownload(download)
|
||||
is HomeSlideListAdapter -> adapter.notifyItemByDownload(download)
|
||||
}
|
||||
} else {
|
||||
notifyItemChanged(gameAndPosition.position)
|
||||
@ -208,11 +210,10 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
|
||||
}
|
||||
|
||||
if (amway.comment.me.isVoted) {
|
||||
binding.likeIv.setImageResource(R.drawable.ic_amway_liked)
|
||||
binding.likeIv.isChecked = true
|
||||
binding.likeCountTv.setTextColor(R.color.theme_font.toColor())
|
||||
binding.likeCountTv.setOnClickListener { binding.likeIv.performClick() }
|
||||
binding.likeIv.setOnClickListener {
|
||||
debounceActionWithInterval(binding.likeIv.id, 1000L) {
|
||||
binding.likeClickableView.setOnClickListener {
|
||||
debounceActionWithInterval(binding.likeClickableView.id, 1000L) {
|
||||
binding.likeIv.context.ifLogin("安利墙") {
|
||||
viewModel.undoLikeAmwayComment(amway.game.id, amway.comment.id)
|
||||
MtaHelper.onEvent("安利墙", "点击", "评论${blockPosition}_${amway.game.name}_取消点赞")
|
||||
@ -220,12 +221,12 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.likeIv.setImageResource(R.drawable.ic_amway_like)
|
||||
binding.likeIv.isChecked = false
|
||||
binding.likeCountTv.setTextColor(R.color.text_B3B3B3.toColor())
|
||||
binding.likeCountTv.setOnClickListener { binding.likeIv.performClick() }
|
||||
binding.likeIv.setOnClickListener {
|
||||
debounceActionWithInterval(binding.likeIv.id, 1000L) {
|
||||
binding.likeClickableView.setOnClickListener {
|
||||
debounceActionWithInterval(binding.likeClickableView.id, 1000L) {
|
||||
binding.likeIv.context.ifLogin("安利墙") {
|
||||
playLikedAnimation(binding.likeCountTv, binding.likeIv, binding.likeAnimView)
|
||||
viewModel.likeAmwayComment(amway.game.id, amway.comment.id)
|
||||
MtaHelper.onEvent("安利墙", "点击", "评论${blockPosition}_${amway.game.name}_点赞")
|
||||
}
|
||||
@ -241,6 +242,19 @@ class AmwayAdapter(context: Context, private var mViewModel: AmwayViewModel, pri
|
||||
DirectUtils.directToBadgeWall(context, amway.comment.user.id, amway.comment.user.name, amway.comment.user.icon)
|
||||
}
|
||||
}
|
||||
|
||||
private fun playLikedAnimation(likeTv: TextView, likeIv: CheckableImageView, likeAnimView: LottieAnimationView) {
|
||||
likeTv.setTextColor(R.color.theme_font.toColor())
|
||||
likeIv.isChecked = true
|
||||
likeIv.visibility = View.INVISIBLE
|
||||
likeAnimView.visibility = View.VISIBLE
|
||||
likeAnimView.setAnimation("lottie/community_vote.json")
|
||||
likeAnimView.playAnimation()
|
||||
likeAnimView.doOnAnimationEnd {
|
||||
likeAnimView.visibility = View.INVISIBLE
|
||||
likeIv.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEventByPosition(pos: Int): ExposureEvent? {
|
||||
|
||||
@ -162,7 +162,7 @@ public abstract class ListActivity<T, VM extends BaseListViewModel /* 该泛型
|
||||
public void onLoadRefresh() {
|
||||
mReuseNoConn.setVisibility(View.GONE);
|
||||
mReuseNoData.setVisibility(View.GONE);
|
||||
mListLoading.setVisibility(View.VISIBLE);
|
||||
mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
|
||||
mListRv.setVisibility(View.GONE);
|
||||
mBaseHandler.postDelayed(() -> {
|
||||
mListViewModel.load(LoadType.REFRESH);
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.gamecenter.baselist;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter;
|
||||
@ -128,7 +129,7 @@ public abstract class ListAdapter<DataType> extends BaseRecyclerAdapter {
|
||||
if (mEntityList != null) mEntityList.clear();
|
||||
mIsNetworkError = false;
|
||||
mIsOver = false;
|
||||
mIsLoading = false;
|
||||
mIsLoading = true;
|
||||
notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ public abstract class ListFragment<T, VM extends BaseListViewModel /* 该泛型
|
||||
showSkeleton(true);
|
||||
mReuseNoConn.setVisibility(View.GONE);
|
||||
mReuseNoData.setVisibility(View.GONE);
|
||||
mListLoading.setVisibility(View.VISIBLE);
|
||||
mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
|
||||
mListRv.setVisibility(View.GONE);
|
||||
mBaseHandler.postDelayed(() -> {
|
||||
mListViewModel.load(LoadType.REFRESH);
|
||||
|
||||
@ -34,4 +34,8 @@ class CategoryDirectoryActivity : NormalActivity() {
|
||||
return "游戏分类"
|
||||
}
|
||||
|
||||
override fun provideNormalIntent(): Intent {
|
||||
return getTargetIntent(this, CategoryDirectoryActivity::class.java, CategoryDirectoryFragment::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
@ -135,15 +135,6 @@ class NewCategoryListFragment : ListFragment<GameEntity, NewCategoryListViewMode
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadRefresh() {
|
||||
mBaseHandler.postDelayed({ mListViewModel.load(LoadType.REFRESH) }, 200)
|
||||
|
||||
mReuseNoConn.visibility = View.GONE
|
||||
mReuseNoData.visibility = View.GONE
|
||||
mListLoading.visibility = View.VISIBLE
|
||||
mListRv.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onRefresh() {
|
||||
mAdapter?.clearPositionAndPackageMap()
|
||||
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
package com.gh.gamecenter.collection;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import kotlin.Pair;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@ -12,22 +8,25 @@ import com.gh.base.OnListClickListener;
|
||||
import com.gh.common.constant.ItemViewType;
|
||||
import com.gh.common.syncpage.ISyncAdapterHandler;
|
||||
import com.gh.common.util.CollectionUtils;
|
||||
import com.gh.common.util.DialogHelper;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder;
|
||||
import com.gh.gamecenter.baselist.ListAdapter;
|
||||
import com.gh.gamecenter.baselist.LoadType;
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding;
|
||||
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder;
|
||||
import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity;
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity;
|
||||
import com.gh.gamecenter.qa.entity.Questions;
|
||||
import com.gh.gamecenter.qa.questions.detail.AnswerViewHolder;
|
||||
import com.gh.gamecenter.baselist.ListAdapter;
|
||||
import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import kotlin.Pair;
|
||||
|
||||
/**
|
||||
* Created by khy on 22/12/17.
|
||||
*/
|
||||
@ -39,14 +38,12 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> implements ISyncAda
|
||||
private AnswerViewModel mListViewModel;
|
||||
|
||||
private String mEntrance;
|
||||
private AnswerFragment.Type mType;
|
||||
|
||||
public AnswerAdapter(Context context, AnswerViewModel viewModel, AnswerFragment.Type type, OnListClickListener listClickListener, String entrance) {
|
||||
public AnswerAdapter(Context context, AnswerViewModel viewModel, OnListClickListener listClickListener, String entrance) {
|
||||
super(context);
|
||||
mListViewModel = viewModel;
|
||||
mListClickListener = listClickListener;
|
||||
mEntrance = entrance;
|
||||
this.mType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,37 +74,45 @@ public class AnswerAdapter extends ListAdapter<AnswerEntity> implements ISyncAda
|
||||
CommunityAnswerItemViewHolder viewHolder = (CommunityAnswerItemViewHolder) holder;
|
||||
AnswerEntity entity = mEntityList.get(position);
|
||||
String path;
|
||||
if (mType == AnswerFragment.Type.COLLECTION) {
|
||||
if (AnswerFragment.COLLECTION.equals(mListViewModel.getType())) {
|
||||
path = "我的收藏-回答列表";
|
||||
} else if (mType == AnswerFragment.Type.HISTORY) {
|
||||
} else if (AnswerFragment.HISTORY.equals(mListViewModel.getType())) {
|
||||
path = "浏览记录-回答列表";
|
||||
viewHolder.itemView.setOnLongClickListener(v -> {
|
||||
DialogHelper.showDialog(holder.itemView.getContext(),
|
||||
"删除记录",
|
||||
"删除浏览记录将不可恢复,确定删除吗?",
|
||||
"确定",
|
||||
"取消",
|
||||
() -> {
|
||||
mListViewModel.removeHistory(entity);
|
||||
},
|
||||
() -> {
|
||||
},
|
||||
false, "", "");
|
||||
return false;
|
||||
});
|
||||
} 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());
|
||||
}
|
||||
holder.itemView.setOnClickListener(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());
|
||||
}
|
||||
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));
|
||||
}
|
||||
viewHolder.getBinding().title.setOnClickListener(v -> {
|
||||
Questions questions = entity.getQuestions();
|
||||
mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.getId(), mEntrance, path));
|
||||
});
|
||||
break;
|
||||
case ItemViewType.ITEM_FOOTER:
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package com.gh.gamecenter.collection;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.common.util.CollectionUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.baselist.ListAdapter;
|
||||
import com.gh.gamecenter.baselist.ListFragment;
|
||||
@ -24,35 +26,26 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
public class AnswerFragment extends ListFragment<AnswerEntity, AnswerViewModel> {
|
||||
|
||||
private AnswerAdapter mAdapter;
|
||||
private Type mType;
|
||||
private String mType;
|
||||
|
||||
public static AnswerFragment getInstance(Type type) {
|
||||
AnswerFragment fragment = new AnswerFragment();
|
||||
fragment.mType = type;
|
||||
return fragment;
|
||||
}
|
||||
public static String COLLECTION = "collection";
|
||||
public static String COLLECTION_ANSWER = "collection_answer";
|
||||
public static String HISTORY = "history";
|
||||
|
||||
@Override
|
||||
protected ListAdapter provideListAdapter() {
|
||||
return mAdapter == null ? mAdapter = new AnswerAdapter(getContext(), mListViewModel, mType, this, mEntrance) : mAdapter;
|
||||
return mAdapter == null ? mAdapter = new AnswerAdapter(getContext(), mListViewModel, this, mEntrance) : mAdapter;
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public Single<List<AnswerEntity>> provideDataSingle(int page) {
|
||||
if (mType == Type.COLLECTION) {
|
||||
return Single.fromObservable(RetrofitManager.getInstance(getContext()).getApi().getCollectionAnswer(UserManager.getInstance().getUserId(), page));
|
||||
} else {
|
||||
return HistoryDatabase.Companion.getInstance().answerDao().getAnswersWithOffset(20, (page - 1) * 20);
|
||||
}
|
||||
}*/
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
mType = getArguments().getString(EntranceUtils.KEY_TYPE, COLLECTION);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
@ -74,14 +67,6 @@ public class AnswerFragment extends ListFragment<AnswerEntity, AnswerViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
COLLECTION,
|
||||
|
||||
COLLECTION_ANSWER,
|
||||
|
||||
HISTORY
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean addSyncPageObserver() {
|
||||
return true;
|
||||
|
||||
@ -2,8 +2,11 @@ package com.gh.gamecenter.collection
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.gamecenter.baselist.ListViewModel
|
||||
import com.gh.gamecenter.baselist.LoadType
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
@ -18,14 +21,14 @@ class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, An
|
||||
|
||||
private var mApi = RetrofitManager.getInstance(getApplication()).api
|
||||
|
||||
var type: AnswerFragment.Type = AnswerFragment.Type.COLLECTION
|
||||
var type: String = AnswerFragment.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) {
|
||||
return if (type == AnswerFragment.COLLECTION) {
|
||||
Single.fromObservable(mApi.getCollectionAnswer(UserManager.getInstance().userId, page))
|
||||
} else {
|
||||
if (page > 5) {
|
||||
@ -33,7 +36,6 @@ class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, An
|
||||
} else {
|
||||
HistoryDatabase.instance.answerDao().getAnswersWithOffset(20, (page - 1) * 20)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,4 +54,17 @@ class AnswerViewModel(application: Application) : ListViewModel<AnswerEntity, An
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun removeHistory(answerEntity: AnswerEntity) {
|
||||
mResultLiveData.value?.let {
|
||||
HistoryHelper.deleteAnswerEntity(answerEntity.id!!)
|
||||
it.remove(answerEntity)
|
||||
|
||||
if (it.size == 0) {
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
|
||||
} else {
|
||||
mResultLiveData.postValue(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,6 @@ package com.gh.gamecenter.collection;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Paint;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
@ -13,6 +11,7 @@ import android.widget.LinearLayout;
|
||||
|
||||
import com.gh.base.OnListClickListener;
|
||||
import com.gh.common.constant.ItemViewType;
|
||||
import com.gh.common.util.DialogHelper;
|
||||
import com.gh.common.util.DisplayUtils;
|
||||
import com.gh.common.util.ImageUtils;
|
||||
import com.gh.common.util.NewsUtils;
|
||||
@ -33,6 +32,8 @@ import org.json.JSONObject;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
@ -43,9 +44,11 @@ import io.reactivex.schedulers.Schedulers;
|
||||
public class ArticleAdapter extends ListAdapter<NewsEntity> {
|
||||
|
||||
private OnListClickListener mListListener;
|
||||
private ArticleViewModel mViewModel;
|
||||
|
||||
public ArticleAdapter(Context context, OnListClickListener listListener) {
|
||||
public ArticleAdapter(Context context, ArticleViewModel viewModel, OnListClickListener listListener) {
|
||||
super(context);
|
||||
mViewModel = viewModel;
|
||||
mListListener = listListener;
|
||||
}
|
||||
|
||||
@ -103,12 +106,15 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
|
||||
switch (getItemViewType(position)) {
|
||||
case ItemViewType.NEWS_IMAGE1:
|
||||
initNewsImage1ViewHolder((NewsImage1ViewHolder) holder, position);
|
||||
addLongClickListenerIfNeed(holder, mEntityList.get(position));
|
||||
break;
|
||||
case ItemViewType.NEWS_IMAGE2:
|
||||
initNewsImage2ViewHolder((NewsImage2ViewHolder) holder, position);
|
||||
addLongClickListenerIfNeed(holder, mEntityList.get(position));
|
||||
break;
|
||||
case ItemViewType.NEWS_IMAGE3:
|
||||
initNewsImage3ViewHolder((NewsImage3ViewHolder) holder, position);
|
||||
addLongClickListenerIfNeed(holder, mEntityList.get(position));
|
||||
break;
|
||||
case ItemViewType.LOADING:
|
||||
FooterViewHolder footerViewHolder = (FooterViewHolder) holder;
|
||||
@ -118,6 +124,24 @@ public class ArticleAdapter extends ListAdapter<NewsEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
private void addLongClickListenerIfNeed(RecyclerView.ViewHolder holder, NewsEntity newsEntity) {
|
||||
if (ArticleFragment.HISTORY.equals(mViewModel.type)) {
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
DialogHelper.showDialog(holder.itemView.getContext(),
|
||||
"删除记录",
|
||||
"删除浏览记录将不可恢复,确定删除吗?",
|
||||
"确定",
|
||||
"取消",
|
||||
() -> {
|
||||
mViewModel.removeHistory(newsEntity);
|
||||
},
|
||||
() -> {
|
||||
},
|
||||
false, "", "");
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package com.gh.gamecenter.collection;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import com.gh.common.util.CollectionUtils;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
import com.gh.common.util.EntranceUtils;
|
||||
import com.gh.gamecenter.NewsDetailActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.baselist.ListAdapter;
|
||||
@ -16,31 +18,39 @@ import com.gh.gamecenter.eventbus.EBCollectionChanged;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by khy on 18/07/17.
|
||||
*/
|
||||
|
||||
public class ArticleFragment extends ListFragment<NewsEntity, ArticleViewModel> {
|
||||
|
||||
private Type mType;
|
||||
private String mType;
|
||||
private ArticleAdapter mAdapter;
|
||||
private ArticleViewModel mViewModel;
|
||||
|
||||
public static ArticleFragment getInstance(Type type) {
|
||||
ArticleFragment fragment = new ArticleFragment();
|
||||
fragment.mType = type;
|
||||
return fragment;
|
||||
}
|
||||
public static String COLLECTION = "collection";
|
||||
public static String HISTORY = "history";
|
||||
|
||||
@Override
|
||||
protected ArticleViewModel provideListViewModel() {
|
||||
ArticleViewModel viewModel = super.provideListViewModel();
|
||||
viewModel.type = mType;
|
||||
return viewModel;
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
mType = getArguments().getString(EntranceUtils.KEY_TYPE, COLLECTION);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListAdapter provideListAdapter() {
|
||||
return mAdapter == null ? mAdapter = new ArticleAdapter(getContext(), this) : mAdapter;
|
||||
return mAdapter == null ? mAdapter = new ArticleAdapter(getContext(), mViewModel,this) : mAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArticleViewModel provideListViewModel() {
|
||||
if (mViewModel == null) {
|
||||
mViewModel = super.provideListViewModel();
|
||||
}
|
||||
mViewModel.type = mType;
|
||||
return mViewModel;
|
||||
}
|
||||
|
||||
// 收藏事件
|
||||
@ -55,7 +65,7 @@ public class ArticleFragment extends ListFragment<NewsEntity, ArticleViewModel>
|
||||
public void onListClick(View view, int position, Object data) {
|
||||
NewsEntity newsEntity = (NewsEntity) data;
|
||||
|
||||
if (mType == Type.COLLECTION) {
|
||||
if (COLLECTION.equals(mType)) {
|
||||
if (!newsEntity.getActive()) {
|
||||
showDeleteDialog(newsEntity.getId());
|
||||
return;
|
||||
@ -89,10 +99,4 @@ public class ArticleFragment extends ListFragment<NewsEntity, ArticleViewModel>
|
||||
}
|
||||
}), null);
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
COLLECTION,
|
||||
|
||||
HISTORY
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,12 @@ package com.gh.gamecenter.collection;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.history.HistoryDatabase;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.util.UrlFilterUtils;
|
||||
import com.gh.gamecenter.baselist.ListViewModel;
|
||||
import com.gh.gamecenter.baselist.LoadType;
|
||||
import com.gh.gamecenter.entity.NewsEntity;
|
||||
import com.gh.gamecenter.entity.ViewsEntity;
|
||||
import com.gh.gamecenter.info.NewsViewsRepository;
|
||||
@ -25,7 +28,7 @@ import io.reactivex.Single;
|
||||
|
||||
public class ArticleViewModel extends ListViewModel<NewsEntity, NewsEntity> {
|
||||
|
||||
public ArticleFragment.Type type;
|
||||
public String type;
|
||||
|
||||
NewsViewsRepository<ViewsEntity> mNewsViewsRepository = new NewsViewsRepository<>();
|
||||
|
||||
@ -76,7 +79,7 @@ public class ArticleViewModel extends ListViewModel<NewsEntity, NewsEntity> {
|
||||
|
||||
@Override
|
||||
public Single<List<NewsEntity>> provideDataSingle(int page) {
|
||||
if (type == ArticleFragment.Type.COLLECTION) {
|
||||
if (ArticleFragment.COLLECTION.equals(type)) {
|
||||
return Single.fromObservable(RetrofitManager.getInstance(getApplication()).getApi().getCollectionArticle(UserManager.getInstance().getUserId(), page));
|
||||
} else {
|
||||
if (page > 5) {
|
||||
@ -90,4 +93,20 @@ public class ArticleViewModel extends ListViewModel<NewsEntity, NewsEntity> {
|
||||
public Observable<List<NewsEntity>> provideDataObservable(int page) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeHistory(NewsEntity newsEntity) {
|
||||
List<NewsEntity> originList = mResultLiveData.getValue();
|
||||
if (originList != null) {
|
||||
HistoryHelper.deleteNewsEntity(newsEntity.getId());
|
||||
|
||||
originList.remove(newsEntity);
|
||||
if (originList.size() == 0) {
|
||||
AppExecutor.getUiExecutor().executeWithDelay(() -> {
|
||||
load(LoadType.REFRESH);
|
||||
}, 100);
|
||||
} else {
|
||||
mResultLiveData.postValue(originList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,10 +40,10 @@ public class CollectionWrapperFragment extends BaseFragment_TabLayout {
|
||||
|
||||
@Override
|
||||
protected void initFragmentList(List<Fragment> fragments) {
|
||||
fragments.add(AnswerFragment.getInstance(AnswerFragment.Type.COLLECTION).with(getArguments()));
|
||||
fragments.add(CommunityArticleFragment.getInstance(CommunityArticleFragment.Type.COLLECTION).with(getArguments()));
|
||||
fragments.add(new AnswerFragment().with(getArguments()));
|
||||
fragments.add(new CommunityArticleFragment().with(getArguments()));
|
||||
fragments.add(new ToolsFragment().with(getArguments()));
|
||||
fragments.add(ArticleFragment.getInstance(ArticleFragment.Type.COLLECTION).with(getArguments()));
|
||||
fragments.add(new ArticleFragment().with(getArguments()));
|
||||
|
||||
Bundle arguments = getArguments();
|
||||
if (arguments != null)
|
||||
|
||||
@ -6,18 +6,18 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.constant.ItemViewType
|
||||
import com.gh.common.syncpage.ISyncAdapterHandler
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DialogHelper
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.consume
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.baselist.ListAdapter
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
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), ISyncAdapterHandler {
|
||||
|
||||
@ -46,13 +46,29 @@ class CommunityArticleAdapter(context: Context,
|
||||
|
||||
override fun getItemCount(): Int = if (mEntityList.size == 0) 0 else mEntityList.size + 1
|
||||
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is CommunityAnswerItemViewHolder) {
|
||||
val path = if (mType == CommunityArticleFragment.Type.COLLECTION) "我的收藏-文章列表" else "浏览记录-文章列表"
|
||||
var path = ""
|
||||
val entity = mEntityList[position]
|
||||
holder.bindArticleItem(entity, mEntrance, path)
|
||||
|
||||
if (mViewModel.type == CommunityArticleFragment.Type.COLLECTION.value) {
|
||||
path = "我的收藏-文章列表"
|
||||
} else {
|
||||
path = "浏览记录-文章列表"
|
||||
holder.itemView.setOnLongClickListener {
|
||||
consume {
|
||||
DialogHelper.showDialog(holder.binding.root.context,
|
||||
"删除记录",
|
||||
"删除浏览记录将不可恢复,确定删除吗?",
|
||||
"确定",
|
||||
"取消", {
|
||||
mViewModel.removeHistory(entity)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
holder.bindArticleItem(entity, mEntrance, path)
|
||||
holder.itemView.setOnClickListener {
|
||||
if (entity.active) {
|
||||
mContext.startActivity(ArticleDetailActivity.getIntent(mContext, entity.community, entity.id, mEntrance, path))
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package com.gh.gamecenter.collection
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.CollectionUtils
|
||||
import com.gh.common.util.EntranceUtils
|
||||
import com.gh.gamecenter.baselist.ListFragment
|
||||
import com.gh.gamecenter.baselist.LoadType
|
||||
import com.gh.gamecenter.eventbus.EBCollectionChanged
|
||||
@ -12,25 +14,35 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class CommunityArticleFragment : ListFragment<ArticleEntity, CommunityArticleViewModel>() {
|
||||
|
||||
private var mType = Type.COLLECTION
|
||||
private var mType = Type.COLLECTION.value
|
||||
private var mViewModel: CommunityArticleViewModel? = null
|
||||
private var mAdapter: CommunityArticleAdapter? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
mType = arguments?.getString(EntranceUtils.KEY_TYPE, Type.COLLECTION.value) ?: Type.COLLECTION.value
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun provideListAdapter(): CommunityArticleAdapter {
|
||||
if (mAdapter == null) {
|
||||
mAdapter = CommunityArticleAdapter(requireContext(), mType, mListViewModel, mEntrance)
|
||||
mAdapter = CommunityArticleAdapter(requireContext(), mViewModel!!, mEntrance)
|
||||
}
|
||||
return mAdapter!!
|
||||
}
|
||||
|
||||
override fun provideListViewModel(): CommunityArticleViewModel {
|
||||
return ViewModelProviders.of(this).get(CommunityArticleViewModel::class.java).apply { type = mType }
|
||||
if (mViewModel == null) {
|
||||
mViewModel = ViewModelProviders.of(this).get(CommunityArticleViewModel::class.java).apply { type = mType }
|
||||
}
|
||||
|
||||
return mViewModel!!
|
||||
}
|
||||
|
||||
// 收藏事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBCollectionChanged) {
|
||||
if (changed.collectionType == CollectionUtils.CollectionType.communityArticle
|
||||
&& mType == Type.COLLECTION) {
|
||||
&& mType == Type.COLLECTION.value) {
|
||||
mListViewModel.load(LoadType.REFRESH)
|
||||
}
|
||||
}
|
||||
@ -43,18 +55,9 @@ class CommunityArticleFragment : ListFragment<ArticleEntity, CommunityArticleVie
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(type: Type): CommunityArticleFragment {
|
||||
val fragment = CommunityArticleFragment()
|
||||
fragment.mType = type
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
enum class Type(val value: String) {
|
||||
COLLECTION("collection"),
|
||||
|
||||
enum class Type {
|
||||
COLLECTION,
|
||||
|
||||
HISTORY
|
||||
HISTORY("history")
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,12 @@ package com.gh.gamecenter.collection
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.baselist.ListViewModel
|
||||
import com.gh.gamecenter.baselist.LoadType
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.qa.entity.ArticleEntity
|
||||
import com.gh.gamecenter.retrofit.BiResponse
|
||||
@ -21,14 +24,14 @@ import retrofit2.HttpException
|
||||
|
||||
class CommunityArticleViewModel(application: Application) : ListViewModel<ArticleEntity, ArticleEntity>(application) {
|
||||
|
||||
var type: CommunityArticleFragment.Type = CommunityArticleFragment.Type.COLLECTION
|
||||
var type: String = CommunityArticleFragment.Type.COLLECTION.value
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<ArticleEntity>>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun provideDataSingle(page: Int): Single<List<ArticleEntity>> {
|
||||
return if (type == CommunityArticleFragment.Type.COLLECTION) {
|
||||
return if (type == CommunityArticleFragment.Type.COLLECTION.value) {
|
||||
Single.fromObservable(RetrofitManager.getInstance(getApplication()).api.getCollectionCommunityArticle(UserManager.getInstance().userId, page))
|
||||
} else {
|
||||
if (page > 5) {
|
||||
@ -43,6 +46,18 @@ class CommunityArticleViewModel(application: Application) : ListViewModel<Articl
|
||||
mResultLiveData.addSource<List<ArticleEntity>>(mListLiveData) { mResultLiveData.postValue(it) }
|
||||
}
|
||||
|
||||
fun removeHistory(articleEntity: ArticleEntity) {
|
||||
mResultLiveData.value?.let {
|
||||
HistoryHelper.deleteArticleEntity(articleEntity.id)
|
||||
|
||||
it.remove(articleEntity)
|
||||
if (it.size == 0) {
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
|
||||
} else {
|
||||
mResultLiveData.postValue(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCollection(communityId: String, articleId: String) {
|
||||
RetrofitManager.getInstance(getApplication()).api
|
||||
|
||||
@ -5,20 +5,17 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.constant.ItemViewType
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.toSimpleCount
|
||||
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.baselist.NormalListViewModel
|
||||
import com.gh.gamecenter.databinding.VideoItemBinding
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.video.VideoItemViewHolder
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
|
||||
class VideoAdapter(context: Context,
|
||||
val mViewModel: NormalListViewModel<MyVideoEntity>, val mVideoStyle: String) : ListAdapter<MyVideoEntity>(context) {
|
||||
val mViewModel: VideoViewModel, val mVideoStyle: String) : ListAdapter<MyVideoEntity>(context) {
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER
|
||||
return ItemViewType.ITEM_BODY
|
||||
@ -55,6 +52,18 @@ class VideoAdapter(context: Context,
|
||||
DirectUtils.directToVideoDetail(mContext, entity.id, VideoDetailContainerViewModel.Location.VIDEO_HOT.value, false, path = getPath())
|
||||
}
|
||||
}
|
||||
|
||||
holder.itemView.setOnLongClickListener {
|
||||
consume {
|
||||
DialogHelper.showDialog(holder.binding.root.context,
|
||||
"删除记录",
|
||||
"删除浏览记录将不可恢复,确定删除吗?",
|
||||
"确定",
|
||||
"取消", {
|
||||
mViewModel.removeHistory(entity)
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (holder is FooterViewHolder) {
|
||||
holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
|
||||
}
|
||||
|
||||
@ -2,30 +2,22 @@ package com.gh.gamecenter.collection
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.viewModelProvider
|
||||
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
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
class VideoFragment : ListFragment<MyVideoEntity, NormalListViewModel<MyVideoEntity>>() {
|
||||
class VideoFragment : ListFragment<MyVideoEntity, VideoViewModel>() {
|
||||
private var mAdapter: VideoAdapter? = null
|
||||
private var mViewModel: VideoViewModel? = null
|
||||
private lateinit var mVideoStyle: String
|
||||
|
||||
override fun provideListAdapter(): VideoAdapter {
|
||||
if (mAdapter == null) {
|
||||
mAdapter = VideoAdapter(context!!, mListViewModel, mVideoStyle)
|
||||
mAdapter = VideoAdapter(requireContext(), mViewModel!!, mVideoStyle)
|
||||
}
|
||||
return mAdapter!!
|
||||
}
|
||||
@ -54,27 +46,12 @@ class VideoFragment : ListFragment<MyVideoEntity, NormalListViewModel<MyVideoEnt
|
||||
mListRv.layoutManager = gridLayoutManager
|
||||
}
|
||||
|
||||
override fun provideListViewModel(): NormalListViewModel<MyVideoEntity> {
|
||||
val factory = NormalListViewModel.Factory(HaloApp.getInstance().application, this)
|
||||
return ViewModelProviders.of(this, factory).get(NormalListViewModel::class.java) as NormalListViewModel<MyVideoEntity>
|
||||
}
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<MyVideoEntity>>? {
|
||||
if (mVideoStyle == VideoStyle.COLLECT.value) {
|
||||
return RetrofitManager.getInstance(context).api.getCollectionVideo(UserManager.getInstance().userId, page, Config.VIDEO_PAGE_SIZE)
|
||||
override fun provideListViewModel(): VideoViewModel {
|
||||
if (mViewModel == null) {
|
||||
mViewModel = viewModelProvider()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
return null
|
||||
mViewModel?.type = mVideoStyle
|
||||
return mViewModel!!
|
||||
}
|
||||
|
||||
enum class VideoStyle(val value: String) {
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
package com.gh.gamecenter.collection
|
||||
|
||||
import android.app.Application
|
||||
import com.gh.common.AppExecutor
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.history.HistoryDatabase
|
||||
import com.gh.common.history.HistoryHelper
|
||||
import com.gh.gamecenter.baselist.ListViewModel
|
||||
import com.gh.gamecenter.baselist.LoadType
|
||||
import com.gh.gamecenter.entity.MyVideoEntity
|
||||
import com.gh.gamecenter.manager.UserManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
class VideoViewModel(application: Application) : ListViewModel<MyVideoEntity, MyVideoEntity>(application) {
|
||||
|
||||
var type = ""
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<MyVideoEntity>>? {
|
||||
if (type == VideoFragment.VideoStyle.COLLECT.value) {
|
||||
return RetrofitManager.getInstance(getApplication()).api.getCollectionVideo(UserManager.getInstance().userId, page, Config.VIDEO_PAGE_SIZE)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun provideDataSingle(page: Int): Single<MutableList<MyVideoEntity>>? {
|
||||
if (page > 5) {
|
||||
return Single.create { it.onSuccess(arrayListOf()) }
|
||||
}
|
||||
if (type == VideoFragment.VideoStyle.BROWSING_HISTORY.value) {
|
||||
return HistoryDatabase.instance.videoHistoryDao().getVideoWithOffset(20, (page - 1) * 20)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
|
||||
}
|
||||
|
||||
fun removeHistory(myVideoEntity: MyVideoEntity) {
|
||||
HistoryHelper.deleteVideoEntity(myVideoEntity.id)
|
||||
AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,6 +11,7 @@ import androidx.fragment.app.Fragment
|
||||
import com.gh.base.fragment.BaseFragment_TabLayout
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.visibleIf
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.DownloadManagerActivity
|
||||
import com.gh.gamecenter.R
|
||||
@ -33,8 +34,19 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
const val INDEX_UPDATE = 1
|
||||
}
|
||||
|
||||
lateinit var mDownloadNumber: TextView
|
||||
lateinit var mUpdateNumber: TextView
|
||||
// 下载 tab 是否被手动选中过
|
||||
private var mIsDownloadTabHasBeenSelected: Boolean = false
|
||||
private var mIsUpdateTabHasBeenSelected: Boolean = false
|
||||
|
||||
private lateinit var mDownloadNumber: TextView
|
||||
private lateinit var mUpdateNumber: TextView
|
||||
private lateinit var mDownloadManager: DownloadManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mDownloadManager = DownloadManager.getInstance(HaloApp.getInstance().application)
|
||||
}
|
||||
|
||||
override fun initFragmentList(fragments: MutableList<Fragment>) {
|
||||
fragments.add(GameDownloadFragment())
|
||||
@ -67,14 +79,17 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setUpdateHint()
|
||||
setDownloadHint()
|
||||
updateUpdateHint()
|
||||
updateDownloadHint()
|
||||
|
||||
if (mDownloadNumber.visibility != View.VISIBLE) {
|
||||
if (mDownloadNumber.visibility != View.VISIBLE && mUpdateNumber.visibility == View.VISIBLE) {
|
||||
mViewPager.currentItem = INDEX_UPDATE
|
||||
} else {
|
||||
// 进入并选中下载管理时立马标记已下载待安装为已读
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).markDownloadedTaskAsRead()
|
||||
mIsDownloadTabHasBeenSelected = true
|
||||
updateDownloadHint()
|
||||
mDownloadManager.markDownloadingTaskAsRead()
|
||||
mDownloadManager.markDownloadedTaskAsRead()
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,11 +99,14 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
DownloadManager.getInstance(requireContext()).checkRetryDownload()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
override fun onParentActivityFinish() {
|
||||
super.onParentActivityFinish()
|
||||
|
||||
// onDestory 的回调有点晚,不能及时更新外部红点
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).markDownloadedTaskAsRead()
|
||||
// onDestroy 的回调有点晚,不能及时更新外部红点
|
||||
if (mIsDownloadTabHasBeenSelected || mViewPager.currentItem == INDEX_DOWNLOAD) {
|
||||
mDownloadManager.markDownloadingTaskAsRead()
|
||||
mDownloadManager.markDownloadedTaskAsRead()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageSelected(index: Int) {
|
||||
@ -101,7 +119,13 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
}
|
||||
|
||||
if (index == INDEX_UPDATE) {
|
||||
DownloadManager.getInstance(HaloApp.getInstance().application).markUpdatableTaskAsRead()
|
||||
mIsUpdateTabHasBeenSelected = true
|
||||
updateUpdateHint()
|
||||
mDownloadManager.markUpdatableTaskAsRead()
|
||||
} else if (index == INDEX_DOWNLOAD) {
|
||||
mIsDownloadTabHasBeenSelected = true
|
||||
updateDownloadHint()
|
||||
mDownloadManager.markDownloadingTaskAsRead()
|
||||
}
|
||||
|
||||
MtaHelper.onEvent("下载管理", "Tab", tabName)
|
||||
@ -117,13 +141,13 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBDownloadChanged) {
|
||||
if ("download" == changed.type) {
|
||||
setDownloadHint()
|
||||
updateDownloadHint()
|
||||
} else if ("update" == changed.type) {
|
||||
setUpdateHint()
|
||||
updateUpdateHint()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDownloadHint() {
|
||||
private fun updateDownloadHint() {
|
||||
val downloadData = DownloadManager.getInstance(context).all
|
||||
if (downloadData.size > 0) {
|
||||
mDownloadNumber.visibility = View.VISIBLE
|
||||
@ -140,31 +164,35 @@ class DownloadFragment : BaseFragment_TabLayout() {
|
||||
}
|
||||
|
||||
val layoutParams = mDownloadNumber.layoutParams as LinearLayout.LayoutParams
|
||||
if (downloadingCount > 0) {
|
||||
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.setMargins(4F.dip2px(), 0, 0, 0F.dip2px())
|
||||
mDownloadNumber.setBackgroundColor(Color.TRANSPARENT)
|
||||
mDownloadNumber.text = downloadingCount.toString()
|
||||
} else {
|
||||
layoutParams.width = 6F.dip2px()
|
||||
layoutParams.height = 6F.dip2px()
|
||||
layoutParams.setMargins(2F.dip2px(), 0, 0, 3F.dip2px())
|
||||
mDownloadNumber.setBackgroundResource(R.drawable.oval_hint_red_bg)
|
||||
mDownloadNumber.text = ""
|
||||
when {
|
||||
downloadingCount > 0 -> {
|
||||
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.setMargins(4F.dip2px(), 0, 0, 0F.dip2px())
|
||||
mDownloadNumber.setBackgroundColor(Color.TRANSPARENT)
|
||||
mDownloadNumber.text = downloadingCount.toString()
|
||||
}
|
||||
mDownloadManager.isContainsUnreadDownloadedTask -> {
|
||||
layoutParams.width = 6F.dip2px()
|
||||
layoutParams.height = 6F.dip2px()
|
||||
layoutParams.setMargins(2F.dip2px(), 0, 0, 3F.dip2px())
|
||||
mDownloadNumber.setBackgroundResource(R.drawable.oval_hint_red_bg)
|
||||
mDownloadNumber.text = ""
|
||||
}
|
||||
else -> mDownloadNumber.visibility = View.GONE
|
||||
}
|
||||
mDownloadNumber.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
private fun setUpdateHint() {
|
||||
var updateSize = 0
|
||||
for (updateEntity in PackagesManager.getUpdateList()) {
|
||||
if (updateEntity.isShowPlugin(PluginLocation.only_index)) updateSize++
|
||||
private fun updateUpdateHint() {
|
||||
if (mIsUpdateTabHasBeenSelected) {
|
||||
mUpdateNumber.visibility = View.INVISIBLE
|
||||
return
|
||||
}
|
||||
|
||||
mUpdateNumber.visibility = if (updateSize != 0) {
|
||||
View.VISIBLE
|
||||
} else View.INVISIBLE
|
||||
val updateCount = mDownloadManager.getUnreadUpdateCount(PackagesManager.getUpdateList().filter { it.isShowPlugin(PluginLocation.only_index) })
|
||||
|
||||
mUpdateNumber.visibleIf(updateCount != 0)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
||||
@ -12,11 +12,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.gh.common.util.BitmapUtils;
|
||||
import com.gh.common.util.DataUtils;
|
||||
import com.gh.common.util.DialogUtils;
|
||||
@ -50,6 +45,10 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
/**
|
||||
* Created by LGT on 2016/8/15.
|
||||
@ -155,6 +154,11 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
downloadTitle = downloadEntity.getName() + " - " + platform;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(downloadEntity.getVersionName())) {
|
||||
downloadTitle = downloadTitle + " - V" + downloadEntity.getVersionName();
|
||||
}
|
||||
|
||||
if (!viewHolder.dmTitle.getText().equals(downloadTitle)) {
|
||||
viewHolder.dmTitle.setText(downloadTitle);
|
||||
}
|
||||
|
||||
@ -8,17 +8,13 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.gh.common.AppExecutor;
|
||||
import com.gh.common.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureSource;
|
||||
import com.gh.common.exposure.ExposureType;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.exposure.IExposable;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.util.ApkActiveUtils;
|
||||
import com.gh.common.util.DataCollectionUtils;
|
||||
import com.gh.common.util.DataUtils;
|
||||
@ -65,6 +61,10 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
@ -128,7 +128,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
|
||||
.subscribe(new Response<GameEntity>() {
|
||||
@Override
|
||||
public void onResponse(GameEntity response) {
|
||||
List<GameUpdateEntity> update = PackageUtils.getUpdateData(mContext, response);
|
||||
List<GameUpdateEntity> update = PackageUtils.getUpdateData(response);
|
||||
if (update.size() > 0) {
|
||||
updateList.addAll(update);
|
||||
// PackagesManager.INSTANCE.addUpdateList(update);
|
||||
@ -351,7 +351,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
|
||||
DialogUtils.checkDownload(mContext, updateEntity.getSize(), isSubscribe -> {
|
||||
if (str.contains("化")) {
|
||||
if (updateEntity.getPluggableCollection() != null) {
|
||||
DownloadDialog.showDownloadDialog(mContext, updateEntity.transformGameEntity(), entrance, finalPluginDesc + "化:" + updateEntity.getName());
|
||||
DownloadDialog.showDownloadDialog(mContext, updateEntity.transformGameEntity(), updateEntity.getExposureEvent(), entrance, finalPluginDesc + "化:" + updateEntity.getName());
|
||||
return;
|
||||
} else {
|
||||
viewHolder.guUpdate.setText(R.string.downloading);
|
||||
@ -549,6 +549,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter<ViewHolder> implemen
|
||||
if (isSubscribe) {
|
||||
DownloadManager.getInstance(mContext).subscribe(downloadEntity);
|
||||
} else {
|
||||
HistoryHelper.insertGameEntity(updateEntity);
|
||||
DownloadManager.getInstance(mContext).add(downloadEntity);
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ data class AmwayCommentEntity(
|
||||
var id: String,
|
||||
var icon: String,
|
||||
var name: String,
|
||||
@SerializedName(value="tag", alternate=["tag_style"])
|
||||
@SerializedName(value="new_tag_style")
|
||||
var tag: List<TagStyleEntity>? = arrayListOf(),
|
||||
var star: Float) : Parcelable {
|
||||
fun toGameEntity() : GameEntity {
|
||||
|
||||
10
app/src/main/java/com/gh/gamecenter/entity/CommentDraft.kt
Normal file
10
app/src/main/java/com/gh/gamecenter/entity/CommentDraft.kt
Normal file
@ -0,0 +1,10 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity
|
||||
class CommentDraft(
|
||||
@PrimaryKey
|
||||
var id: String,
|
||||
var draft: String)
|
||||
@ -19,7 +19,7 @@ data class GameInstall(
|
||||
fun transformGameInstall(game: GameEntity, installedPkgName: String): GameInstall {
|
||||
val gameInstall = GameInstall()
|
||||
val application = HaloApp.getInstance().application
|
||||
gameInstall.isSignature = PackageUtils.isSignature(application, installedPkgName)
|
||||
gameInstall.isSignature = PackageUtils.isSignedByGh(application, installedPkgName)
|
||||
gameInstall.installTime = PackageUtils.getInstalledTime(application, installedPkgName)
|
||||
gameInstall.id = game.id
|
||||
gameInstall.name = game.name
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.gh.common.annotation.SyncPage
|
||||
import com.gh.common.syncpage.SyncFieldConstants
|
||||
import com.gh.gamecenter.qa.entity.AnswerEntity
|
||||
import com.gh.gamecenter.qa.entity.CommunityVideoEntity
|
||||
import com.gh.gamecenter.qa.entity.Questions
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@ -15,13 +19,15 @@ data class PersonalHistoryEntity(
|
||||
var count: Count = Count(),
|
||||
val time: Long = 0,
|
||||
var title: String = "",
|
||||
var description: 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(),
|
||||
var comment: Comment = Comment()) :Parcelable{
|
||||
val me: MeEntity = MeEntity(),
|
||||
var comment: Comment = Comment()) : Parcelable {
|
||||
|
||||
fun getPassVideos(): List<CommunityVideoEntity> {
|
||||
val passVideos = arrayListOf<CommunityVideoEntity>()
|
||||
@ -36,20 +42,25 @@ data class PersonalHistoryEntity(
|
||||
data class Question(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
var title: String = ""):Parcelable
|
||||
var title: String = "") : Parcelable
|
||||
|
||||
@Parcelize
|
||||
data class Count(
|
||||
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_COMMENT_COUNT, SyncFieldConstants.ARTICLE_COMMENT_COUNT])
|
||||
var comment: Int = -1,
|
||||
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_VOTE_COUNT, SyncFieldConstants.ARTICLE_VOTE_COUNT])
|
||||
var vote: Int = -1,
|
||||
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_COUNT])
|
||||
var answer: Int = -1,
|
||||
var reply: Int = -1):Parcelable
|
||||
var reply: Int = -1) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
data class Comment(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
var star: Int = 0,
|
||||
var content: String = "",
|
||||
val game: Game = Game()):Parcelable
|
||||
val game: Game = Game()) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
data class Game(
|
||||
@ -60,11 +71,41 @@ data class PersonalHistoryEntity(
|
||||
val nameSuffix: String = "",
|
||||
|
||||
val icon: String = "",
|
||||
@SerializedName(value = "tag", alternate = ["tag_style"])
|
||||
@SerializedName(value = "new_tag_style")
|
||||
val tag: ArrayList<TagStyleEntity> = ArrayList(),
|
||||
val star: Float = 0F,
|
||||
@SerializedName("libao_exists")
|
||||
var isLibaoExists: Boolean = false,
|
||||
val active: Boolean = true//游戏是否被隐藏 false被隐藏
|
||||
) : Parcelable
|
||||
|
||||
|
||||
// 因为内容是文章和回答混合的,所以返回的有可能是文章的实体
|
||||
fun transformAnswerEntity(): AnswerEntity {
|
||||
val question = Questions(title = title)
|
||||
val answer = AnswerEntity()
|
||||
answer.id = id
|
||||
answer.questions = question
|
||||
answer.brief = brief
|
||||
answer.images = images
|
||||
answer.videos = videos
|
||||
answer.time = time
|
||||
answer.vote = count.vote
|
||||
answer.commentCount = count.comment
|
||||
answer.me = me
|
||||
if (type.contains("article")) {
|
||||
answer.type = "community_article"
|
||||
}
|
||||
return answer
|
||||
}
|
||||
|
||||
fun transformQuestionEntity(): Questions {
|
||||
val question = Questions(title = title)
|
||||
question.answerCount = count.answer
|
||||
question.me = me
|
||||
question.id = id
|
||||
question.images = images as ArrayList<String>
|
||||
question.communityName = community.name
|
||||
return question
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ class GameFragment : NormalFragment() {
|
||||
mBinding.loadStatus = it
|
||||
mListAdapter.setLoadStatus(it)
|
||||
mNoConn.visibility = if (it == LoadStatus.INIT_FAILED) View.VISIBLE else View.GONE
|
||||
mLoading.visibility = if (it == LoadStatus.INIT_LOADING) View.VISIBLE else View.GONE
|
||||
mLoading.visibility = if (it == LoadStatus.INIT_LOADING && !mBinding.gameRefresh.isRefreshing) View.VISIBLE else View.GONE
|
||||
if (it != LoadStatus.INIT_LOADING) {
|
||||
mSkeleton.hide()
|
||||
} else {
|
||||
|
||||
@ -370,6 +370,7 @@ class GameFragmentAdapter(context: Context,
|
||||
entity.type == EntranceUtils.HOST_COMMUNITY -> DirectUtils.directToCommunity(mContext, CommunityEntity(entity.link!!, entity.text!!))
|
||||
entity.type == "top_game_comment" -> DirectUtils.directToAmway(mContext, null, "(推荐入口)", "")
|
||||
entity.type == "server" -> mContext.startActivity(GameServersActivity.getIntent(mContext, "(推荐入口)", ""))
|
||||
//entity.type == "h5_game_center" -> DirectUtils.directLetoGameCenter(mContext)
|
||||
else -> DialogUtils.showLowVersionDialog(mContext)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,9 @@ package com.gh.gamecenter.game.horizontal
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.DataCollectionUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.StringUtils
|
||||
import com.gh.common.util.dip2px
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.GameHorizontalItemBinding
|
||||
@ -55,6 +53,11 @@ class GameHorizontalAdapter(context: Context,
|
||||
|
||||
override fun onBindViewHolder(holder: GameHorizontalItemViewHolder, position: Int) {
|
||||
holder.binding.root.setPadding(0, 0, 0, 8f.dip2px())
|
||||
if (exposureEventList.isNullOrEmpty()) {
|
||||
val params = holder.binding.root.layoutParams as RecyclerView.LayoutParams
|
||||
params.width = RecyclerView.LayoutParams.WRAP_CONTENT
|
||||
holder.binding.root.layoutParams = params
|
||||
}
|
||||
|
||||
val gameEntity = mSubjectEntity.data!![position + getIndex()]
|
||||
holder.binding.game = gameEntity
|
||||
|
||||
@ -20,6 +20,7 @@ import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.base.BaseActivity
|
||||
import com.gh.base.adapter.FragmentAdapter
|
||||
import com.gh.base.fragment.BaseFragment_TabLayout
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.exposure.ExposureEvent
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.FlexLinearLayout
|
||||
@ -49,6 +50,7 @@ import com.gh.gamecenter.suggest.SuggestType
|
||||
import com.gh.gamecenter.tag.TagsActivity
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.halo.assistant.fragment.WebFragment
|
||||
import com.lightgame.download.DataWatcher
|
||||
@ -471,6 +473,9 @@ class GameDetailFragment : NormalFragment() {
|
||||
|
||||
val descFragment = DescFragment()
|
||||
descFragment.arguments = bundle
|
||||
// TODO 从 fragmentManager 里把已有的 fragment 找回来,而不是每次都新建一个
|
||||
fragmentsList.clear()
|
||||
tabTitleList.clear()
|
||||
fragmentsList.add(descFragment)
|
||||
tabTitleList.add(getString(R.string.game_detail_desc))
|
||||
|
||||
@ -911,10 +916,20 @@ class GameDetailFragment : NormalFragment() {
|
||||
|
||||
private fun releaseVideo() {
|
||||
if (mViewModel.displayTopVideo) {
|
||||
recordVideoSchedule()
|
||||
mTopVideoView.release()
|
||||
mTopVideoView.disposableTimer()
|
||||
}
|
||||
}
|
||||
//保存视频进度
|
||||
private fun recordVideoSchedule(){
|
||||
val datas = SPUtils.getString(Constants.SP_TOP_VIDEO_SCHEDULE)
|
||||
val type = object : TypeToken<HashMap<String, Long>>() {}.type
|
||||
val schedules = GsonUtils.gson.fromJson<HashMap<String, Long>>(datas, type)
|
||||
?: hashMapOf()
|
||||
schedules[mTopVideoView.video?.url ?: ""] = mTopVideoView.getCurrentPosition()
|
||||
SPUtils.setString(Constants.SP_TOP_VIDEO_SCHEDULE, GsonUtils.toJson(schedules))
|
||||
}
|
||||
|
||||
private fun tabPerformClick(position: Int) {
|
||||
if (!mIsPreferredTabSelected) {
|
||||
|
||||
@ -15,10 +15,12 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.base.OnListClickListener
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.view.ExpandTextView
|
||||
import com.gh.common.view.GridSpacingItemColorDecoration
|
||||
import com.gh.common.view.divider.HorizontalDividerItemDecoration
|
||||
import com.gh.common.view.divider.VerticalDividerItemDecoration
|
||||
import com.gh.gamecenter.GameNewsActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.SuggestionActivity
|
||||
@ -53,7 +55,8 @@ class DescAdapter(context: Context,
|
||||
|
||||
var descItemList = arrayListOf<DetailEntity>()
|
||||
|
||||
private var mExpandSparseBooleanArray = SparseBooleanArray()
|
||||
private var mExpandableTextExpandStatusSparseBooleanArray = SparseBooleanArray()
|
||||
private var mCustomColumnTagsExpandStatusSparseBooleanArray = SparseBooleanArray()
|
||||
|
||||
fun updateDescItemList(descItemList: ArrayList<DetailEntity>) {
|
||||
this.descItemList = descItemList
|
||||
@ -76,7 +79,6 @@ class DescAdapter(context: Context,
|
||||
DetailEntity.Type.RECOMMENDED_GAMES.value -> RECOMMENDED_GAMES
|
||||
DetailEntity.Type.CUSTOM_COLUMN.value -> CUSTOM_COLUMN
|
||||
DetailEntity.Type.NOTICE.value -> NOTICE
|
||||
DetailEntity.Type.INFERIOR_CUSTOM_COLUMN.value -> INFERIOR_CUSTOM_COLUMN
|
||||
else -> FOOTER
|
||||
}
|
||||
}
|
||||
@ -86,9 +88,6 @@ class DescAdapter(context: Context,
|
||||
COMMENTS -> {
|
||||
GameDetailCommentsViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.gamedetail_item_comments, parent, false))
|
||||
}
|
||||
INFERIOR_CUSTOM_COLUMN -> {
|
||||
GameDetailInferiorCustomColumnViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.gamedetail_item_inferior_custom_column, parent, false))
|
||||
}
|
||||
CUSTOM_COLUMN -> {
|
||||
GameDetailCustomColumnViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.gamedetail_item_custom_column, parent, false))
|
||||
}
|
||||
@ -140,8 +139,6 @@ class DescAdapter(context: Context,
|
||||
when (holder) {
|
||||
is GameDetailNoticeViewHolder -> bindNoticeViewHolder(holder, descItemList[position])
|
||||
|
||||
is GameDetailInferiorCustomColumnViewHolder -> bindCustomColumnViewHolder(holder, descItemList[position])
|
||||
|
||||
is GameDetailCustomColumnViewHolder -> bindCustomColumnViewHolder(holder, descItemList[position])
|
||||
|
||||
is GamesRecommendedGalleryViewHolder -> bindGamesRecommendedGalleryViewHolder(holder, position)
|
||||
@ -222,7 +219,9 @@ class DescAdapter(context: Context,
|
||||
linkImageIv = viewHolder.binding.linkImageIv,
|
||||
linkHintIv = viewHolder.binding.linkHintIv,
|
||||
linkHintTv = viewHolder.binding.linkHintTv,
|
||||
linkHintArrowIv = viewHolder.binding.linkHintArrowIv)
|
||||
linkHintArrowIv = viewHolder.binding.linkHintArrowIv,
|
||||
expandTagsHint = viewHolder.binding.expandTagsHint
|
||||
)
|
||||
|
||||
viewHolder.binding.customColumn = customColumn
|
||||
viewHolder.binding.shouldBoundToNextItem = detailEntity.shouldBoundTogetherWithNextItem
|
||||
@ -237,36 +236,20 @@ class DescAdapter(context: Context,
|
||||
detailEntity.shouldBoundTogetherWithNextItem)
|
||||
}
|
||||
|
||||
// 绑定低优先级自定义栏目
|
||||
private fun bindCustomColumnViewHolder(viewHolder: GameDetailInferiorCustomColumnViewHolder, detailEntity: DetailEntity) {
|
||||
val customColumn = detailEntity.customColumn!!
|
||||
updateCommonCustomView(
|
||||
customColumn,
|
||||
position = viewHolder.adapterPosition,
|
||||
titleHintTv = viewHolder.binding.titleHintTv,
|
||||
contentTv = viewHolder.binding.contentTv,
|
||||
recyclerView = viewHolder.binding.recyclerview,
|
||||
linkImageIv = viewHolder.binding.linkImageIv,
|
||||
linkHintIv = viewHolder.binding.linkHintIv,
|
||||
linkHintTv = viewHolder.binding.linkHintTv,
|
||||
linkHintArrowIv = viewHolder.binding.linkHintArrowIv)
|
||||
viewHolder.binding.customColumn = customColumn
|
||||
viewHolder.binding.executePendingBindings()
|
||||
}
|
||||
|
||||
//绑定大家都在玩
|
||||
private fun bindGamesRecommendedGalleryViewHolder(viewHolder: GamesRecommendedGalleryViewHolder, position: Int) {
|
||||
viewHolder.binding.galleryRv.isNestedScrollingEnabled = false
|
||||
|
||||
viewHolder.binding.executePendingBindings()
|
||||
//分割线
|
||||
val params = viewHolder.itemView.layoutParams as RecyclerView.LayoutParams
|
||||
params.topMargin = DisplayUtils.dip2px(8f)
|
||||
viewHolder.itemView.layoutParams = params
|
||||
// val params = viewHolder.itemView.layoutParams as RecyclerView.LayoutParams
|
||||
// params.topMargin = DisplayUtils.dip2px(8f)
|
||||
// viewHolder.itemView.layoutParams = params
|
||||
//重新调整间距
|
||||
// viewHolder.itemView.setPadding(viewHolder.itemView.paddingLeft, viewHolder.itemView.paddingTop - DisplayUtils.dip2px(4f), viewHolder.itemView.paddingRight, viewHolder.itemView.paddingBottom)
|
||||
val galleryParams = viewHolder.binding.galleryRv.layoutParams as ConstraintLayout.LayoutParams
|
||||
galleryParams.topMargin = DisplayUtils.dip2px(8f)
|
||||
galleryParams.topMargin = DisplayUtils.dip2px(6f)
|
||||
galleryParams.rightMargin = 0
|
||||
viewHolder.binding.galleryRv.layoutParams = galleryParams
|
||||
|
||||
val subjectEntity = descItemList[position].recommendedGames
|
||||
@ -277,6 +260,12 @@ class DescAdapter(context: Context,
|
||||
subjectAdapter = GameHorizontalAdapter(mContext, subjectEntity, true)
|
||||
subjectAdapter.gameName = gameName ?: ""
|
||||
(viewHolder.binding.galleryRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
|
||||
val dividerWidth = (DisplayUtils.getScreenWidth() - 20F.dip2px() * 2 - 72F.dip2px() * 4) / 3
|
||||
val itemDecoration = VerticalDividerItemDecoration.Builder(mContext)
|
||||
.size(dividerWidth)
|
||||
.color(ContextCompat.getColor(mContext, R.color.transparent)).build()
|
||||
viewHolder.binding.galleryRv.addItemDecoration(itemDecoration)
|
||||
viewHolder.binding.galleryRv.adapter = subjectAdapter
|
||||
} else {
|
||||
(subjectAdapter as GameHorizontalAdapter).checkResetData(subjectEntity)
|
||||
@ -298,13 +287,14 @@ class DescAdapter(context: Context,
|
||||
if (viewHolder.binding.recyclerview.adapter == null) {
|
||||
val commentsAdapter = viewHolder.binding.recyclerview.adapter as DescCommentsAdapter?
|
||||
?: DescCommentsAdapter(mContext, mViewModel, mEntrance, gameName)
|
||||
viewHolder.binding.recyclerview.background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
|
||||
viewHolder.binding.recyclerview.isNestedScrollingEnabled = false
|
||||
viewHolder.binding.recyclerview.adapter = commentsAdapter
|
||||
viewHolder.binding.recyclerview.layoutManager = LinearLayoutManager(mContext)
|
||||
val itemDecoration = HorizontalDividerItemDecoration.Builder(mContext)
|
||||
.size(DisplayUtils.dip2px(1f))
|
||||
.size(DisplayUtils.dip2px(0.5f))
|
||||
.margin(DisplayUtils.dip2px(16f))
|
||||
.color(ContextCompat.getColor(mContext, R.color.text_eeeeee)).build()
|
||||
.color(ContextCompat.getColor(mContext, R.color.text_f5f5f5)).build()
|
||||
viewHolder.binding.recyclerview.addItemDecoration(itemDecoration)
|
||||
viewHolder.binding.tvAll.setOnClickListener {
|
||||
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
|
||||
@ -327,6 +317,8 @@ class DescAdapter(context: Context,
|
||||
viewHolder.binding.galleryRv.isNestedScrollingEnabled = false
|
||||
if (viewHolder.binding.galleryRv.adapter == null) {
|
||||
viewHolder.binding.galleryRv.apply {
|
||||
background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
|
||||
setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 16F.dip2px())
|
||||
layoutManager = LinearLayoutManager(mContext)
|
||||
val relatedVersionAdapter = GameRelatedVersionAdapter(mContext, gameName
|
||||
?: "", relatedVersion!!, mEntrance)
|
||||
@ -431,19 +423,19 @@ class DescAdapter(context: Context,
|
||||
holder.binding.containerPaddingTop = itemData.paddingTop
|
||||
holder.binding.containerPaddingBottom = itemData.paddingBottom
|
||||
holder.binding.contentTv.text = updateContent?.updateDes ?: ""
|
||||
val maxDesLines = if (mExpandSparseBooleanArray.get(holder.adapterPosition)) Int.MAX_VALUE else 4
|
||||
val maxDesLines = if (mExpandableTextExpandStatusSparseBooleanArray.get(holder.adapterPosition)) Int.MAX_VALUE else 4
|
||||
holder.binding.contentTv.setExpandMaxLines(maxDesLines)
|
||||
holder.binding.contentTv.setIsExpanded(Int.MAX_VALUE == maxDesLines)
|
||||
holder.binding.executePendingBindings()
|
||||
holder.binding.contentTv.setExpandCallback {
|
||||
mExpandSparseBooleanArray.put(holder.adapterPosition, true)
|
||||
mExpandableTextExpandStatusSparseBooleanArray.put(holder.adapterPosition, true)
|
||||
MtaHelper.onEvent("游戏详情_新", "展开更新内容", gameName)
|
||||
}
|
||||
holder.binding.historyVersionTv.setOnClickListener {
|
||||
MtaHelper.onEvent("历史版本", "进入", gameName)
|
||||
MtaHelper.onEvent("游戏详情_新", "更新内容_历史版本", gameName)
|
||||
val intent = HistoryApkListActivity.getIntent(mContext, mViewModel.game
|
||||
?: GameEntity(), mEntrance, "更新内容")
|
||||
?: GameEntity(), mEntrance, "游戏详情[${gameName}]:更新内容")
|
||||
mContext.startActivity(intent)
|
||||
}
|
||||
holder.binding.historyVersionTv.visibility = if (updateContent?.historyApkStatus == "on" && updateContent.historyApkCount != 0) View.VISIBLE else View.GONE
|
||||
@ -470,7 +462,7 @@ class DescAdapter(context: Context,
|
||||
adapter = serviceAdapter
|
||||
val itemDecoration = HorizontalDividerItemDecoration.Builder(mContext)
|
||||
.size(DisplayUtils.dip2px(12f))
|
||||
.color(ContextCompat.getColor(mContext, R.color.white)).build()
|
||||
.color(ContextCompat.getColor(mContext, R.color.transparent)).build()
|
||||
addItemDecoration(itemDecoration)
|
||||
}
|
||||
}
|
||||
@ -534,15 +526,15 @@ class DescAdapter(context: Context,
|
||||
viewHolder.binding.containerPaddingBottom = itemData.paddingBottom
|
||||
viewHolder.binding.galleryRv.isNestedScrollingEnabled = false
|
||||
viewHolder.binding.galleryRv.apply {
|
||||
background = ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5)
|
||||
background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
|
||||
layoutManager = LinearLayoutManager(mContext)
|
||||
val libaoAdapter = GameLibaoAdapter(mContext, libao!!, gameName ?: "", mListListener)
|
||||
adapter = libaoAdapter
|
||||
if (itemDecorationCount == 0) {
|
||||
val itemDecoration = HorizontalDividerItemDecoration.Builder(mContext)
|
||||
.size(DisplayUtils.dip2px(1f))
|
||||
.size(DisplayUtils.dip2px(0.5f))
|
||||
.margin(DisplayUtils.dip2px(16f))
|
||||
.color(ContextCompat.getColor(mContext, R.color.text_eeeeee)).build()
|
||||
.color(ContextCompat.getColor(mContext, R.color.text_f5f5f5)).build()
|
||||
addItemDecoration(itemDecoration)
|
||||
}
|
||||
}
|
||||
@ -598,13 +590,13 @@ class DescAdapter(context: Context,
|
||||
|
||||
private fun updateBoundableContainerBackground(container: View, shouldBoundTogetherWithPreviousItem: Boolean, shouldBoundTogetherWithNextItem: Boolean) {
|
||||
container.background = if (shouldBoundTogetherWithPreviousItem && shouldBoundTogetherWithNextItem) {
|
||||
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8)
|
||||
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white)
|
||||
} else if (shouldBoundTogetherWithPreviousItem) {
|
||||
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5_bottom_only)
|
||||
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5_bottm_only)
|
||||
} else if (shouldBoundTogetherWithNextItem) {
|
||||
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5_top_only)
|
||||
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5_top_only)
|
||||
} else {
|
||||
ContextCompat.getDrawable(mContext, R.drawable.bg_shape_f8_radius_5)
|
||||
ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
|
||||
}
|
||||
}
|
||||
|
||||
@ -616,9 +608,10 @@ class DescAdapter(context: Context,
|
||||
linkImageIv: View,
|
||||
linkHintIv: View,
|
||||
linkHintTv: View,
|
||||
linkHintArrowIv: View) {
|
||||
linkHintArrowIv: View,
|
||||
expandTagsHint: View) {
|
||||
val tags = if (customColumn.showInfoTag == true) customColumn.infoTag else arrayListOf()
|
||||
val maxDesLines = if (mExpandSparseBooleanArray.get(position)) {
|
||||
val maxDesLines = if (mExpandableTextExpandStatusSparseBooleanArray.get(position)) {
|
||||
Int.MAX_VALUE
|
||||
} else {
|
||||
when {
|
||||
@ -626,27 +619,42 @@ class DescAdapter(context: Context,
|
||||
else -> customColumn.showDesRowNum!!
|
||||
}
|
||||
}
|
||||
val layoutManager = if (customColumn.showInfoTagDesType == "expand" || mCustomColumnTagsExpandStatusSparseBooleanArray.get(position)) {
|
||||
if (customColumn.showInfoTagDes == false) {
|
||||
GridLayoutManager(mContext, 3)
|
||||
} else {
|
||||
mCustomColumnTagsExpandStatusSparseBooleanArray.put(position, true)
|
||||
LinearLayoutManager(mContext)
|
||||
}
|
||||
} else {
|
||||
GridLayoutManager(mContext, 3)
|
||||
}
|
||||
|
||||
titleHintTv.paint?.isUnderlineText = true
|
||||
contentTv.setExpandMaxLines(maxDesLines)
|
||||
contentTv.setIsExpanded(Int.MAX_VALUE == maxDesLines)
|
||||
contentTv.setTextWithHighlightedTextWrappedInsideWrapper(customColumn.des
|
||||
?: "")
|
||||
contentTv.setTextWithHighlightedTextWrappedInsideWrapper(customColumn.des ?: "")
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
recyclerView.layoutManager = if (customColumn.showInfoTagDes == true) {
|
||||
LinearLayoutManager(mContext)
|
||||
} else {
|
||||
GridLayoutManager(mContext, 3)
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.setOnClickListener {
|
||||
if (customColumn.showInfoTagDes == true) {
|
||||
customColumn.showExpandTagsHint = false
|
||||
SPUtils.setBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT, true)
|
||||
mCustomColumnTagsExpandStatusSparseBooleanArray.put(position, true)
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
expandTagsHint.goneIf(customColumn.showExpandTagsHint == false)
|
||||
|
||||
if (recyclerView.adapter == null) {
|
||||
recyclerView.adapter = GameDetailCustomColumnAdapter(mContext)
|
||||
}
|
||||
|
||||
(recyclerView.adapter as GameDetailCustomColumnAdapter)
|
||||
.updateData(ArrayList(tags!!), customColumn.showInfoTagDes ?: false)
|
||||
.updateData(ArrayList(tags!!), mCustomColumnTagsExpandStatusSparseBooleanArray.get(position))
|
||||
contentTv.setExpandCallback {
|
||||
mExpandSparseBooleanArray.put(position, true)
|
||||
mExpandableTextExpandStatusSparseBooleanArray.put(position, true)
|
||||
if (customColumn.name == "游戏简介") {
|
||||
MtaHelper.onEvent("游戏详情_新", "展开游戏介绍", gameName)
|
||||
} else {
|
||||
@ -659,7 +667,7 @@ class DescAdapter(context: Context,
|
||||
titleHintTv.performClick()
|
||||
}
|
||||
|
||||
val linkClosure: (LinkEntity) -> Unit = {
|
||||
val linkClosure: (LinkEntity) -> Unit = {
|
||||
// 当配置的是不需要 id 也能跳转的时候直接跳转,否则都得根据是否有 ID 判断跳不跳
|
||||
if (it.type == "top_game_comment"
|
||||
|| it.type == "server"
|
||||
@ -702,7 +710,6 @@ class DescAdapter(context: Context,
|
||||
|
||||
companion object {
|
||||
const val CUSTOM_COLUMN = 64 // 自定义栏目
|
||||
const val INFERIOR_CUSTOM_COLUMN = 92 // 低权重自定义栏目
|
||||
const val RELATED_VERSION = 128//其他相关版本
|
||||
const val COMMENTS = 8//评论
|
||||
const val IMAGE = 3//图片推荐
|
||||
@ -726,8 +733,6 @@ class DescAdapter(context: Context,
|
||||
|
||||
class GameDetailCustomColumnViewHolder(var binding: GamedetailItemCustomColumnBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class GameDetailInferiorCustomColumnViewHolder(var binding: GamedetailItemInferiorCustomColumnBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class GameDetailRelatedVersionViewHolder(var binding: GameGalleryListBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class GameVideoGalleryViewHolder(var binding: GameGalleryListBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
@ -60,6 +60,7 @@ class DescCommentsAdapter(context: Context,
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is GameDetailRatingCommentViewHolder) {
|
||||
val commentData = comments[position]
|
||||
var isChildLongClick = false
|
||||
holder.binding.run {
|
||||
data = commentData
|
||||
val p = Pattern.compile(RatingEditActivity.LABEL_REGEX)
|
||||
@ -116,6 +117,10 @@ class DescCommentsAdapter(context: Context,
|
||||
tvBadgeName.setOnClickListener { sdvUserBadge.performClick() }
|
||||
|
||||
commentItem.setOnClickListener {
|
||||
if (isChildLongClick) {
|
||||
isChildLongClick = false
|
||||
return@setOnClickListener
|
||||
}
|
||||
val intent = RatingReplyActivity.getIntent(mContext, mViewModel.game!!, commentData, mEntrance, path)
|
||||
SyncDataBetweenPageHelper.startActivityForResult(mContext, intent, RATING_REPLY_REQUEST, position)
|
||||
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击评论", mViewModel.game?.name)
|
||||
@ -123,6 +128,12 @@ class DescCommentsAdapter(context: Context,
|
||||
content.setExpandCallback {
|
||||
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击全文", mViewModel.game?.name)
|
||||
}
|
||||
|
||||
content.setOnLongClickListener(View.OnLongClickListener {
|
||||
isChildLongClick = true
|
||||
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "").copyTextAndToast()
|
||||
return@OnLongClickListener true
|
||||
})
|
||||
more.setOnClickListener {
|
||||
showMorePopWindow(it, commentData.user.id == UserManager.getInstance().userId) { text ->
|
||||
when (text) {
|
||||
|
||||
@ -10,6 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import com.gh.base.fragment.BaseFragment
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.LibaoDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
@ -23,9 +24,11 @@ import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
|
||||
import com.gh.gamecenter.video.detail.VideoDetailActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import kotlin.math.abs
|
||||
|
||||
class DescFragment : BaseFragment<Any>() {
|
||||
|
||||
@ -33,8 +36,8 @@ class DescFragment : BaseFragment<Any>() {
|
||||
private var layoutManager: LinearLayoutManager? = null
|
||||
private var mGameEntity: GameEntity? = null
|
||||
|
||||
// private var mDetailEntity: GameDetailEntity? = null
|
||||
private var mNewDetailEntity: NewGameDetailEntity? = null
|
||||
private var mDisplayHintDisposable: Disposable? = null
|
||||
|
||||
private lateinit var mViewModel: DescViewModel
|
||||
|
||||
@ -125,14 +128,29 @@ class DescFragment : BaseFragment<Any>() {
|
||||
mRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
val position = layoutManager!!.findFirstCompletelyVisibleItemPosition()
|
||||
if (position == 0 && Math.abs(dy) > 10) {
|
||||
val firstCompletelyVisibleItemPosition = layoutManager!!.findFirstCompletelyVisibleItemPosition()
|
||||
val lastCompletelyVisibleItemPosition = layoutManager!!.findLastCompletelyVisibleItemPosition()
|
||||
if (firstCompletelyVisibleItemPosition == 0 && abs(dy) > 10) {
|
||||
EventBus.getDefault().post(EBReuse(OPEN_APPBAR))
|
||||
}
|
||||
|
||||
for (i in firstCompletelyVisibleItemPosition..lastCompletelyVisibleItemPosition) {
|
||||
if (i < 0) continue
|
||||
|
||||
if (mAdapter.getItemViewType(i) == DescAdapter.CUSTOM_COLUMN
|
||||
&& mAdapter.descItemList[i].customColumn?.showExpandTagsHint == true) {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mDisplayHintDisposable?.dispose()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(reuse: EBReuse) {
|
||||
if (SKIP_DESC == reuse.type) {
|
||||
@ -159,5 +177,4 @@ class DescFragment : BaseFragment<Any>() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -3,11 +3,13 @@ package com.gh.gamecenter.gamedetail.desc
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.facebook.common.util.UriUtil
|
||||
import com.gh.common.constant.Constants
|
||||
import com.gh.common.repository.RemenkapaiRepository
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.R
|
||||
@ -195,19 +197,12 @@ class DescViewModel(application: Application,
|
||||
|
||||
// 装饰列表数据
|
||||
fun decorateList(detailEntityList: ArrayList<DetailEntity>): ArrayList<DetailEntity> {
|
||||
|
||||
// // A 把低权重的自定义栏目转化为新的低权重自定义栏目 item // DEPRECATED
|
||||
// for (rawItem in detailEntityList) {
|
||||
// if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
|
||||
// if (rawItem.customColumn?.order ?: -1 <= 0) {
|
||||
// rawItem.type = DetailEntity.Type.INFERIOR_CUSTOM_COLUMN.value
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
val specialPadding = DisplayUtils.dip2px(12F)
|
||||
val defaultPadding = DisplayUtils.dip2px(15F)
|
||||
|
||||
var containsFirstTimeExpandCustomColumnTags = false
|
||||
var hasShownCustomColumnTagsExpandHint = SPUtils.getBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT)
|
||||
|
||||
// A 确定每个 item 的上下内边距
|
||||
for ((index, rawItem) in detailEntityList.withIndex()) {
|
||||
rawItem.paddingTop = defaultPadding
|
||||
@ -247,6 +242,38 @@ class DescViewModel(application: Application,
|
||||
}
|
||||
}
|
||||
|
||||
// D 处理自定义栏目相关的东西
|
||||
for (rawItem in detailEntityList) {
|
||||
if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
|
||||
// 判断自定义栏目的标签是否需要进入就自动展开
|
||||
if (rawItem.customColumn?.showInfoTagDesType == "first_expand"
|
||||
&& !SPUtils.getBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS)) {
|
||||
containsFirstTimeExpandCustomColumnTags = true
|
||||
rawItem.customColumn?.showInfoTagDesType = "expand"
|
||||
}
|
||||
|
||||
// 正文内容为空,但是后台配置了标签展开的默认展开
|
||||
if (rawItem.customColumn?.showInfoTag == true
|
||||
&& TextUtils.isEmpty(rawItem.customColumn?.des)) {
|
||||
rawItem.customColumn?.showInfoTagDesType = "expand"
|
||||
}
|
||||
|
||||
// 判断是否显示标签展开提示
|
||||
if (rawItem.customColumn?.showInfoTagDes == true
|
||||
&& rawItem.customColumn?.infoTag?.size != 0
|
||||
&& rawItem.customColumn?.showInfoTagDesType != "expand"
|
||||
&& !hasShownCustomColumnTagsExpandHint) {
|
||||
rawItem.customColumn?.showExpandTagsHint = true
|
||||
// 内存置为 true 避免出现多个提示
|
||||
hasShownCustomColumnTagsExpandHint = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (containsFirstTimeExpandCustomColumnTags) {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS, true)
|
||||
}
|
||||
|
||||
loadCustomColumnImageInAdvance(detailEntityList)
|
||||
|
||||
return detailEntityList
|
||||
|
||||
@ -85,6 +85,7 @@ class GameGalleryAdapter(var context: Context,
|
||||
}
|
||||
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
|
||||
params.leftMargin = DisplayUtils.dip2px(if (position == 0) 20f else 8f)
|
||||
params.rightMargin = DisplayUtils.dip2px(if (position == itemCount - 1) 20f else 0f)
|
||||
holder.itemView.layoutParams = params
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ class GameRaidersAdapter(val context: Context, val articles: ArrayList<NewsEntit
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
|
||||
params.leftMargin = DisplayUtils.dip2px(if (position == 0) 20f else 12f)
|
||||
params.rightMargin = DisplayUtils.dip2px(if (position == itemCount - 1) 20f else 0f)
|
||||
holder.itemView.layoutParams = params
|
||||
val newsEntity = articles[position]
|
||||
if (holder is RaidersViewHolder) {
|
||||
|
||||
@ -6,10 +6,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.GameViewUtils
|
||||
import com.gh.common.util.ImageUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.util.StringUtils
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRelatedVersionBinding
|
||||
@ -55,10 +52,13 @@ class GameRelatedVersionAdapter(val context: Context, val gameName: String, val
|
||||
}
|
||||
}
|
||||
is MoreViewHolder -> {
|
||||
holder.itemView.setOnClickListener {
|
||||
MtaHelper.onEvent("游戏详情_新", "相关游戏版本_展开", gameName)
|
||||
isExpand = true
|
||||
notifyItemRangeInserted(mShowItemCount + 1, datas.size - mShowItemCount)
|
||||
holder.itemView.apply {
|
||||
setPadding(0, 0, 0, 0)
|
||||
setOnClickListener {
|
||||
MtaHelper.onEvent("游戏详情_新", "相关游戏版本_展开", gameName)
|
||||
isExpand = true
|
||||
notifyItemRangeInserted(mShowItemCount + 1, datas.size - mShowItemCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import android.widget.TextView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.dialog.TrackableDialog
|
||||
import com.gh.common.util.DisplayUtils
|
||||
import com.gh.common.util.MtaHelper
|
||||
import com.gh.common.view.VerticalItemDecoration
|
||||
import com.gh.gamecenter.R
|
||||
@ -17,12 +18,18 @@ import com.gh.gamecenter.gamedetail.entity.BigEvent
|
||||
|
||||
class GameBigEventDialog(context: Context, val gameName: String, val bigEvents: List<BigEvent>, val mEntrance: String, mEvent: String, mKey: String, mValue: String) :
|
||||
TrackableDialog(context, R.style.GhAlertDialog, mEvent, mKey, mValue) {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (window != null) {
|
||||
window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
val params = window!!.attributes
|
||||
params.width = context.resources.displayMetrics.widthPixels - DisplayUtils.dip2px(40f)
|
||||
window!!.attributes = params
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (window != null) {
|
||||
window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
}
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
|
||||
val contentView = LayoutInflater.from(context).inflate(R.layout.dialog_game_big_event, null)
|
||||
|
||||
@ -93,9 +93,13 @@ data class CustomColumn(
|
||||
var showInfoTag: Boolean? = false,
|
||||
@SerializedName("show_info_tag_des")
|
||||
var showInfoTagDes: Boolean? = false,
|
||||
@SerializedName("show_info_tag_des_type")
|
||||
var showInfoTagDesType: String? = "", // first_expand (用于默认展开), collapse, expand
|
||||
@SerializedName("info_tag")
|
||||
var infoTag: List<TagEntity>? = listOf(),
|
||||
var time: Long? = 0)
|
||||
var time: Long? = 0,
|
||||
// 是否显示自定义栏目的提示浮窗 (本地字段)
|
||||
var showExpandTagsHint: Boolean? = false)
|
||||
|
||||
@Keep
|
||||
data class Title(var icon: String, var value: String, var color: String)
|
||||
|
||||
@ -107,11 +107,13 @@ class FuLiAdapter(context: Context,
|
||||
|
||||
private fun initAnswerViewHolder(holder: GameDetailAnswerViewHolder, position: Int) {
|
||||
holder.binding.run {
|
||||
|
||||
val isShowAnswerHint = mSharedPreferences.getBoolean(mAnswerHintKey, true)
|
||||
if (isShowAnswerHint) {
|
||||
answerItemHint.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
holder.itemView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.transparent))
|
||||
answerItemList.background = ContextCompat.getDrawable(mContext, R.drawable.background_shape_white_radius_5)
|
||||
answerItemList.layoutManager = LinearLayoutManager(mContext)
|
||||
answerAdapter = GameDetailAnswerAdapter(mContext, mFuLiViewModel!!, itemList?.get(position)?.answer!!, mEntrance)
|
||||
mFuLiViewModel.gameCommunity = itemList?.get(position)?.community
|
||||
@ -155,6 +157,7 @@ class FuLiAdapter(context: Context,
|
||||
viewHolder.binding.galleryRv.apply {
|
||||
layoutManager = LinearLayoutManager(mContext)
|
||||
val toolkitAdapter = GameDetailToolsAdapter(mContext, mFuLiViewModel?.game?.name, tools)
|
||||
toolkitAdapter.setItemColor(R.color.transparent)
|
||||
adapter = toolkitAdapter
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,8 +37,8 @@ class GameDetailAnswerAdapter(context: Context,
|
||||
|
||||
override fun onBindViewHolder(holder: CommunityAnswerItemViewHolder, position: Int) {
|
||||
holder.binding.contentContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
|
||||
holder.binding.commentCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
|
||||
holder.binding.voteCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
|
||||
holder.commentCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
|
||||
holder.voteCountContainer.setBackgroundColor(ContextCompat.getColor(mContext,R.color.transparent))
|
||||
holder.binding.contentContainer.setPadding(DisplayUtils.dip2px(12f),0,DisplayUtils.dip2px(12f),0)
|
||||
|
||||
holder.binding.topLine.visibleIf(position > 0)
|
||||
|
||||
@ -9,8 +9,8 @@ import com.gh.gamecenter.databinding.DialogServersCalendearDetailItemBinding
|
||||
import com.gh.gamecenter.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.MeEntity
|
||||
import com.gh.gamecenter.entity.ServerCalendarEntity
|
||||
import com.gh.gamecenter.gamedetail.fuli.FuLiFragment
|
||||
import com.gh.gamecenter.servers.patch.PatchKaifuActivity.Companion.getIntent
|
||||
import com.gh.gamecenter.servers.patch.PatchKaifuActivity
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
class ServersDetailViewHolder(val binding: DialogServersCalendearDetailItemBinding) : BaseRecyclerViewHolder<Any>(binding.root) {
|
||||
|
||||
@ -28,11 +28,15 @@ class ServersDetailViewHolder(val binding: DialogServersCalendearDetailItemBindi
|
||||
binding.name.paint.isAntiAlias = true
|
||||
binding.name.setOnClickListener {
|
||||
val context = binding.root.context
|
||||
(context as Activity).startActivityForResult(getIntent(
|
||||
context,
|
||||
data,
|
||||
gameEntity.id),
|
||||
ServersCalendarActivity.GAME_DETAIL_PATCH_KAIFU_REQUEST)
|
||||
if ("删档内测" == data.type || "不删档内测" == data.type || "公测" == data.type) {
|
||||
Utils.toast(context, "开测信息不可编辑");
|
||||
} else {
|
||||
(context as Activity).startActivityForResult(PatchKaifuActivity.getIntent(
|
||||
context,
|
||||
data,
|
||||
gameEntity.id),
|
||||
ServersCalendarActivity.GAME_DETAIL_PATCH_KAIFU_REQUEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,9 @@ import com.lightgame.adapter.BaseRecyclerAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
@ -34,6 +36,11 @@ public class GameDetailToolsAdapter extends BaseRecyclerAdapter {
|
||||
private String mGameName;
|
||||
private final int MORE = 0;
|
||||
private final int TOOLBOX = 1;
|
||||
private int mItemColor = R.color.white;
|
||||
|
||||
public void setItemColor(@ColorRes int color) {
|
||||
mItemColor = color;
|
||||
}
|
||||
|
||||
public GameDetailToolsAdapter(Context context, String gameName, List<ToolBoxEntity> toolBoxList) {
|
||||
super(context);
|
||||
@ -86,6 +93,7 @@ public class GameDetailToolsAdapter extends BaseRecyclerAdapter {
|
||||
}
|
||||
|
||||
private void initToolBoxViewHolder(ToolBoxViewHolder viewHolder, final ToolBoxEntity toolBoxEntity) {
|
||||
viewHolder.itemView.setBackground(ContextCompat.getDrawable(mContext, mItemColor));
|
||||
viewHolder.itemView.setPadding(0, DisplayUtils.dip2px(mContext, 10), 0, DisplayUtils.dip2px(mContext, 10));
|
||||
|
||||
viewHolder.mDes.setText(toolBoxEntity.getDes());
|
||||
|
||||
@ -25,7 +25,9 @@ import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
class HistoryApkListAdapter(context: Context, private var mViewModel: HistoryApkListViewModel) : ListAdapter<GameEntity>(context) {
|
||||
class HistoryApkListAdapter(context: Context,
|
||||
private var mViewModel: HistoryApkListViewModel,
|
||||
private var mEntrance: String) : ListAdapter<GameEntity>(context) {
|
||||
|
||||
private var mExpandSparseBooleanArray = SparseBooleanArray()
|
||||
private var mDescExpandedMarginRight = -1
|
||||
@ -74,8 +76,8 @@ class HistoryApkListAdapter(context: Context, private var mViewModel: HistoryApk
|
||||
gameEntity,
|
||||
0,
|
||||
this@HistoryApkListAdapter,
|
||||
"$mEntrance+(历史版本)",
|
||||
"历史版本",
|
||||
"",
|
||||
null,
|
||||
object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
@ -155,10 +157,10 @@ class HistoryApkListAdapter(context: Context, private var mViewModel: HistoryApk
|
||||
|
||||
private fun showDowngradeToastIfNeed(apkEntity: ApkEntity, btnText: CharSequence) {
|
||||
when (btnText) {
|
||||
"下载" -> MtaHelper.onEvent("历史版本", "下载", mViewModel.game.name)
|
||||
"下载中" -> MtaHelper.onEvent("历史版本", "下载中", mViewModel.game.name)
|
||||
"安装" -> MtaHelper.onEvent("历史版本", "安装", mViewModel.game.name)
|
||||
"启动" -> MtaHelper.onEvent("历史版本", "启动", mViewModel.game.name)
|
||||
"下载" -> MtaHelper.onEvent("历史版本", "下载", "${mViewModel.game.name}_${apkEntity.version}")
|
||||
"下载中" -> MtaHelper.onEvent("历史版本", "下载中", "${mViewModel.game.name}_${apkEntity.version}")
|
||||
"安装" -> MtaHelper.onEvent("历史版本", "安装", "${mViewModel.game.name}_${apkEntity.version}")
|
||||
"启动" -> MtaHelper.onEvent("历史版本", "启动", "${mViewModel.game.name}_${apkEntity.version}")
|
||||
}
|
||||
if (btnText == "安装" || btnText == "下载") {
|
||||
if (PackageUtils.isInstalled(mContext, apkEntity.packageName)) {
|
||||
|
||||
@ -84,7 +84,7 @@ class HistoryApkListFragment : ListFragment<GameEntity, HistoryApkListViewModel>
|
||||
|
||||
override fun provideListAdapter(): ListAdapter<*> {
|
||||
if (mAdapter == null) {
|
||||
mAdapter = HistoryApkListAdapter(requireContext(), mViewModel!!)
|
||||
mAdapter = HistoryApkListAdapter(requireContext(), mViewModel!!, mEntrance)
|
||||
}
|
||||
return mAdapter!!
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user