Compare commits
32 Commits
v5.31.3-97
...
feature-js
| Author | SHA1 | Date | |
|---|---|---|---|
| 49a610deee | |||
| 61f43d53b2 | |||
| 0dcf5d2097 | |||
| 32e584c04c | |||
| fbe29d82be | |||
| 3d4977dc87 | |||
| 4d0fda6157 | |||
| 28e28d0775 | |||
| 6f53a67554 | |||
| 05268442f8 | |||
| 55521e6f29 | |||
| db5b09cc11 | |||
| b0922b4c29 | |||
| b809ae6687 | |||
| c575e589ae | |||
| 2af47af681 | |||
| b1228bdd2a | |||
| ffae0d1b1d | |||
| 3fc1fd821a | |||
| b3af44cc4c | |||
| dd7072eea4 | |||
| 4ee463f03e | |||
| 16526ddfbd | |||
| d6e676300e | |||
| 7852972e01 | |||
| 80403e1684 | |||
| db7fbe057e | |||
| 41340f7333 | |||
| e73fc09d9b | |||
| 70e63ed8e3 | |||
| b7a36074ed | |||
| 141d179a64 |
@ -71,7 +71,7 @@ android_build:
|
||||
exit_codes: 137
|
||||
only:
|
||||
- dev
|
||||
- dev-5.31.0
|
||||
- dev-5.32.0
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -102,7 +102,7 @@ sonarqube_analysis:
|
||||
exit_codes: 137
|
||||
only:
|
||||
- dev
|
||||
- dev-5.31.0
|
||||
- dev-5.32.0
|
||||
|
||||
## 发送简易检测结果报告
|
||||
send_sonar_report:
|
||||
@ -120,7 +120,7 @@ send_sonar_report:
|
||||
exit_codes: 137
|
||||
only:
|
||||
- dev
|
||||
- dev-5.31.0
|
||||
- dev-5.32.0
|
||||
|
||||
oss-upload&send-email:
|
||||
tags:
|
||||
@ -152,4 +152,4 @@ oss-upload&send-email:
|
||||
- /usr/local/bin/python /ci-android-mail.py
|
||||
only:
|
||||
- dev
|
||||
- dev-5.31.0
|
||||
- dev-5.32.0
|
||||
@ -275,7 +275,7 @@
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.VoteActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
|
||||
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
|
||||
|
||||
<activity
|
||||
android:name="com.gh.gamecenter.WeiBoShareActivity"
|
||||
|
||||
@ -352,9 +352,9 @@ RE.ImageClickListener = function() {
|
||||
var img = imgs[i];
|
||||
var imageClassName = img.className;
|
||||
if (imageClassName == "image-link"|| img.className == "poster") continue;
|
||||
window.imagelistener.imageArr(img.src);
|
||||
window.NativeCallBack.invokeMethod("imageArr", img.src);
|
||||
img.onclick = function() {
|
||||
window.imagelistener.imageClick(this.src);
|
||||
window.NativeCallBack.invokeMethod("imageClick", this.src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,6 +60,9 @@ object AdDelegateHelper {
|
||||
private val mGameSearchAdList: ArrayList<AdConfig> by lazy { arrayListOf() }
|
||||
private var mVGameLaunchAd: AdConfig? = null
|
||||
|
||||
val vGameLaunchAd: AdConfig?
|
||||
get() = mVGameLaunchAd
|
||||
|
||||
private const val AD_SDK_CSJ = "穿山甲"
|
||||
private const val AD_SDK_BEIZI = "倍孜"
|
||||
private const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
|
||||
|
||||
@ -58,7 +58,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
|
||||
val accelerateSet =
|
||||
HashSet(SPUtils.getStringSet(Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET))
|
||||
if (!mGameList.isNullOrEmpty() && !accelerateSet.contains(mGameList!![0].messageId)) {
|
||||
showAccelerateNotificationPopupWindow(mGameList!![0]) {
|
||||
showAccelerateNotificationPopupWindow(mActivity!!, mViewModel, mBaseHandler, mGameList!![0]) {
|
||||
processNext()
|
||||
}
|
||||
accelerateSet.add(mGameList!![0].messageId)
|
||||
@ -74,54 +74,61 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAccelerateNotificationPopupWindow(gameEntity: GameEntity?, dismissCallback: () -> Unit) {
|
||||
val binding: PopupAccelerateNotificationBinding =
|
||||
PopupAccelerateNotificationBinding.inflate(LayoutInflater.from(mActivity))
|
||||
if (gameEntity != null) {
|
||||
binding.gameIconView.displayGameIcon(gameEntity)
|
||||
binding.gameNameTv.text = gameEntity.name
|
||||
binding.root.setOnClickListener {
|
||||
NewFlatLogUtils.logMessageInformClickPluginVersion(
|
||||
gameEntity.id,
|
||||
gameEntity.name!!
|
||||
)
|
||||
if (gameEntity.messageId.isNotEmpty()) {
|
||||
// 把对应系统消息设为已读
|
||||
mViewModel?.postMessageRead(gameEntity.messageId)
|
||||
companion object {
|
||||
fun showAccelerateNotificationPopupWindow(
|
||||
activity: Activity,
|
||||
viewModel: MainWrapperViewModel?,
|
||||
baseHandler: BaseFragment.BaseHandler?,
|
||||
gameEntity: GameEntity?,
|
||||
dismissCallback: (() -> Unit)?
|
||||
) {
|
||||
val binding: PopupAccelerateNotificationBinding =
|
||||
PopupAccelerateNotificationBinding.inflate(LayoutInflater.from(activity))
|
||||
if (gameEntity != null) {
|
||||
binding.gameIconView.displayGameIcon(gameEntity)
|
||||
binding.gameNameTv.text = gameEntity.name
|
||||
binding.root.setOnClickListener {
|
||||
NewFlatLogUtils.logMessageInformClickPluginVersion(
|
||||
gameEntity.id,
|
||||
gameEntity.name!!
|
||||
)
|
||||
if (gameEntity.messageId.isNotEmpty()) {
|
||||
// 把对应系统消息设为已读
|
||||
viewModel?.postMessageRead(gameEntity.messageId)
|
||||
}
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
context = activity,
|
||||
gameId = gameEntity.id,
|
||||
entrance = "首页插件上架弹窗",
|
||||
defaultTab = -1,
|
||||
isSkipGameComment = false,
|
||||
scrollToLibao = false,
|
||||
openVideoStreaming = false,
|
||||
openPlatformWindow = true,
|
||||
traceEvent = null
|
||||
)
|
||||
}
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
context = mActivity!!,
|
||||
gameId = gameEntity.id,
|
||||
entrance = "首页插件上架弹窗",
|
||||
defaultTab = -1,
|
||||
isSkipGameComment = false,
|
||||
scrollToLibao = false,
|
||||
openVideoStreaming = false,
|
||||
openPlatformWindow = true,
|
||||
traceEvent = null
|
||||
}
|
||||
BugFixedPopupWindow(
|
||||
binding.root,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
isTouchable = true
|
||||
isFocusable = true
|
||||
isOutsideTouchable = true
|
||||
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
|
||||
showAtLocation(
|
||||
activity.window.decorView,
|
||||
Gravity.TOP,
|
||||
0,
|
||||
DisplayUtils.getStatusBarHeight(activity.resources) + DisplayUtils.dip2px(42f)
|
||||
)
|
||||
setOnDismissListener {
|
||||
dismissCallback?.invoke()
|
||||
}
|
||||
baseHandler?.postDelayed({ dismiss() }, 5000)
|
||||
}
|
||||
}
|
||||
BugFixedPopupWindow(
|
||||
binding.root,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
isTouchable = true
|
||||
isFocusable = true
|
||||
isOutsideTouchable = true
|
||||
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
|
||||
showAtLocation(
|
||||
mActivity!!.window.decorView,
|
||||
Gravity.TOP,
|
||||
0,
|
||||
DisplayUtils.getStatusBarHeight(mActivity!!.resources) + DisplayUtils.dip2px(42f)
|
||||
)
|
||||
setOnDismissListener {
|
||||
dismissCallback.invoke()
|
||||
}
|
||||
mBaseHandler?.postDelayed({ dismiss() }, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -17,4 +17,6 @@ class PriorityChain {
|
||||
mHandlerQueue.poll()?.process(mHandlerQueue)
|
||||
}
|
||||
|
||||
fun isHandlerQueueEmpty() = mHandlerQueue.isEmpty()
|
||||
|
||||
}
|
||||
@ -15,18 +15,19 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.MainActivity;
|
||||
import com.gh.gamecenter.SplashScreenActivity;
|
||||
import com.gh.gamecenter.common.avoidcallback.AvoidOnResultManager;
|
||||
import com.gh.gamecenter.common.avoidcallback.Callback;
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
|
||||
import com.gh.gamecenter.common.base.fragment.ToolbarFragment;
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts;
|
||||
import com.gh.gamecenter.core.utils.ClassUtils;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.AppManager;
|
||||
import com.lightgame.utils.Utils;
|
||||
|
||||
import org.json.JSONException;
|
||||
@ -66,8 +67,8 @@ public class EntranceUtils {
|
||||
public static void jumpActivity(Context context, Bundle bundle) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
if (HaloApp.getInstance().isRunningForeground) {
|
||||
// 应用正在运行,前台或后台
|
||||
if (AppManager.getInstance().findActivity(MainActivity.class) != null) {
|
||||
// 应用正在运行,前台或后台,且MainActivity在栈中
|
||||
String to = bundle.getString(KEY_TO);
|
||||
Class<?> clazz = ClassUtils.forName(to);
|
||||
if (clazz == null) clazz = MainActivity.class;
|
||||
@ -92,8 +93,8 @@ public class EntranceUtils {
|
||||
public static void jumpActivity(Context context, Bundle nextToBundle, Bundle bundle, Callback callback) {
|
||||
bundle.putBoolean(KEY_REQUIRE_REDIRECT, true);
|
||||
|
||||
if (HaloApp.getInstance().isRunningForeground) {
|
||||
// 应用正在运行,前台或后台
|
||||
if (AppManager.getInstance().findActivity(MainActivity.class) != null) {
|
||||
// 应用正在运行,前台或后台,且MainActivity在栈中
|
||||
String to = bundle.getString(KEY_TO);
|
||||
Class<?> clazz = ClassUtils.forName(to);
|
||||
if (clazz == null) clazz = MainActivity.class;
|
||||
|
||||
@ -11,9 +11,12 @@ import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.common.constant.Config;
|
||||
@ -40,8 +43,10 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2017 Wasabeef
|
||||
@ -74,6 +79,8 @@ public class RichEditor extends WebView {
|
||||
|
||||
private EmptyCallback mInitialLayoutCallback;
|
||||
|
||||
private Map<String, DynamicJsInterface> mDynamicJsInterfaces = new HashMap<>();
|
||||
|
||||
private String mCurrentContent = "";
|
||||
|
||||
public enum Type {
|
||||
@ -122,6 +129,7 @@ public class RichEditor extends WebView {
|
||||
private OnDecorationStateListener mDecorationStateListener;
|
||||
private AfterInitialLoadListener mLoadListener;
|
||||
private WebChromeClientListener mChromeClientListener;
|
||||
private WebResourceRequestInterceptor mWebResourceRequestInterceptor;
|
||||
private PageFinishedListener mPageFinishedListener;
|
||||
|
||||
public RichEditor(Context context) {
|
||||
@ -179,6 +187,10 @@ public class RichEditor extends WebView {
|
||||
mChromeClientListener = chromeClientListener;
|
||||
}
|
||||
|
||||
public void setWebResourceRequestInterceptor(WebResourceRequestInterceptor interceptor) {
|
||||
mWebResourceRequestInterceptor = interceptor;
|
||||
}
|
||||
|
||||
public void setPageFinishedListener(PageFinishedListener pageFinishedListener) {
|
||||
mPageFinishedListener = pageFinishedListener;
|
||||
}
|
||||
@ -597,6 +609,14 @@ public class RichEditor extends WebView {
|
||||
exec("javascript:RE.formatBlock();");
|
||||
}
|
||||
|
||||
public void registerDynamicJsInterface(String method, DynamicJsInterface jsInterface) {
|
||||
mDynamicJsInterfaces.put(method, jsInterface);
|
||||
}
|
||||
|
||||
public void unregisterDynamicJsInterface(String method) {
|
||||
mDynamicJsInterfaces.remove(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 JS 方法,告诉网页端该 url 对应视频播放的进度
|
||||
*/
|
||||
@ -683,6 +703,16 @@ public class RichEditor extends WebView {
|
||||
|
||||
return super.shouldOverrideUrlLoading(view, url);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
||||
if (mWebResourceRequestInterceptor != null) {
|
||||
return mWebResourceRequestInterceptor.shouldInterceptRequest(view, url);
|
||||
}
|
||||
|
||||
return super.shouldInterceptRequest(view, url);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentOwner(boolean contentOwner) {
|
||||
@ -699,6 +729,10 @@ public class RichEditor extends WebView {
|
||||
boolean shouldOverrideUrlLoading(WebView view, String url);
|
||||
}
|
||||
|
||||
public interface WebResourceRequestInterceptor {
|
||||
WebResourceResponse shouldInterceptRequest(WebView view, String url);
|
||||
}
|
||||
|
||||
public interface PageFinishedListener {
|
||||
void onPageFinished();
|
||||
}
|
||||
@ -840,6 +874,14 @@ public class RichEditor extends WebView {
|
||||
public void logMtaEvent(String event) {
|
||||
// do nothing, mta is deprecated
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void invokeMethod(String method, String data) {
|
||||
DynamicJsInterface jsInterface = mDynamicJsInterfaces.get(method);
|
||||
if (jsInterface != null) {
|
||||
jsInterface.invoke(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -852,4 +894,8 @@ public class RichEditor extends WebView {
|
||||
mInitialLayoutCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
public interface DynamicJsInterface {
|
||||
void invoke(String data);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.gh.download.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -27,6 +28,7 @@ import com.gh.gamecenter.common.utils.throwExceptionInDebug
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.TimeElapsedHelper
|
||||
import com.gh.gamecenter.databinding.DialogDownloadBinding
|
||||
import com.gh.gamecenter.entity.GamePlatform
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
@ -50,8 +52,7 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
|
||||
private var mAdapter: DownloadDialogAdapter? = null
|
||||
private var mTraceEvent: ExposureEvent? = null
|
||||
private var mPlatformName: String = ""
|
||||
private var mPackageName: String = ""
|
||||
private var mPlatformList: List<GamePlatform>? = null
|
||||
private var mParentBundle: Bundle? = null
|
||||
|
||||
// 合集页面保持和后台一样的顺序
|
||||
@ -97,8 +98,11 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mParentBundle = requireActivity().intent.extras?.getBundle(ToolBarActivity.NORMAL_FRAGMENT_BUNDLE)
|
||||
mPlatformName = mParentBundle?.getString(EntranceConsts.KEY_PLATFORM, "") ?: ""
|
||||
mPackageName = mParentBundle?.getString(EntranceConsts.KEY_PACKAGENAME, "") ?: ""
|
||||
mPlatformList = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
mParentBundle?.getParcelableArrayList(EntranceConsts.KEY_PLATFORMS, GamePlatform::class.java)
|
||||
} else {
|
||||
mParentBundle?.getParcelableArrayList(EntranceConsts.KEY_PLATFORMS)
|
||||
}
|
||||
mGameEntity = requireArguments().getParcelable(GameEntity::class.java.simpleName)!!
|
||||
mEntrance = requireArguments().getString(EntranceConsts.KEY_ENTRANCE) ?: ""
|
||||
mLocation = requireArguments().getString(EntranceConsts.KEY_LOCATION) ?: ""
|
||||
@ -172,28 +176,37 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
|
||||
//自动下载
|
||||
private fun performAutoDownload(itemList: List<DownloadDialogItemData>, recyclerView: RecyclerView) {
|
||||
if (mPlatformName.isEmpty() && mPackageName.isEmpty()) return
|
||||
val platformList = this.mPlatformList
|
||||
if (platformList.isNullOrEmpty()) return
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
recyclerView.adapter?.let {
|
||||
for (i in 0 until it.itemCount) {
|
||||
val apkEntity = itemList[i].normal ?: continue
|
||||
val apkCollection = apkEntity.apkCollection
|
||||
if (apkCollection != null) {
|
||||
if (apkCollection.name == mPlatformName) {
|
||||
val platformName = platformList[0].name
|
||||
val packageName = platformList[0].packageName
|
||||
if (apkCollection != null) {// 插件集合首先切换到集合列表,再自动下载插件
|
||||
if (apkCollection.name == platformName) {// 第一个需要自动下载的插件名称与插件集合名称相同
|
||||
scrollAndDownload(recyclerView, false, i)
|
||||
break
|
||||
} else {
|
||||
apkCollection.saveApkEntity?.forEach { entity ->
|
||||
if (entity.getPlatformName() == mPlatformName || entity.packageName == mPackageName) {
|
||||
scrollAndDownload(recyclerView, false, i)
|
||||
}
|
||||
// 插件集合列表中存在需要自动下载的插件
|
||||
val matched = apkCollection.saveApkEntity?.any { entity ->
|
||||
entity.getPlatformName() == platformName || entity.packageName == packageName
|
||||
}
|
||||
|
||||
if (matched == true) {
|
||||
scrollAndDownload(recyclerView, false, i)
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (apkEntity.getPlatformName() == mPlatformName || apkEntity.packageName == mPackageName) {
|
||||
// 自动下载符合条件的插件
|
||||
val matchPlatformIndex = platformList.indexOfFirst { platform ->
|
||||
platform.name == apkEntity.getPlatformName() || platform.packageName == apkEntity.packageName
|
||||
}
|
||||
if (matchPlatformIndex != -1) {
|
||||
scrollAndDownload(recyclerView, true, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,9 @@ import com.gh.common.exposure.ExposureManager.log
|
||||
import com.gh.common.exposure.ExposureTraceUtils.appendTrace
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.toArrayList
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.entity.GamePlatform
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
|
||||
@ -195,6 +197,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
|
||||
openPlatformWindow,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
traceEvent
|
||||
)
|
||||
}
|
||||
@ -222,6 +225,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
|
||||
openPlatformWindow: Boolean = false,
|
||||
platformName: String? = null,
|
||||
packageName: String? = null,
|
||||
platforms: List<GamePlatform>? = null,
|
||||
traceEvent: ExposureEvent? = null
|
||||
) {
|
||||
val bundle = Bundle()
|
||||
@ -261,11 +265,13 @@ class GameDetailActivity : DownloadToolbarActivity() {
|
||||
}
|
||||
if (openPlatformWindow) {
|
||||
bundle.putBoolean(EntranceConsts.KEY_OPEN_PLATFORM_WINDOW, true)
|
||||
if (!platformName.isNullOrEmpty()) {
|
||||
bundle.putString(EntranceConsts.KEY_PLATFORM, platformName)
|
||||
}
|
||||
if (!packageName.isNullOrEmpty()) {
|
||||
bundle.putString(EntranceConsts.KEY_PACKAGENAME, packageName)
|
||||
if (!platforms.isNullOrEmpty()) {
|
||||
bundle.putParcelableArrayList(EntranceConsts.KEY_PLATFORMS, platforms.toArrayList())
|
||||
} else if (!platformName.isNullOrEmpty() || !packageName.isNullOrEmpty()) {
|
||||
bundle.putParcelableArrayList(
|
||||
EntranceConsts.KEY_PLATFORMS,
|
||||
arrayListOf(GamePlatform(platformName, packageName))
|
||||
)
|
||||
}
|
||||
}
|
||||
if (scrollToLibao) {
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
/**
|
||||
* Created by khy on 2017/4/24.
|
||||
@ -37,4 +39,12 @@ class VersionVoteLinkEntity(
|
||||
var platform: String = "",
|
||||
@SerializedName("package")
|
||||
var packageName: String = "",
|
||||
) : LinkEntity()
|
||||
var platforms: List<GamePlatform>? = null
|
||||
) : LinkEntity()
|
||||
|
||||
@Parcelize
|
||||
class GamePlatform(
|
||||
val name: String? = null,
|
||||
@SerializedName("package")
|
||||
val packageName: String? = null
|
||||
) : Parcelable
|
||||
@ -32,6 +32,7 @@ import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
|
||||
import com.gh.gamecenter.fragment.MainWrapperFragment
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleWebCacheManager
|
||||
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
|
||||
import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity
|
||||
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
|
||||
@ -60,6 +61,9 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
|
||||
ArticleWebCacheManager.init(requireContext().applicationContext)
|
||||
|
||||
mViewModel = viewModelProvider()
|
||||
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
@ -6,6 +6,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.prioritychain.AccelerateNotificationHandler
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DownloadItemUtils
|
||||
import com.gh.common.util.LogUtils
|
||||
@ -61,6 +62,7 @@ class HomeSearchToolWrapperFragment : HomeTabWrapperFragment() {
|
||||
private var mIsDisplayingLightContent = false
|
||||
|
||||
private var mViewModel: HomeSearchToolWrapperViewModel? = null
|
||||
private var mMainWrapperViewModel: MainWrapperViewModel? = null
|
||||
|
||||
private var mOffsetCritical = 0.7F
|
||||
|
||||
@ -94,6 +96,7 @@ class HomeSearchToolWrapperFragment : HomeTabWrapperFragment() {
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
mViewModel = viewModelProviderFromParent()
|
||||
mMainWrapperViewModel = viewModelProviderFromParent(MainWrapperViewModel.Factory(HaloApp.getInstance()))
|
||||
mElapsedHelper = TimeElapsedHelper()
|
||||
mSearchToolbarFragment =
|
||||
childFragmentManager.findFragmentById(R.id.wrapper_toolbar) as SearchToolbarFragment?
|
||||
@ -152,6 +155,25 @@ class HomeSearchToolWrapperFragment : HomeTabWrapperFragment() {
|
||||
setHomePush()
|
||||
}
|
||||
}
|
||||
|
||||
mMainWrapperViewModel?.accelerateNotificationPopup?.observeNonNull(viewLifecycleOwner) {
|
||||
if (parentFragment is MainWrapperFragment && isSupportVisible) {
|
||||
val isHandlerQueueEmpty = (parentFragment as MainWrapperFragment).isPriorityChainHandlerQueueEmpty()
|
||||
val accelerateSet =
|
||||
HashSet(SPUtils.getStringSet(Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET))
|
||||
if (isHandlerQueueEmpty && it.isNotEmpty() && !accelerateSet.contains(it[0].messageId)) {
|
||||
AccelerateNotificationHandler.showAccelerateNotificationPopupWindow(
|
||||
requireActivity(),
|
||||
mMainWrapperViewModel,
|
||||
mBaseHandler as BaseHandler,
|
||||
it[0],
|
||||
null
|
||||
)
|
||||
accelerateSet.add(it[0].messageId)
|
||||
SPUtils.setStringSet(Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET, accelerateSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSmartRefresh() {
|
||||
@ -707,6 +729,7 @@ class HomeSearchToolWrapperFragment : HomeTabWrapperFragment() {
|
||||
resumeHomePushVideo()
|
||||
DownloadManager.getInstance().addObserver(dataWatcher)
|
||||
updateHomePushDownloadBtn()
|
||||
mMainWrapperViewModel?.requestAccelerateNotificationPopup()
|
||||
}
|
||||
|
||||
override fun getInflatedLayout() =
|
||||
|
||||
@ -41,7 +41,9 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.FragmentMainBinding
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.entity.HomeDataEntity
|
||||
import com.gh.gamecenter.entity.SubjectData
|
||||
import com.gh.gamecenter.entity.SubjectRecommendEntity
|
||||
import com.gh.gamecenter.eventbus.EBSkip
|
||||
import com.gh.gamecenter.eventbus.EBUISwitch
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment
|
||||
@ -314,6 +316,8 @@ class MainWrapperFragment : BaseFragment_ViewPager_Checkable(), OnBackPressedLis
|
||||
mPriorityChain.start()
|
||||
}
|
||||
|
||||
fun isPriorityChainHandlerQueueEmpty() = mPriorityChain.isHandlerQueueEmpty()
|
||||
|
||||
private fun applyPkgConfig() {
|
||||
val pkgLinkEntity = PkgHelper.getPkgConfig()
|
||||
if (pkgLinkEntity != null) {
|
||||
|
||||
@ -12,15 +12,15 @@ import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.DialogEntity
|
||||
import com.gh.gamecenter.common.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.DialogEntity
|
||||
import com.gh.gamecenter.entity.SubjectRecommendEntity
|
||||
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
|
||||
import com.gh.gamecenter.floatingwindow.FloatingWindowEntity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
@ -140,7 +140,7 @@ class MainWrapperViewModel(application: Application, repository: MainWrapperRepo
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestAccelerateNotificationPopup() {
|
||||
fun requestAccelerateNotificationPopup() {
|
||||
if (CheckLoginUtils.isLogin()) {
|
||||
mApi.getAccelerateNotificationPopup(UserManager.getInstance().userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
@ -3,7 +3,10 @@ package com.gh.gamecenter.game.doublecard
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.display
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.StringUtils
|
||||
import com.gh.gamecenter.databinding.GameDoubleCardItemAlBinding
|
||||
import com.gh.gamecenter.databinding.GameDoubleCardItemBinding
|
||||
@ -11,6 +14,7 @@ import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.game.GameItemViewHolder
|
||||
|
||||
class DoubleCardViewHolder(val binding: GameDoubleCardItemAlBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
private val mPosterWidth = (DisplayUtils.getScreenWidth() - 40F.dip2px()) / 2
|
||||
|
||||
fun bindView(gameList: MutableList<GameEntity>, subjectName: String, positionInOriginSubject: Int) {
|
||||
bindSubView(
|
||||
@ -40,6 +44,7 @@ class DoubleCardViewHolder(val binding: GameDoubleCardItemAlBinding) : RecyclerV
|
||||
positionInOriginSubject: Int
|
||||
) {
|
||||
subBinding.run {
|
||||
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, mPosterWidth)
|
||||
poster.post { poster.display(gameEntity.columnImage) }
|
||||
gameName.text = gameEntity.name
|
||||
brief.text =
|
||||
|
||||
@ -37,6 +37,7 @@ import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.entity.SimpleGameEntity
|
||||
import com.gh.gamecenter.common.entity.SuggestType
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.divider.HorizontalDividerItemDecoration
|
||||
import com.gh.gamecenter.common.view.divider.VerticalDividerItemDecoration
|
||||
@ -46,7 +47,6 @@ import com.gh.gamecenter.databinding.*
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.game.horizontal.GameHorizontalAdapter
|
||||
import com.gh.gamecenter.game.horizontal.GameHorizontalListType
|
||||
import com.gh.gamecenter.game.vertical.SpanCountPagerSnapHelper
|
||||
@ -1048,6 +1048,9 @@ class DescAdapter(
|
||||
StringUtils.buildString(mEntrance, "游戏详情[", mGameName, "]:自定义栏目"),
|
||||
""
|
||||
)
|
||||
} else if (it.type == "qqqun" && it.link.isNullOrEmpty() && !it.text.isNullOrEmpty()) {
|
||||
// 若QQ群key填写为空,交互改为复制群号
|
||||
it.text?.copyTextAndToast()
|
||||
} else {
|
||||
PageSwitchDataHelper.pushCurrentPageData(
|
||||
hashMapOf(
|
||||
|
||||
@ -62,7 +62,7 @@ class GameDetailInfoItemAdapter(
|
||||
GameInfoItemData(
|
||||
title = gameInfo.contact!!.hint,
|
||||
info = gameInfo.contact!!.qq,
|
||||
actionStr = if (gameInfo.contact!!.type == "qq") "咨询" else "加入",
|
||||
actionStr = if (gameInfo.contact!!.type == "qq") "咨询" else if (gameInfo.contact?.key.isNullOrEmpty()) "复制" else "加入",
|
||||
key = gameInfo.contact!!.key
|
||||
)
|
||||
)
|
||||
@ -182,6 +182,9 @@ class GameDetailInfoItemAdapter(
|
||||
gameInfoItemData.info.copyTextAndToast("已复制")
|
||||
}
|
||||
}
|
||||
"复制" -> {
|
||||
gameInfoItemData.info.copyTextAndToast()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import android.widget.RelativeLayout
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.PagerSnapHelper
|
||||
@ -21,6 +20,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.databind.BindingAdapters
|
||||
import com.gh.common.prioritychain.AccelerateNotificationHandler
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
@ -40,6 +40,7 @@ import com.gh.gamecenter.entity.BadgeEntity
|
||||
import com.gh.gamecenter.feature.entity.Badge
|
||||
import com.gh.gamecenter.feature.eventbus.EBConcernChanged
|
||||
import com.gh.gamecenter.fragment.MainWrapperFragment
|
||||
import com.gh.gamecenter.fragment.MainWrapperViewModel
|
||||
import com.gh.gamecenter.gamecollection.mine.MyGameCollectionActivity
|
||||
import com.gh.gamecenter.history.HistoryActivity
|
||||
import com.gh.gamecenter.login.entity.UserInfoEntity
|
||||
@ -76,6 +77,7 @@ class HaloPersonalFragment : BaseLazyFragment() {
|
||||
private lateinit var mUnreadViewModel: MessageUnreadViewModel
|
||||
private lateinit var mUserHomeViewModel: UserHomeViewModel
|
||||
private lateinit var mHaloPersonalViewModel: HaloPersonalViewModel
|
||||
private lateinit var mMainWrapperViewModel: MainWrapperViewModel
|
||||
|
||||
private lateinit var mPersonalRecommendAdapter: HaloPersonalRecommendAdapter
|
||||
private lateinit var mPersonalBannerAdapter: HaloPersonalBannerAdapter
|
||||
@ -261,19 +263,16 @@ class HaloPersonalFragment : BaseLazyFragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mDatabase = AppDatabase.getInstance()
|
||||
val factory = UserViewModel.Factory(requireActivity().application)
|
||||
mUserViewModel = ViewModelProvider(this, factory).get(UserViewModel::class.java)
|
||||
mUserHomeViewModel = ViewModelProvider(
|
||||
this, UserHomeViewModel.Factory(
|
||||
mUserViewModel = viewModelProvider(UserViewModel.Factory(requireActivity().application))
|
||||
mUserHomeViewModel = viewModelProvider(
|
||||
UserHomeViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
UserManager.getInstance().userId
|
||||
)
|
||||
).get(UserHomeViewModel::class.java)
|
||||
mUnreadViewModel = ViewModelProvider(
|
||||
this,
|
||||
MessageUnreadViewModel.Factory(HaloApp.getInstance().application)
|
||||
).get(MessageUnreadViewModel::class.java)
|
||||
mHaloPersonalViewModel = ViewModelProvider(this).get(HaloPersonalViewModel::class.java)
|
||||
)
|
||||
mUnreadViewModel = viewModelProvider(MessageUnreadViewModel.Factory(HaloApp.getInstance().application))
|
||||
mHaloPersonalViewModel = viewModelProvider()
|
||||
mMainWrapperViewModel = viewModelProviderFromParent(MainWrapperViewModel.Factory(HaloApp.getInstance()))
|
||||
mUserHomeViewModel.getUserInfo()
|
||||
|
||||
observeNoneUIRelatedChanges()
|
||||
@ -292,6 +291,7 @@ class HaloPersonalFragment : BaseLazyFragment() {
|
||||
mUnreadViewModel.retry()
|
||||
mUserHomeViewModel.getBadgeList()
|
||||
mUserHomeViewModel.availableBadges()
|
||||
mMainWrapperViewModel.requestAccelerateNotificationPopup()
|
||||
}
|
||||
val currentItem = (parentFragment as MainWrapperFragment).currentItem
|
||||
if (currentItem == MainWrapperFragment.INDEX_PERSONAL) {
|
||||
@ -451,6 +451,28 @@ class HaloPersonalFragment : BaseLazyFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
mMainWrapperViewModel.accelerateNotificationPopup.observeNonNull(viewLifecycleOwner) {
|
||||
if (parentFragment is MainWrapperFragment && isSupportVisible) {
|
||||
val isHandlerQueueEmpty = (parentFragment as MainWrapperFragment).isPriorityChainHandlerQueueEmpty()
|
||||
val accelerateSet =
|
||||
HashSet(SPUtils.getStringSet(com.gh.gamecenter.common.constant.Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET))
|
||||
if (isHandlerQueueEmpty && it.isNotEmpty() && !accelerateSet.contains(it[0].messageId)) {
|
||||
AccelerateNotificationHandler.showAccelerateNotificationPopupWindow(
|
||||
requireActivity(),
|
||||
mMainWrapperViewModel,
|
||||
mBaseHandler as BaseHandler,
|
||||
it[0],
|
||||
null
|
||||
)
|
||||
accelerateSet.add(it[0].messageId)
|
||||
SPUtils.setStringSet(
|
||||
com.gh.gamecenter.common.constant.Constants.SP_ACCELERATE_NOTIFICATION_POP_UP_SET,
|
||||
accelerateSet
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 微信/签到
|
||||
RxView.clicks(mStubBinding.personalSign)
|
||||
.throttleFirst(1, TimeUnit.SECONDS)
|
||||
|
||||
@ -8,14 +8,12 @@ import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager.widget.ViewPager.LayoutParams
|
||||
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.UnAvaliableWebviewViewHolder
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.databinding.TabItemBinding
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.visibleIf
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
@ -53,6 +51,7 @@ class ArticleDetailAdapter(
|
||||
ITEM_ARTICLE_DETAIL -> {
|
||||
val isWebViewInstalled = PackageUtils.checkWebViewIsAvailable(mContext)
|
||||
if (isWebViewInstalled) {
|
||||
ArticleDetailContentViewHolder.wvLoadTimeInMills = System.currentTimeMillis()
|
||||
val binding: ItemArticleDetailContentBinding =
|
||||
ItemArticleDetailContentBinding.inflate(mLayoutInflater, parent, false)
|
||||
ArticleDetailContentViewHolder(binding, mViewModel).apply { articleDetailVH = this }
|
||||
|
||||
@ -5,6 +5,7 @@ import android.app.Activity
|
||||
import android.graphics.Bitmap
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.webkit.JavascriptInterface
|
||||
@ -41,6 +42,33 @@ class ArticleDetailContentViewHolder(
|
||||
var viewModel: ArticleDetailViewModel
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
companion object {
|
||||
var wvLoadTimeInMills = 0L
|
||||
}
|
||||
|
||||
val richEditor = ArticleWebCacheManager
|
||||
.attachToRichEditor(binding.richEditorContainer)
|
||||
.apply {
|
||||
setInputEnabled(false)
|
||||
setPadding(16, 4, 16, 4)
|
||||
enableForceDark(DarkModeUtils.isDarkModeOn(binding.root.context))
|
||||
setTransparentBackground()
|
||||
setLayoutCallback { viewModel.articleRenderedLiveData.postValue(true) }
|
||||
setPageFinishedListener {
|
||||
Log.d("ArticleDetail", "pageFinished->${System.currentTimeMillis() - wvLoadTimeInMills}")
|
||||
viewModel.articlePageFinishedLiveData.postValue(true)
|
||||
}
|
||||
setChromeClientListener(object : RichEditor.WebChromeClientListener {
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
Log.d("ArticleDetail", "onPageFinished: $url->${System.currentTimeMillis() - wvLoadTimeInMills}")
|
||||
}
|
||||
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", "帖子详情")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private var mEntrance = ""
|
||||
val articleImgUrlList = ArrayList<String>()
|
||||
|
||||
@ -58,11 +86,41 @@ class ArticleDetailContentViewHolder(
|
||||
titleTv.setTextColor(R.color.text_title.toColor(binding.root.context))
|
||||
gameName.setTextColor(R.color.text_subtitleDesc.toColor(binding.root.context))
|
||||
|
||||
richEditor.enableForceDark(DarkModeUtils.isDarkModeOn(binding.root.context))
|
||||
richEditor.setTransparentBackground()
|
||||
richEditor.setInputEnabled(false)
|
||||
richEditor.setPadding(16, 4, 16, 4)
|
||||
richEditor.addJavascriptInterface(JsInterface(article.status ?: ""), "imagelistener")
|
||||
richEditor.registerDynamicJsInterface("imageArr") { url ->
|
||||
val defUrl = url.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
|
||||
if (!articleImgUrlList.contains(defUrl) && !url.contains("web_load_dfimg_icon.png")) {
|
||||
articleImgUrlList.add(defUrl)
|
||||
}
|
||||
}
|
||||
richEditor.registerDynamicJsInterface("imageClick") { url ->
|
||||
when {
|
||||
url.contains("web_load_dfimg_icon.png") -> {
|
||||
runOnUiThread { richEditor.replaceAllDfImageExcludeGif() }
|
||||
}
|
||||
else -> {
|
||||
val status = article.status ?: ""
|
||||
clickToastByStatus(status) {
|
||||
var current = 0
|
||||
var i = 0
|
||||
val size = articleImgUrlList.size
|
||||
while (i < size) {
|
||||
if (url.contains(articleImgUrlList.get(i))) {
|
||||
current = i
|
||||
}
|
||||
i++
|
||||
}
|
||||
val intent = ImageViewerActivity.getIntent(
|
||||
binding.root.context, articleImgUrlList, current,
|
||||
mEntrance + "+(帖子详情[" + binding.titleTv.text.toString() + "])"
|
||||
)
|
||||
(binding.root.context as Activity).startActivityForResult(
|
||||
intent,
|
||||
ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
richEditor.addJavascriptInterface(
|
||||
OnLinkClickListener(
|
||||
root.context,
|
||||
@ -72,23 +130,7 @@ class ArticleDetailContentViewHolder(
|
||||
"帖子详情"
|
||||
), "OnLinkClickListener"
|
||||
)
|
||||
richEditor.setLayoutCallback(object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
viewModel.articleRenderedLiveData.postValue(true)
|
||||
}
|
||||
})
|
||||
richEditor.setPageFinishedListener {
|
||||
viewModel.articlePageFinishedLiveData.postValue(true)
|
||||
}
|
||||
richEditor.setChromeClientListener(object : RichEditor.WebChromeClientListener {
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
|
||||
}
|
||||
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", "帖子详情")
|
||||
}
|
||||
})
|
||||
approvalStatusTv.goneIf(article.status == "pass")
|
||||
statusContainer.goneIf(article.status == "pass")
|
||||
when (article.status) {
|
||||
@ -320,7 +362,7 @@ class ArticleDetailContentViewHolder(
|
||||
* 回调列表视频播放结束时的时间
|
||||
*/
|
||||
fun onVideoPlayedCallback(url: String, position: Int) {
|
||||
binding.richEditor.onVideoPlayedCallback(url, position)
|
||||
richEditor.onVideoPlayedCallback(url, position)
|
||||
}
|
||||
|
||||
fun updateFollowBtn(isFollowed: Boolean) {
|
||||
@ -344,7 +386,7 @@ class ArticleDetailContentViewHolder(
|
||||
fun imageClick(url: String) {
|
||||
when {
|
||||
url.contains("web_load_dfimg_icon.png") -> {
|
||||
runOnUiThread { binding.richEditor.replaceAllDfImageExcludeGif() }
|
||||
runOnUiThread { richEditor.replaceAllDfImageExcludeGif() }
|
||||
}
|
||||
// url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> {
|
||||
// runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
|
||||
@ -381,4 +423,14 @@ class ArticleDetailContentViewHolder(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
richEditor.setLayoutCallback(null)
|
||||
richEditor.removeJavascriptInterface("imagelistener")
|
||||
richEditor.removeJavascriptInterface("OnLinkClickListener")
|
||||
richEditor.setChromeClientListener(null)
|
||||
richEditor.setContentOwner(false)
|
||||
richEditor.setPageFinishedListener(null)
|
||||
ArticleWebCacheManager.detachFromRichEditor(binding.richEditorContainer)
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,6 @@ import com.gh.gamecenter.common.baselist.LoadType
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.entity.AdditionalParamsEntity
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.NormalShareEntity
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
@ -41,6 +40,7 @@ import com.gh.gamecenter.eventbus.EBDeleteCommentDetail
|
||||
import com.gh.gamecenter.eventbus.EBDeleteDetail
|
||||
import com.gh.gamecenter.eventbus.EBTopCommunityChanged
|
||||
import com.gh.gamecenter.feature.entity.ArticleDraftEntity
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.qa.article.edit.ArticleEditActivity
|
||||
@ -119,11 +119,11 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
|
||||
mAdapter?.articleDetailVH?.run {
|
||||
if (articleImgUrlList.size > 0) {
|
||||
if (imageSet.size == articleImgUrlList.size) {
|
||||
binding.richEditor.replaceAllDfImage()
|
||||
richEditor.replaceAllDfImage()
|
||||
} else {
|
||||
for (i in imageSet) {
|
||||
val url = articleImgUrlList[i.toInt()]
|
||||
binding.richEditor.replaceDfImageByUrl(url)
|
||||
richEditor.replaceDfImageByUrl(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,6 +165,9 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
mAdapter?.articleDetailVH?.destroy()
|
||||
|
||||
if (mViewModel.detailEntity != null) {
|
||||
HistoryHelper.insertArticleEntity(mViewModel.detailEntity!!)
|
||||
|
||||
|
||||
@ -0,0 +1,146 @@
|
||||
package com.gh.gamecenter.qa.article.detail
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.MutableContextWrapper
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import com.gh.common.view.RichEditor
|
||||
import com.gh.gamecenter.common.utils.EnvHelper
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
import retrofit2.http.Streaming
|
||||
import retrofit2.http.Url
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* 社区文章详情-Web资源缓存管理类
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object ArticleWebCacheManager {
|
||||
|
||||
private lateinit var cacheDir: File
|
||||
|
||||
private lateinit var cacheRichEditor: RichEditor
|
||||
|
||||
private var isInit = false
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun init(applicationContext: Context) {
|
||||
if (isInit) return
|
||||
|
||||
isInit = true
|
||||
|
||||
this.cacheRichEditor = RichEditor(
|
||||
MutableContextWrapper(applicationContext)
|
||||
)
|
||||
|
||||
this.cacheDir = File(applicationContext.cacheDir, "article/web").apply {
|
||||
if (!exists()) mkdirs()
|
||||
}
|
||||
|
||||
val cacheUrlList = mutableListOf(
|
||||
"https://static-web.ghzs.com/website-static/lib/polyfill.min.js",
|
||||
"https://and-static.ghzs.com/web/dplayer/DPlayer.min.js"
|
||||
)
|
||||
|
||||
if (EnvHelper.isDevEnv) {
|
||||
cacheUrlList.add("https://resource.ghzs.com/js/halo_app_test.js")
|
||||
cacheUrlList.add("https://resource.ghzs.com/css/halo_app_test.css")
|
||||
} else {
|
||||
cacheUrlList.add("https://resource.ghzs.com/js/halo.js")
|
||||
cacheUrlList.add("https://resource.ghzs.com/css/halo.css")
|
||||
}
|
||||
|
||||
val okHttpClient = OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val retrofit = Retrofit.Builder()
|
||||
.client(okHttpClient)
|
||||
.baseUrl("https://resource.ghzs.com")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
.build()
|
||||
|
||||
val apiService = retrofit.create(ApiService::class.java)
|
||||
|
||||
val requestSingleList = cacheUrlList.map { url ->
|
||||
apiService.downloadFile(url, System.currentTimeMillis() / 1000)
|
||||
.map {
|
||||
val file = File(cacheDir, MD5Utils.getUrlMD5(url)).apply {
|
||||
if (!exists()) createNewFile()
|
||||
}
|
||||
val inputStream = it.byteStream()
|
||||
val outputStream = FileOutputStream(file)
|
||||
inputStream.copyTo(outputStream, DEFAULT_BUFFER_SIZE)
|
||||
file
|
||||
}
|
||||
}
|
||||
|
||||
Single.zip(requestSingleList) {}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
}
|
||||
|
||||
fun attachToRichEditor(parent: ViewGroup): RichEditor {
|
||||
val richEditor = this.cacheRichEditor.apply {
|
||||
(this.context as MutableContextWrapper).baseContext = parent.context
|
||||
setWebResourceRequestInterceptor { view, url -> shouldInterceptRequest(view, url) }
|
||||
}
|
||||
parent.addView(
|
||||
richEditor,
|
||||
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
)
|
||||
return cacheRichEditor
|
||||
}
|
||||
|
||||
fun detachFromRichEditor(parent: ViewGroup) {
|
||||
this.cacheRichEditor.setHtml("", false)
|
||||
this.cacheRichEditor.setWebResourceRequestInterceptor(null)
|
||||
(this.cacheRichEditor.context as MutableContextWrapper).baseContext = parent.context.applicationContext
|
||||
parent.removeView(this.cacheRichEditor)
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截WebView的资源请求,并返回URL对应的缓存数据
|
||||
*/
|
||||
fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {
|
||||
val urlWithoutQueryParams = url.split("?")[0]
|
||||
|
||||
val cacheFile = File(cacheDir, MD5Utils.getUrlMD5(urlWithoutQueryParams))
|
||||
if (!cacheFile.exists()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val mimeType = if (urlWithoutQueryParams.endsWith(".js")) {
|
||||
"text/javascript"
|
||||
} else if (urlWithoutQueryParams.endsWith(".css")) {
|
||||
"text/css"
|
||||
} else null
|
||||
|
||||
return WebResourceResponse(mimeType, "utf-8", cacheFile.inputStream())
|
||||
}
|
||||
|
||||
interface ApiService {
|
||||
@GET
|
||||
@Streaming
|
||||
fun downloadFile(@Url url: String, @Query("timestamp") timestamp: Long): Single<ResponseBody>
|
||||
}
|
||||
}
|
||||
@ -108,11 +108,11 @@ class NewQuestionDetailFragment :
|
||||
mAdapter?.questionDetailVH?.run {
|
||||
if (questionImgUrlList.size > 0) {
|
||||
if (imageSet.size == questionImgUrlList.size) {
|
||||
binding.richEditor.replaceAllDfImage()
|
||||
richEditor.replaceAllDfImage()
|
||||
} else {
|
||||
for (i in imageSet) {
|
||||
val url = questionImgUrlList[i.toInt()]
|
||||
binding.richEditor.replaceDfImageByUrl(url)
|
||||
richEditor.replaceDfImageByUrl(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -742,6 +742,11 @@ class NewQuestionDetailFragment :
|
||||
mBinding.root.setBackgroundColor(Color.TRANSPARENT)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
mAdapter?.questionDetailVH?.destroy()
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
mAdapter?.let { it.notifyItemRangeChanged(0, it.itemCount) }
|
||||
|
||||
@ -26,6 +26,7 @@ import com.gh.gamecenter.core.runOnUiThread
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemArticleDetailContentBinding
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleWebCacheManager
|
||||
import com.gh.gamecenter.qa.article.detail.EditHistoryDialog
|
||||
import com.gh.gamecenter.qa.editor.OnLinkClickListener
|
||||
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
|
||||
@ -36,40 +37,39 @@ class QuestionDetailContentViewHolder(
|
||||
var viewModel: NewQuestionDetailViewModel
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
val richEditor = ArticleWebCacheManager
|
||||
.attachToRichEditor(binding.richEditorContainer)
|
||||
.apply {
|
||||
setInputEnabled(false)
|
||||
setPadding(16, 4, 16, 4)
|
||||
enableForceDark(DarkModeUtils.isDarkModeOn(binding.root.context))
|
||||
setTransparentBackground()
|
||||
setLayoutCallback { viewModel.questionRenderedLiveData.postValue(true) }
|
||||
setPageFinishedListener { viewModel.questionPageFinishedLiveData.postValue(true) }
|
||||
setChromeClientListener(object : RichEditor.WebChromeClientListener {
|
||||
override fun onPageFinished(view: WebView?, url: String?) {}
|
||||
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", "问题详情")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private var mEntrance = ""
|
||||
val questionImgUrlList = ArrayList<String>()
|
||||
|
||||
@SuppressLint("AddJavascriptInterface")
|
||||
fun bindView(question: QuestionsDetailEntity) {
|
||||
binding.run {
|
||||
richEditor.setInputEnabled(false)
|
||||
richEditor.enableForceDark(DarkModeUtils.isDarkModeOn(binding.root.context))
|
||||
richEditor.setTransparentBackground()
|
||||
richEditor.setPadding(16, 4, 16, 4)
|
||||
richEditor.removeJavascriptInterface("imagelistener")
|
||||
richEditor.addJavascriptInterface(JsInterface(question.status), "imagelistener")
|
||||
richEditor.removeJavascriptInterface("OnLinkClickListener")
|
||||
richEditor.addJavascriptInterface(
|
||||
OnLinkClickListener(
|
||||
root.context, question.title
|
||||
?: "", question.status, mEntrance, "问题详情"
|
||||
), "OnLinkClickListener"
|
||||
)
|
||||
richEditor.setLayoutCallback(object : EmptyCallback {
|
||||
override fun onCallback() {
|
||||
viewModel.questionRenderedLiveData.postValue(true)
|
||||
}
|
||||
})
|
||||
richEditor.setPageFinishedListener {
|
||||
viewModel.questionPageFinishedLiveData.postValue(true)
|
||||
}
|
||||
richEditor.setChromeClientListener(object : RichEditor.WebChromeClientListener {
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
|
||||
}
|
||||
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
return DefaultUrlHandler.interceptUrl(binding.root.context, url ?: "", "问题详情")
|
||||
}
|
||||
})
|
||||
approvalStatusTv.goneIf(question.status == "pass")
|
||||
statusContainer.goneIf(question.status == "pass")
|
||||
when (question.status) {
|
||||
@ -275,7 +275,7 @@ class QuestionDetailContentViewHolder(
|
||||
* 回调列表视频播放结束时的时间
|
||||
*/
|
||||
fun onVideoPlayedCallback(url: String, position: Int) {
|
||||
binding.richEditor.onVideoPlayedCallback(url, position)
|
||||
richEditor.onVideoPlayedCallback(url, position)
|
||||
}
|
||||
|
||||
inner class JsInterface(val status: String) {
|
||||
@ -283,7 +283,7 @@ class QuestionDetailContentViewHolder(
|
||||
fun imageClick(url: String) {
|
||||
when {
|
||||
url.contains("web_load_dfimg_icon.png") -> {
|
||||
runOnUiThread { binding.richEditor.replaceAllDfImageExcludeGif() }
|
||||
runOnUiThread { richEditor.replaceAllDfImageExcludeGif() }
|
||||
}
|
||||
// url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL) -> {
|
||||
// runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) }
|
||||
@ -320,4 +320,14 @@ class QuestionDetailContentViewHolder(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
richEditor.setLayoutCallback(null)
|
||||
richEditor.removeJavascriptInterface("imagelistener")
|
||||
richEditor.removeJavascriptInterface("OnLinkClickListener")
|
||||
richEditor.setChromeClientListener(null)
|
||||
richEditor.setContentOwner(false)
|
||||
richEditor.setPageFinishedListener(null)
|
||||
ArticleWebCacheManager.detachFromRichEditor(binding.richEditorContainer)
|
||||
}
|
||||
}
|
||||
@ -193,6 +193,7 @@ class VoteAdapter(
|
||||
openPlatformWindow = true,
|
||||
link.platform,
|
||||
link.packageName,
|
||||
link.platforms,
|
||||
traceEvent = mExposureEventSparseArray[position]
|
||||
)
|
||||
}
|
||||
|
||||
@ -13,11 +13,11 @@ import android.view.Window
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.TextView
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils.directToLinkPage
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
@ -30,8 +30,8 @@ import com.gh.gamecenter.core.utils.MtaHelper.onEvent
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.DialogAddVoteBinding
|
||||
import com.gh.gamecenter.databinding.FragmentVoteBinding
|
||||
import com.gh.gamecenter.feature.entity.InstallGameEntity
|
||||
import com.gh.gamecenter.entity.VersionVoteEntity
|
||||
import com.gh.gamecenter.feature.entity.InstallGameEntity
|
||||
import com.gh.gamecenter.game.upload.GameUploadFragment
|
||||
import com.gh.gamecenter.game.upload.UploadScheduleDialog
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
@ -135,6 +135,9 @@ class VoteFragment : ListFragment<VersionVoteEntity, VoteViewModel>() {
|
||||
etSearch.addTextChangedListener { s ->
|
||||
tvBack.visibility = if (s.isNullOrEmpty()) View.GONE else View.VISIBLE
|
||||
}
|
||||
etSearch.doAfterTextChanged { editable ->
|
||||
mListViewModel.autoSearchVersion(editable.toString().trim { it <= ' ' })
|
||||
}
|
||||
tvSearch.setOnClickListener {
|
||||
if (etSearch.text.isNullOrEmpty()) {
|
||||
toast("请输入搜索关键词")
|
||||
@ -145,7 +148,6 @@ class VoteFragment : ListFragment<VersionVoteEntity, VoteViewModel>() {
|
||||
}
|
||||
tvBack.setOnClickListener {
|
||||
etSearch.text.clear()
|
||||
mListViewModel.searchVersion("")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -317,9 +319,13 @@ class VoteFragment : ListFragment<VersionVoteEntity, VoteViewModel>() {
|
||||
mListViewModel.postVersionVote(name, isNewVote, entity.me?.isVersionRequested ?: false, { response ->
|
||||
try {
|
||||
waitDialog.dismiss()
|
||||
val jsonObject = JSONObject(response.string())
|
||||
val wechatBindStatus = jsonObject.optBoolean("wechat_bind")
|
||||
|
||||
if (isNewVote) {
|
||||
val id = JSONObject(response.string()).getString("_id")
|
||||
toast(R.string.vote_success)
|
||||
showVoteSuccessDialog(wechatBindStatus)
|
||||
|
||||
val id = jsonObject.getString("_id")
|
||||
if (!TextUtils.isEmpty(id)) {
|
||||
mAdapter.updateVote(isNewVote, id, name, true)
|
||||
val lastView = mLayoutManager.findViewByPosition(mAdapter.itemCount - 1)
|
||||
@ -329,20 +335,7 @@ class VoteFragment : ListFragment<VersionVoteEntity, VoteViewModel>() {
|
||||
}
|
||||
} else {
|
||||
if (entity.me?.isVersionRequested != true) {
|
||||
val wechatBindStatus = JSONObject(response.string()).optBoolean("wechat_bind")
|
||||
if (wechatBindStatus) {
|
||||
NewFlatLogUtils.logGameDetailClickForVersionVote(mGameId, mGameName, "我知道了")
|
||||
DialogUtils.showReserveOrVoteSuccessDialog(requireContext(), false)
|
||||
} else {
|
||||
DialogUtils.showReserveOrVoteSuccess2WechatBindDialog(requireContext(), false, {
|
||||
NewFlatLogUtils.logGameDetailClickForVersionVote(mGameId, mGameName, "开启微信提醒")
|
||||
requireContext().startActivity(WebActivity.getBindWechatIntent(requireContext()))
|
||||
}, object : CancelListener {
|
||||
override fun onCancel() {
|
||||
NewFlatLogUtils.logGameDetailClickForVersionVote(mGameId, mGameName, "关闭")
|
||||
}
|
||||
})
|
||||
}
|
||||
showVoteSuccessDialog(wechatBindStatus)
|
||||
}
|
||||
mAdapter.updateVote(isNewVote, name, null, !(entity.me?.isVersionRequested ?: false))
|
||||
}
|
||||
@ -381,6 +374,22 @@ class VoteFragment : ListFragment<VersionVoteEntity, VoteViewModel>() {
|
||||
})
|
||||
}
|
||||
|
||||
private fun showVoteSuccessDialog(wechatBindStatus: Boolean) {
|
||||
if (wechatBindStatus) {
|
||||
NewFlatLogUtils.logGameDetailClickForVersionVote(mGameId, mGameName, "我知道了")
|
||||
DialogUtils.showReserveOrVoteSuccessDialog(requireContext(), false)
|
||||
} else {
|
||||
DialogUtils.showReserveOrVoteSuccess2WechatBindDialog(requireContext(), false, {
|
||||
NewFlatLogUtils.logGameDetailClickForVersionVote(mGameId, mGameName, "开启微信提醒")
|
||||
requireContext().startActivity(WebActivity.getBindWechatIntent(requireContext()))
|
||||
}, object : CancelListener {
|
||||
override fun onCancel() {
|
||||
NewFlatLogUtils.logGameDetailClickForVersionVote(mGameId, mGameName, "关闭")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
return if (mListViewModel.keyword.isNotEmpty()) {
|
||||
mBinding.searchBarInclude.tvBack.performClick()
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.gh.gamecenter.vote
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.SearchType
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.common.baselist.LoadType
|
||||
import com.gh.gamecenter.common.retrofit.ApiResponse
|
||||
@ -15,13 +17,16 @@ import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class VoteViewModel(application: Application, private val mGameId: String = "") :
|
||||
ListViewModel<VersionVoteEntity, VersionVoteEntity>(application) {
|
||||
@ -29,6 +34,20 @@ class VoteViewModel(application: Application, private val mGameId: String = "")
|
||||
var keyword = ""
|
||||
val uploadSuccess = MutableLiveData<Boolean>()
|
||||
|
||||
val disposable = CompositeDisposable()
|
||||
|
||||
private val searchKeySubject = PublishSubject.create<String>()
|
||||
.also {
|
||||
val disposable = it.debounce(300, TimeUnit.MILLISECONDS)
|
||||
.distinctUntilChanged()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { keyword ->
|
||||
searchVersion(keyword)
|
||||
}
|
||||
this.disposable.add(disposable)
|
||||
}
|
||||
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource(mListLiveData) { list ->
|
||||
mResultLiveData.postValue(list)
|
||||
@ -37,6 +56,7 @@ class VoteViewModel(application: Application, private val mGameId: String = "")
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<VersionVoteEntity>> =
|
||||
RetrofitManager.getInstance().api.getVersionVote(mGameId, page, keyword)
|
||||
.doOnSubscribe { disposable.add(it) }
|
||||
|
||||
fun postApkInfo(url: String, installGameEntity: InstallGameEntity) {
|
||||
val requestMap = HashMap<String, Any>()
|
||||
@ -52,6 +72,7 @@ class VoteViewModel(application: Application, private val mGameId: String = "")
|
||||
GsonUtils.toJson(requestMap)
|
||||
)
|
||||
RetrofitManager.getInstance().api.postPlatformRequestApk(installGameEntity.platformRequestsId, body)
|
||||
.doOnSubscribe { disposable.add(it) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
@ -89,6 +110,7 @@ class VoteViewModel(application: Application, private val mGameId: String = "")
|
||||
RetrofitManager.getInstance().api.postVersionVote(name) // name is id
|
||||
}
|
||||
responseBodyObservable
|
||||
.doOnSubscribe { disposable.add(it) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
@ -110,11 +132,19 @@ class VoteViewModel(application: Application, private val mGameId: String = "")
|
||||
})
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
fun searchVersion(keyword: String) {
|
||||
this.keyword = keyword
|
||||
load(LoadType.REFRESH)
|
||||
}
|
||||
|
||||
fun autoSearchVersion(keyword: String) {
|
||||
searchKeySubject.onNext(keyword)
|
||||
}
|
||||
|
||||
class Factory(private val gameId: String) : ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return VoteViewModel(HaloApp.getInstance().application, gameId) as T
|
||||
|
||||
@ -2,12 +2,11 @@ package com.gh.ndownload
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.gh.common.util.PackageInstaller
|
||||
import com.gh.download.DownloadDataHelper
|
||||
import com.gh.download.DownloadDataSimpleHelper
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.common.utils.NetworkUtils
|
||||
import com.gh.gamecenter.common.utils.addMetaExtra
|
||||
import com.gh.gamecenter.common.utils.deepClone
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.halo.assistant.HaloApp
|
||||
@ -20,6 +19,7 @@ import com.lightgame.download.FileUtils
|
||||
import com.lightgame.utils.Utils
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
import java.net.URLConnection
|
||||
@ -34,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
object NDownloadBridge : InnerDownloadListener, IErrorRetryHandler {
|
||||
|
||||
private const val TAG = "NDownloadBridge"
|
||||
private const val REAL_FORMAT = "real_format" // 最终的文件格式
|
||||
private const val DEFAULT_DOWNLOAD_THREAD_SIZE = 2
|
||||
private const val NO_NETWORK_MAX_RETRY_COUNT = 5
|
||||
|
||||
@ -218,6 +219,21 @@ object NDownloadBridge : InnerDownloadListener, IErrorRetryHandler {
|
||||
downloadEntity.status = com.lightgame.download.DownloadStatus.done
|
||||
downloadEntity.addMetaExtra(com.lightgame.download.DownloadConfig.KEY_DOWNLOAD_ELAPSED_TIME, elapsedTime.toString())
|
||||
|
||||
val originalFormat = downloadEntity.format
|
||||
val realFormat = downloadEntity.getMetaExtra(REAL_FORMAT)
|
||||
// 若最终的格式有异常,那么根据最后获得的格式进行修改、重命名下载文件
|
||||
if (realFormat.isNotEmpty() && originalFormat != realFormat) {
|
||||
Utils.log(TAG, "更新最终的文件格式,更新前的格式为 $originalFormat 更新后的格式为 $realFormat")
|
||||
|
||||
val renamedId = PackageInstaller.createDownloadId(downloadEntity.name)
|
||||
val renamedPath = PackageInstaller.getDownloadPathWithId(
|
||||
renamedId, downloadEntity.getMetaExtra(REAL_FORMAT)
|
||||
)
|
||||
File(downloadEntity.path).renameTo(File(renamedPath))
|
||||
downloadEntity.path = renamedPath
|
||||
downloadEntity.format = realFormat
|
||||
}
|
||||
|
||||
DownloadManager.getInstance().onTaskDone(downloadEntity)
|
||||
NDownloadService.getService()?.removeFromDataChangerAndResumeWaitingTask(downloadEntity, true)
|
||||
|
||||
@ -243,6 +259,15 @@ object NDownloadBridge : InnerDownloadListener, IErrorRetryHandler {
|
||||
DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
|
||||
}
|
||||
|
||||
// 记录重定向时获取到的最终格式,因为缓存问题,原格式与实际下载的格式有区别
|
||||
val realFormat = connection?.getHeaderField("Halo-Format")
|
||||
if (!realFormat.isNullOrEmpty() && downloadEntity.format != realFormat) {
|
||||
Utils.log(TAG, "获取到新的文件格式, $realFormat")
|
||||
|
||||
downloadEntity.addMetaExtra(REAL_FORMAT, realFormat)
|
||||
DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
|
||||
}
|
||||
|
||||
NDataChanger.notifyDataChanged(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import android.view.View
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.*
|
||||
import com.gh.ad.AdDelegateHelper
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.ExposureUtils
|
||||
import com.gh.common.history.HistoryHelper
|
||||
@ -1084,6 +1085,7 @@ object VHelper {
|
||||
logLaunch(gameId, gameName, downloadEntity?.getGameCategory() ?: "", packageName)
|
||||
|
||||
if (showLoading) {
|
||||
val thirdPartyAd = AdDelegateHelper.vGameLaunchAd?.thirdPartyAd
|
||||
val intent = mDelegateManager.getStartGameIntent(
|
||||
packageName,
|
||||
gameId,
|
||||
@ -1092,7 +1094,9 @@ object VHelper {
|
||||
MetaUtil.getBase64EncodedAndroidId(),
|
||||
HaloApp.getInstance().gid,
|
||||
com.gh.gamecenter.BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel
|
||||
HaloApp.getInstance().channel,
|
||||
thirdPartyAd?.slotId,
|
||||
thirdPartyAd?.displaySize
|
||||
)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(intent)
|
||||
|
||||
@ -198,7 +198,8 @@ class ShortcutManager private constructor() {
|
||||
MetaUtil.getBase64EncodedAndroidId(),
|
||||
HaloApp.getInstance().gid,
|
||||
com.gh.gamecenter.BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel
|
||||
HaloApp.getInstance().channel,
|
||||
"", ""
|
||||
)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
return intent
|
||||
|
||||
@ -217,8 +217,8 @@
|
||||
android:textStyle="bold"
|
||||
tools:text="这是一个很长很长很长很长很长很长很长很长很长很长的标题" />
|
||||
|
||||
<com.gh.common.view.RichEditor
|
||||
android:id="@+id/richEditor"
|
||||
<FrameLayout
|
||||
android:id="@+id/richEditorContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="13dp" />
|
||||
|
||||
@ -7,8 +7,8 @@ ext {
|
||||
targetSdkVersion = 28
|
||||
|
||||
// application info (每个大版本之间的 versionCode 增加 20)
|
||||
versionCode = 971
|
||||
versionName = "5.31.1"
|
||||
versionCode = 990
|
||||
versionName = "5.32.0"
|
||||
applicationId = "com.gh.gamecenter"
|
||||
|
||||
// AndroidX
|
||||
|
||||
@ -110,6 +110,8 @@ public class EntranceConsts {
|
||||
public static final String KEY_USER_AVATAR = "user_avatar";
|
||||
public static final String KEY_PLATFORM = "platform";
|
||||
public static final String KEY_GAME_NAME = "game_name";
|
||||
|
||||
public static final String KEY_PLATFORMS = "platforms";
|
||||
public static final String KEY_GAME_INFO = "game_info";
|
||||
|
||||
public static final String KEY_GAME_TYPE = "game_type";
|
||||
|
||||
Submodule vspace-bridge updated: cdcfbd091f...c757c46e65
Reference in New Issue
Block a user